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_web::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_web::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
13
pub fn calendarize_with_offset(date: NaiveDate, offset: u32) -> Vec<[u32; 7]> {
75
13
    let mut monthly_calendar: Vec<[u32; 7]> = Vec::with_capacity(6);
76
13
    let year = date.year();
77
13
    let month = date.month();
78
13
    let num_days_from_sunday = NaiveDate::from_ymd_opt(year, month, 1)
79
        .unwrap()
80
        .weekday()
81
        .num_days_from_sunday();
82
13
    let mut first_date_day = if num_days_from_sunday < offset {
83
2
        num_days_from_sunday + (7 - offset)
84
    } else {
85
11
        num_days_from_sunday - offset
86
    };
87
26
    let end_date = NaiveDate::from_ymd_opt(year, month + 1, 1)
88
13
        .unwrap_or_else(|| NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap())
89
        .pred_opt()
90
        .unwrap()
91
        .day();
92

            
93
13
    let mut date: u32 = 0;
94
81
    while date < end_date {
95
68
        let mut week: [u32; 7] = [0; 7];
96
447
        for day in first_date_day..7 {
97
392
            date += 1;
98
784
            week[day as usize] = date;
99
392
            if date >= end_date {
100
                break;
101
            }
102
        }
103
68
        first_date_day = 0;
104

            
105
68
        monthly_calendar.push(week);
106
    }
107

            
108
13
    monthly_calendar
109
26
}
110

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

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

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

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

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

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

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

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