1
// MIT License
2
//
3
// Copyright (c) 2021 sadnessOjisan
4
//
5
// Permission is hereby granted, free of charge, to any person obtaining a copy
6
// of this software and associated documentation files (the "Software"), to deal
7
// in the Software without restriction, including without limitation the rights
8
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the Software is
10
// furnished to do so, subject to the following conditions:
11
//
12
// The above copyright notice and this permission notice shall be included in
13
// all copies or substantial portions of the Software.
14
//
15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
// SOFTWARE.
22

            
23
use chrono::*;
24

            
25
#[allow(dead_code)]
26
/// Generate a calendar view of the given date's month.
27
///
28
/// Each vector element is an array of seven numbers representing weeks
29
/// (starting on Sundays), and each value is the numeric date.
30
/// A value of zero means a date that not exists in the current month.
31
///
32
/// # Examples
33
/// ```
34
/// use chrono::*;
35
/// use mailpot_archives::cal::calendarize;
36
///
37
/// let date = NaiveDate::parse_from_str("2021-01-02", "%Y-%m-%d").unwrap();
38
/// // Week = [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
39
/// println!("{:?}", calendarize(date));
40
/// // [0, 0, 0, 0, 0, 1, 2],
41
/// // [3, 4, 5, 6, 7, 8, 9],
42
/// // [10, 11, 12, 13, 14, 15, 16],
43
/// // [17, 18, 19, 20, 21, 22, 23],
44
/// // [24, 25, 26, 27, 28, 29, 30],
45
/// // [31, 0, 0, 0, 0, 0, 0]
46
/// ```
47
5
pub fn calendarize(date: NaiveDate) -> Vec<[u32; 7]> {
48
5
    calendarize_with_offset(date, 0)
49
5
}
50

            
51
/// Generate a calendar view of the given date's month and offset.
52
///
53
/// Each vector element is an array of seven numbers representing weeks
54
/// (starting on Sundays), and each value is the numeric date.
55
/// A value of zero means a date that not exists in the current month.
56
///
57
/// Offset means the number of days from sunday.
58
/// For example, 1 means monday, 6 means saturday.
59
///
60
/// # Examples
61
/// ```
62
/// use chrono::*;
63
/// use mailpot_archives::cal::calendarize_with_offset;
64
///
65
/// let date = NaiveDate::parse_from_str("2021-01-02", "%Y-%m-%d").unwrap();
66
/// // Week = [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
67
/// println!("{:?}", calendarize_with_offset(date, 1));
68
/// // [0, 0, 0, 0, 1, 2, 3],
69
/// // [4, 5, 6, 7, 8, 9, 10],
70
/// // [11, 12, 13, 14, 15, 16, 17],
71
/// // [18, 19, 20, 21, 22, 23, 24],
72
/// // [25, 26, 27, 28, 29, 30, 0],
73
/// ```
74
10
pub fn calendarize_with_offset(date: NaiveDate, offset: u32) -> Vec<[u32; 7]> {
75
10
    let mut monthly_calendar: Vec<[u32; 7]> = Vec::with_capacity(6);
76
10
    let year = date.year();
77
10
    let month = date.month();
78
10
    let num_days_from_sunday = NaiveDate::from_ymd_opt(year, month, 1)
79
        .unwrap()
80
        .weekday()
81
        .num_days_from_sunday();
82
    let mut first_date_day;
83
10
    if num_days_from_sunday < offset {
84
2
        first_date_day = num_days_from_sunday + (7 - offset);
85
    } else {
86
8
        first_date_day = num_days_from_sunday - offset;
87
    }
88
20
    let end_date = NaiveDate::from_ymd_opt(year, month + 1, 1)
89
10
        .unwrap_or_else(|| NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap())
90
        .pred_opt()
91
        .unwrap()
92
        .day();
93

            
94
10
    let mut date: u32 = 0;
95
63
    while date < end_date {
96
53
        let mut week: [u32; 7] = [0; 7];
97
343
        for day in first_date_day..7 {
98
300
            date += 1;
99
600
            week[day as usize] = date;
100
300
            if date >= end_date {
101
                break;
102
            }
103
        }
104
53
        first_date_day = 0;
105

            
106
53
        monthly_calendar.push(week);
107
    }
108

            
109
10
    monthly_calendar
110
20
}
111

            
112
#[test]
113
2
fn january() {
114
1
    let date = NaiveDate::parse_from_str("2021-01-02", "%Y-%m-%d").unwrap();
115
1
    let actual = calendarize(date);
116
1
    assert_eq!(
117
2
        vec![
118
1
            [0, 0, 0, 0, 0, 1, 2],
119
1
            [3, 4, 5, 6, 7, 8, 9],
120
1
            [10, 11, 12, 13, 14, 15, 16],
121
1
            [17, 18, 19, 20, 21, 22, 23],
122
1
            [24, 25, 26, 27, 28, 29, 30],
123
1
            [31, 0, 0, 0, 0, 0, 0]
124
        ],
125
        actual
126
    );
127
2
}
128

            
129
#[test]
130
// Week = [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
131
2
fn with_offset_from_sunday() {
132
1
    let date = NaiveDate::parse_from_str("2019-11-01", "%Y-%m-%d").unwrap();
133
1
    let actual = calendarize_with_offset(date, 0);
134
1
    assert_eq!(
135
2
        vec![
136
1
            [0, 0, 0, 0, 0, 1, 2],
137
1
            [3, 4, 5, 6, 7, 8, 9],
138
1
            [10, 11, 12, 13, 14, 15, 16],
139
1
            [17, 18, 19, 20, 21, 22, 23],
140
1
            [24, 25, 26, 27, 28, 29, 30],
141
        ],
142
        actual
143
    );
144
2
}
145

            
146
#[test]
147
// Week = [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
148
2
fn with_offset_from_monday() {
149
1
    let date = NaiveDate::parse_from_str("2019-11-01", "%Y-%m-%d").unwrap();
150
1
    let actual = calendarize_with_offset(date, 1);
151
1
    assert_eq!(
152
2
        vec![
153
1
            [0, 0, 0, 0, 1, 2, 3],
154
1
            [4, 5, 6, 7, 8, 9, 10],
155
1
            [11, 12, 13, 14, 15, 16, 17],
156
1
            [18, 19, 20, 21, 22, 23, 24],
157
1
            [25, 26, 27, 28, 29, 30, 0],
158
        ],
159
        actual
160
    );
161
2
}
162

            
163
#[test]
164
// Week = [Sat, Sun, Mon, Tue, Wed, Thu, Fri]
165
2
fn with_offset_from_saturday() {
166
1
    let date = NaiveDate::parse_from_str("2019-11-01", "%Y-%m-%d").unwrap();
167
1
    let actual = calendarize_with_offset(date, 6);
168
1
    assert_eq!(
169
2
        vec![
170
1
            [0, 0, 0, 0, 0, 0, 1],
171
1
            [2, 3, 4, 5, 6, 7, 8],
172
1
            [9, 10, 11, 12, 13, 14, 15],
173
1
            [16, 17, 18, 19, 20, 21, 22],
174
1
            [23, 24, 25, 26, 27, 28, 29],
175
1
            [30, 0, 0, 0, 0, 0, 0]
176
        ],
177
        actual
178
    );
179
2
}
180

            
181
#[test]
182
// Week = [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
183
2
fn with_offset_from_sunday_with7() {
184
1
    let date = NaiveDate::parse_from_str("2019-11-01", "%Y-%m-%d").unwrap();
185
1
    let actual = calendarize_with_offset(date, 7);
186
1
    assert_eq!(
187
2
        vec![
188
1
            [0, 0, 0, 0, 0, 1, 2],
189
1
            [3, 4, 5, 6, 7, 8, 9],
190
1
            [10, 11, 12, 13, 14, 15, 16],
191
1
            [17, 18, 19, 20, 21, 22, 23],
192
1
            [24, 25, 26, 27, 28, 29, 30],
193
        ],
194
        actual
195
    );
196
2
}
197

            
198
#[test]
199
2
fn april() {
200
1
    let date = NaiveDate::parse_from_str("2021-04-02", "%Y-%m-%d").unwrap();
201
1
    let actual = calendarize(date);
202
1
    assert_eq!(
203
2
        vec![
204
1
            [0, 0, 0, 0, 1, 2, 3],
205
1
            [4, 5, 6, 7, 8, 9, 10],
206
1
            [11, 12, 13, 14, 15, 16, 17],
207
1
            [18, 19, 20, 21, 22, 23, 24],
208
1
            [25, 26, 27, 28, 29, 30, 0]
209
        ],
210
        actual
211
    );
212
2
}
213

            
214
#[test]
215
2
fn uruudoshi() {
216
1
    let date = NaiveDate::parse_from_str("2020-02-02", "%Y-%m-%d").unwrap();
217
1
    let actual = calendarize(date);
218
1
    assert_eq!(
219
2
        vec![
220
1
            [0, 0, 0, 0, 0, 0, 1],
221
1
            [2, 3, 4, 5, 6, 7, 8],
222
1
            [9, 10, 11, 12, 13, 14, 15],
223
1
            [16, 17, 18, 19, 20, 21, 22],
224
1
            [23, 24, 25, 26, 27, 28, 29]
225
        ],
226
        actual
227
    );
228
2
}
229

            
230
#[test]
231
2
fn uruwanaidoshi() {
232
1
    let date = NaiveDate::parse_from_str("2021-02-02", "%Y-%m-%d").unwrap();
233
1
    let actual = calendarize(date);
234
1
    assert_eq!(
235
2
        vec![
236
1
            [0, 1, 2, 3, 4, 5, 6],
237
1
            [7, 8, 9, 10, 11, 12, 13],
238
1
            [14, 15, 16, 17, 18, 19, 20],
239
1
            [21, 22, 23, 24, 25, 26, 27],
240
1
            [28, 0, 0, 0, 0, 0, 0]
241
        ],
242
        actual
243
    );
244
2
}