• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::{Days, Months, NaiveDate, MAX_YEAR, MIN_YEAR};
2 use crate::naive::internals::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
3 use crate::{Datelike, TimeDelta, Weekday};
4 
5 // as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`,
6 // we use a separate run-time test.
7 #[test]
test_date_bounds()8 fn test_date_bounds() {
9     let calculated_min = NaiveDate::from_ymd_opt(MIN_YEAR, 1, 1).unwrap();
10     let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap();
11     assert!(
12         NaiveDate::MIN == calculated_min,
13         "`NaiveDate::MIN` should have year flag {:?}",
14         calculated_min.year_flags()
15     );
16     assert!(
17         NaiveDate::MAX == calculated_max,
18         "`NaiveDate::MAX` should have year flag {:?} and ordinal {}",
19         calculated_max.year_flags(),
20         calculated_max.ordinal()
21     );
22 
23     // let's also check that the entire range do not exceed 2^44 seconds
24     // (sometimes used for bounding `TimeDelta` against overflow)
25     let maxsecs = NaiveDate::MAX.signed_duration_since(NaiveDate::MIN).num_seconds();
26     let maxsecs = maxsecs + 86401; // also take care of DateTime
27     assert!(
28         maxsecs < (1 << MAX_BITS),
29         "The entire `NaiveDate` range somehow exceeds 2^{} seconds",
30         MAX_BITS
31     );
32 
33     const BEFORE_MIN: NaiveDate = NaiveDate::BEFORE_MIN;
34     assert_eq!(BEFORE_MIN.year_flags(), YearFlags::from_year(BEFORE_MIN.year()));
35     assert_eq!((BEFORE_MIN.month(), BEFORE_MIN.day()), (12, 31));
36 
37     const AFTER_MAX: NaiveDate = NaiveDate::AFTER_MAX;
38     assert_eq!(AFTER_MAX.year_flags(), YearFlags::from_year(AFTER_MAX.year()));
39     assert_eq!((AFTER_MAX.month(), AFTER_MAX.day()), (1, 1));
40 }
41 
42 #[test]
diff_months()43 fn diff_months() {
44     // identity
45     assert_eq!(
46         NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(0)),
47         Some(NaiveDate::from_ymd_opt(2022, 8, 3).unwrap())
48     );
49 
50     // add with months exceeding `i32::MAX`
51     assert_eq!(
52         NaiveDate::from_ymd_opt(2022, 8, 3)
53             .unwrap()
54             .checked_add_months(Months::new(i32::MAX as u32 + 1)),
55         None
56     );
57 
58     // sub with months exceeding `i32::MIN`
59     assert_eq!(
60         NaiveDate::from_ymd_opt(2022, 8, 3)
61             .unwrap()
62             .checked_sub_months(Months::new(i32::MIN.unsigned_abs() + 1)),
63         None
64     );
65 
66     // add overflowing year
67     assert_eq!(NaiveDate::MAX.checked_add_months(Months::new(1)), None);
68 
69     // add underflowing year
70     assert_eq!(NaiveDate::MIN.checked_sub_months(Months::new(1)), None);
71 
72     // sub crossing year 0 boundary
73     assert_eq!(
74         NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(2050 * 12)),
75         Some(NaiveDate::from_ymd_opt(-28, 8, 3).unwrap())
76     );
77 
78     // add crossing year boundary
79     assert_eq!(
80         NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(6)),
81         Some(NaiveDate::from_ymd_opt(2023, 2, 3).unwrap())
82     );
83 
84     // sub crossing year boundary
85     assert_eq!(
86         NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(10)),
87         Some(NaiveDate::from_ymd_opt(2021, 10, 3).unwrap())
88     );
89 
90     // add clamping day, non-leap year
91     assert_eq!(
92         NaiveDate::from_ymd_opt(2022, 1, 29).unwrap().checked_add_months(Months::new(1)),
93         Some(NaiveDate::from_ymd_opt(2022, 2, 28).unwrap())
94     );
95 
96     // add to leap day
97     assert_eq!(
98         NaiveDate::from_ymd_opt(2022, 10, 29).unwrap().checked_add_months(Months::new(16)),
99         Some(NaiveDate::from_ymd_opt(2024, 2, 29).unwrap())
100     );
101 
102     // add into december
103     assert_eq!(
104         NaiveDate::from_ymd_opt(2022, 10, 31).unwrap().checked_add_months(Months::new(2)),
105         Some(NaiveDate::from_ymd_opt(2022, 12, 31).unwrap())
106     );
107 
108     // sub into december
109     assert_eq!(
110         NaiveDate::from_ymd_opt(2022, 10, 31).unwrap().checked_sub_months(Months::new(10)),
111         Some(NaiveDate::from_ymd_opt(2021, 12, 31).unwrap())
112     );
113 
114     // add into january
115     assert_eq!(
116         NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_add_months(Months::new(5)),
117         Some(NaiveDate::from_ymd_opt(2023, 1, 3).unwrap())
118     );
119 
120     // sub into january
121     assert_eq!(
122         NaiveDate::from_ymd_opt(2022, 8, 3).unwrap().checked_sub_months(Months::new(7)),
123         Some(NaiveDate::from_ymd_opt(2022, 1, 3).unwrap())
124     );
125 }
126 
127 #[test]
test_readme_doomsday()128 fn test_readme_doomsday() {
129     for y in NaiveDate::MIN.year()..=NaiveDate::MAX.year() {
130         // even months
131         let d4 = NaiveDate::from_ymd_opt(y, 4, 4).unwrap();
132         let d6 = NaiveDate::from_ymd_opt(y, 6, 6).unwrap();
133         let d8 = NaiveDate::from_ymd_opt(y, 8, 8).unwrap();
134         let d10 = NaiveDate::from_ymd_opt(y, 10, 10).unwrap();
135         let d12 = NaiveDate::from_ymd_opt(y, 12, 12).unwrap();
136 
137         // nine to five, seven-eleven
138         let d59 = NaiveDate::from_ymd_opt(y, 5, 9).unwrap();
139         let d95 = NaiveDate::from_ymd_opt(y, 9, 5).unwrap();
140         let d711 = NaiveDate::from_ymd_opt(y, 7, 11).unwrap();
141         let d117 = NaiveDate::from_ymd_opt(y, 11, 7).unwrap();
142 
143         // "March 0"
144         let d30 = NaiveDate::from_ymd_opt(y, 3, 1).unwrap().pred_opt().unwrap();
145 
146         let weekday = d30.weekday();
147         let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117];
148         assert!(other_dates.iter().all(|d| d.weekday() == weekday));
149     }
150 }
151 
152 #[test]
test_date_from_ymd()153 fn test_date_from_ymd() {
154     let from_ymd = NaiveDate::from_ymd_opt;
155 
156     assert!(from_ymd(2012, 0, 1).is_none());
157     assert!(from_ymd(2012, 1, 1).is_some());
158     assert!(from_ymd(2012, 2, 29).is_some());
159     assert!(from_ymd(2014, 2, 29).is_none());
160     assert!(from_ymd(2014, 3, 0).is_none());
161     assert!(from_ymd(2014, 3, 1).is_some());
162     assert!(from_ymd(2014, 3, 31).is_some());
163     assert!(from_ymd(2014, 3, 32).is_none());
164     assert!(from_ymd(2014, 12, 31).is_some());
165     assert!(from_ymd(2014, 13, 1).is_none());
166 }
167 
168 #[test]
test_date_from_yo()169 fn test_date_from_yo() {
170     let from_yo = NaiveDate::from_yo_opt;
171     let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
172 
173     assert_eq!(from_yo(2012, 0), None);
174     assert_eq!(from_yo(2012, 1), Some(ymd(2012, 1, 1)));
175     assert_eq!(from_yo(2012, 2), Some(ymd(2012, 1, 2)));
176     assert_eq!(from_yo(2012, 32), Some(ymd(2012, 2, 1)));
177     assert_eq!(from_yo(2012, 60), Some(ymd(2012, 2, 29)));
178     assert_eq!(from_yo(2012, 61), Some(ymd(2012, 3, 1)));
179     assert_eq!(from_yo(2012, 100), Some(ymd(2012, 4, 9)));
180     assert_eq!(from_yo(2012, 200), Some(ymd(2012, 7, 18)));
181     assert_eq!(from_yo(2012, 300), Some(ymd(2012, 10, 26)));
182     assert_eq!(from_yo(2012, 366), Some(ymd(2012, 12, 31)));
183     assert_eq!(from_yo(2012, 367), None);
184     assert_eq!(from_yo(2012, 1 << 28 | 60), None);
185 
186     assert_eq!(from_yo(2014, 0), None);
187     assert_eq!(from_yo(2014, 1), Some(ymd(2014, 1, 1)));
188     assert_eq!(from_yo(2014, 2), Some(ymd(2014, 1, 2)));
189     assert_eq!(from_yo(2014, 32), Some(ymd(2014, 2, 1)));
190     assert_eq!(from_yo(2014, 59), Some(ymd(2014, 2, 28)));
191     assert_eq!(from_yo(2014, 60), Some(ymd(2014, 3, 1)));
192     assert_eq!(from_yo(2014, 100), Some(ymd(2014, 4, 10)));
193     assert_eq!(from_yo(2014, 200), Some(ymd(2014, 7, 19)));
194     assert_eq!(from_yo(2014, 300), Some(ymd(2014, 10, 27)));
195     assert_eq!(from_yo(2014, 365), Some(ymd(2014, 12, 31)));
196     assert_eq!(from_yo(2014, 366), None);
197 }
198 
199 #[test]
test_date_from_isoywd()200 fn test_date_from_isoywd() {
201     let from_isoywd = NaiveDate::from_isoywd_opt;
202     let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
203 
204     assert_eq!(from_isoywd(2004, 0, Weekday::Sun), None);
205     assert_eq!(from_isoywd(2004, 1, Weekday::Mon), Some(ymd(2003, 12, 29)));
206     assert_eq!(from_isoywd(2004, 1, Weekday::Sun), Some(ymd(2004, 1, 4)));
207     assert_eq!(from_isoywd(2004, 2, Weekday::Mon), Some(ymd(2004, 1, 5)));
208     assert_eq!(from_isoywd(2004, 2, Weekday::Sun), Some(ymd(2004, 1, 11)));
209     assert_eq!(from_isoywd(2004, 52, Weekday::Mon), Some(ymd(2004, 12, 20)));
210     assert_eq!(from_isoywd(2004, 52, Weekday::Sun), Some(ymd(2004, 12, 26)));
211     assert_eq!(from_isoywd(2004, 53, Weekday::Mon), Some(ymd(2004, 12, 27)));
212     assert_eq!(from_isoywd(2004, 53, Weekday::Sun), Some(ymd(2005, 1, 2)));
213     assert_eq!(from_isoywd(2004, 54, Weekday::Mon), None);
214 
215     assert_eq!(from_isoywd(2011, 0, Weekday::Sun), None);
216     assert_eq!(from_isoywd(2011, 1, Weekday::Mon), Some(ymd(2011, 1, 3)));
217     assert_eq!(from_isoywd(2011, 1, Weekday::Sun), Some(ymd(2011, 1, 9)));
218     assert_eq!(from_isoywd(2011, 2, Weekday::Mon), Some(ymd(2011, 1, 10)));
219     assert_eq!(from_isoywd(2011, 2, Weekday::Sun), Some(ymd(2011, 1, 16)));
220 
221     assert_eq!(from_isoywd(2018, 51, Weekday::Mon), Some(ymd(2018, 12, 17)));
222     assert_eq!(from_isoywd(2018, 51, Weekday::Sun), Some(ymd(2018, 12, 23)));
223     assert_eq!(from_isoywd(2018, 52, Weekday::Mon), Some(ymd(2018, 12, 24)));
224     assert_eq!(from_isoywd(2018, 52, Weekday::Sun), Some(ymd(2018, 12, 30)));
225     assert_eq!(from_isoywd(2018, 53, Weekday::Mon), None);
226 }
227 
228 #[test]
test_date_from_isoywd_and_iso_week()229 fn test_date_from_isoywd_and_iso_week() {
230     for year in 2000..2401 {
231         for week in 1..54 {
232             for &weekday in [
233                 Weekday::Mon,
234                 Weekday::Tue,
235                 Weekday::Wed,
236                 Weekday::Thu,
237                 Weekday::Fri,
238                 Weekday::Sat,
239                 Weekday::Sun,
240             ]
241             .iter()
242             {
243                 let d = NaiveDate::from_isoywd_opt(year, week, weekday);
244                 if let Some(d) = d {
245                     assert_eq!(d.weekday(), weekday);
246                     let w = d.iso_week();
247                     assert_eq!(w.year(), year);
248                     assert_eq!(w.week(), week);
249                 }
250             }
251         }
252     }
253 
254     for year in 2000..2401 {
255         for month in 1..13 {
256             for day in 1..32 {
257                 let d = NaiveDate::from_ymd_opt(year, month, day);
258                 if let Some(d) = d {
259                     let w = d.iso_week();
260                     let d_ = NaiveDate::from_isoywd_opt(w.year(), w.week(), d.weekday());
261                     assert_eq!(d, d_.unwrap());
262                 }
263             }
264         }
265     }
266 }
267 
268 #[test]
test_date_from_num_days_from_ce()269 fn test_date_from_num_days_from_ce() {
270     let from_ndays_from_ce = NaiveDate::from_num_days_from_ce_opt;
271     assert_eq!(from_ndays_from_ce(1), Some(NaiveDate::from_ymd_opt(1, 1, 1).unwrap()));
272     assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd_opt(1, 1, 2).unwrap()));
273     assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd_opt(1, 1, 31).unwrap()));
274     assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd_opt(1, 2, 1).unwrap()));
275     assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd_opt(1, 2, 28).unwrap()));
276     assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd_opt(1, 3, 1).unwrap()));
277     assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd_opt(1, 12, 31).unwrap()));
278     assert_eq!(from_ndays_from_ce(365 + 1), Some(NaiveDate::from_ymd_opt(2, 1, 1).unwrap()));
279     assert_eq!(from_ndays_from_ce(365 * 2 + 1), Some(NaiveDate::from_ymd_opt(3, 1, 1).unwrap()));
280     assert_eq!(from_ndays_from_ce(365 * 3 + 1), Some(NaiveDate::from_ymd_opt(4, 1, 1).unwrap()));
281     assert_eq!(from_ndays_from_ce(365 * 4 + 2), Some(NaiveDate::from_ymd_opt(5, 1, 1).unwrap()));
282     assert_eq!(from_ndays_from_ce(146097 + 1), Some(NaiveDate::from_ymd_opt(401, 1, 1).unwrap()));
283     assert_eq!(
284         from_ndays_from_ce(146097 * 5 + 1),
285         Some(NaiveDate::from_ymd_opt(2001, 1, 1).unwrap())
286     );
287     assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()));
288     assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd_opt(0, 12, 31).unwrap())); // 1 BCE
289     assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap()));
290     assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap())); // 2 BCE
291 
292     for days in (-9999..10001).map(|x| x * 100) {
293         assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Some(days));
294     }
295 
296     assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce()), Some(NaiveDate::MIN));
297     assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce() - 1), None);
298     assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce()), Some(NaiveDate::MAX));
299     assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce() + 1), None);
300 
301     assert_eq!(from_ndays_from_ce(i32::MIN), None);
302     assert_eq!(from_ndays_from_ce(i32::MAX), None);
303 }
304 
305 #[test]
test_date_from_weekday_of_month_opt()306 fn test_date_from_weekday_of_month_opt() {
307     let ymwd = NaiveDate::from_weekday_of_month_opt;
308     assert_eq!(ymwd(2018, 8, Weekday::Tue, 0), None);
309     assert_eq!(ymwd(2018, 8, Weekday::Wed, 1), Some(NaiveDate::from_ymd_opt(2018, 8, 1).unwrap()));
310     assert_eq!(ymwd(2018, 8, Weekday::Thu, 1), Some(NaiveDate::from_ymd_opt(2018, 8, 2).unwrap()));
311     assert_eq!(ymwd(2018, 8, Weekday::Sun, 1), Some(NaiveDate::from_ymd_opt(2018, 8, 5).unwrap()));
312     assert_eq!(ymwd(2018, 8, Weekday::Mon, 1), Some(NaiveDate::from_ymd_opt(2018, 8, 6).unwrap()));
313     assert_eq!(ymwd(2018, 8, Weekday::Tue, 1), Some(NaiveDate::from_ymd_opt(2018, 8, 7).unwrap()));
314     assert_eq!(ymwd(2018, 8, Weekday::Wed, 2), Some(NaiveDate::from_ymd_opt(2018, 8, 8).unwrap()));
315     assert_eq!(ymwd(2018, 8, Weekday::Sun, 2), Some(NaiveDate::from_ymd_opt(2018, 8, 12).unwrap()));
316     assert_eq!(ymwd(2018, 8, Weekday::Thu, 3), Some(NaiveDate::from_ymd_opt(2018, 8, 16).unwrap()));
317     assert_eq!(ymwd(2018, 8, Weekday::Thu, 4), Some(NaiveDate::from_ymd_opt(2018, 8, 23).unwrap()));
318     assert_eq!(ymwd(2018, 8, Weekday::Thu, 5), Some(NaiveDate::from_ymd_opt(2018, 8, 30).unwrap()));
319     assert_eq!(ymwd(2018, 8, Weekday::Fri, 5), Some(NaiveDate::from_ymd_opt(2018, 8, 31).unwrap()));
320     assert_eq!(ymwd(2018, 8, Weekday::Sat, 5), None);
321 }
322 
323 #[test]
test_date_fields()324 fn test_date_fields() {
325     fn check(year: i32, month: u32, day: u32, ordinal: u32) {
326         let d1 = NaiveDate::from_ymd_opt(year, month, day).unwrap();
327         assert_eq!(d1.year(), year);
328         assert_eq!(d1.month(), month);
329         assert_eq!(d1.day(), day);
330         assert_eq!(d1.ordinal(), ordinal);
331 
332         let d2 = NaiveDate::from_yo_opt(year, ordinal).unwrap();
333         assert_eq!(d2.year(), year);
334         assert_eq!(d2.month(), month);
335         assert_eq!(d2.day(), day);
336         assert_eq!(d2.ordinal(), ordinal);
337 
338         assert_eq!(d1, d2);
339     }
340 
341     check(2012, 1, 1, 1);
342     check(2012, 1, 2, 2);
343     check(2012, 2, 1, 32);
344     check(2012, 2, 29, 60);
345     check(2012, 3, 1, 61);
346     check(2012, 4, 9, 100);
347     check(2012, 7, 18, 200);
348     check(2012, 10, 26, 300);
349     check(2012, 12, 31, 366);
350 
351     check(2014, 1, 1, 1);
352     check(2014, 1, 2, 2);
353     check(2014, 2, 1, 32);
354     check(2014, 2, 28, 59);
355     check(2014, 3, 1, 60);
356     check(2014, 4, 10, 100);
357     check(2014, 7, 19, 200);
358     check(2014, 10, 27, 300);
359     check(2014, 12, 31, 365);
360 }
361 
362 #[test]
test_date_weekday()363 fn test_date_weekday() {
364     assert_eq!(NaiveDate::from_ymd_opt(1582, 10, 15).unwrap().weekday(), Weekday::Fri);
365     // May 20, 1875 = ISO 8601 reference date
366     assert_eq!(NaiveDate::from_ymd_opt(1875, 5, 20).unwrap().weekday(), Weekday::Thu);
367     assert_eq!(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().weekday(), Weekday::Sat);
368 }
369 
370 #[test]
test_date_with_fields()371 fn test_date_with_fields() {
372     let d = NaiveDate::from_ymd_opt(2000, 2, 29).unwrap();
373     assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd_opt(-400, 2, 29).unwrap()));
374     assert_eq!(d.with_year(-100), None);
375     assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd_opt(1600, 2, 29).unwrap()));
376     assert_eq!(d.with_year(1900), None);
377     assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap()));
378     assert_eq!(d.with_year(2001), None);
379     assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd_opt(2004, 2, 29).unwrap()));
380     assert_eq!(d.with_year(i32::MAX), None);
381 
382     let d = NaiveDate::from_ymd_opt(2000, 4, 30).unwrap();
383     assert_eq!(d.with_month(0), None);
384     assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd_opt(2000, 1, 30).unwrap()));
385     assert_eq!(d.with_month(2), None);
386     assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd_opt(2000, 3, 30).unwrap()));
387     assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd_opt(2000, 4, 30).unwrap()));
388     assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd_opt(2000, 12, 30).unwrap()));
389     assert_eq!(d.with_month(13), None);
390     assert_eq!(d.with_month(u32::MAX), None);
391 
392     let d = NaiveDate::from_ymd_opt(2000, 2, 8).unwrap();
393     assert_eq!(d.with_day(0), None);
394     assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd_opt(2000, 2, 1).unwrap()));
395     assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap()));
396     assert_eq!(d.with_day(30), None);
397     assert_eq!(d.with_day(u32::MAX), None);
398 }
399 
400 #[test]
test_date_with_ordinal()401 fn test_date_with_ordinal() {
402     let d = NaiveDate::from_ymd_opt(2000, 5, 5).unwrap();
403     assert_eq!(d.with_ordinal(0), None);
404     assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap()));
405     assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap()));
406     assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd_opt(2000, 3, 1).unwrap()));
407     assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd_opt(2000, 12, 31).unwrap()));
408     assert_eq!(d.with_ordinal(367), None);
409     assert_eq!(d.with_ordinal(1 << 28 | 60), None);
410     let d = NaiveDate::from_ymd_opt(1999, 5, 5).unwrap();
411     assert_eq!(d.with_ordinal(366), None);
412     assert_eq!(d.with_ordinal(u32::MAX), None);
413 }
414 
415 #[test]
test_date_num_days_from_ce()416 fn test_date_num_days_from_ce() {
417     assert_eq!(NaiveDate::from_ymd_opt(1, 1, 1).unwrap().num_days_from_ce(), 1);
418 
419     for year in -9999..10001 {
420         assert_eq!(
421             NaiveDate::from_ymd_opt(year, 1, 1).unwrap().num_days_from_ce(),
422             NaiveDate::from_ymd_opt(year - 1, 12, 31).unwrap().num_days_from_ce() + 1
423         );
424     }
425 }
426 
427 #[test]
test_date_succ()428 fn test_date_succ() {
429     let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
430     assert_eq!(ymd(2014, 5, 6).succ_opt(), Some(ymd(2014, 5, 7)));
431     assert_eq!(ymd(2014, 5, 31).succ_opt(), Some(ymd(2014, 6, 1)));
432     assert_eq!(ymd(2014, 12, 31).succ_opt(), Some(ymd(2015, 1, 1)));
433     assert_eq!(ymd(2016, 2, 28).succ_opt(), Some(ymd(2016, 2, 29)));
434     assert_eq!(ymd(NaiveDate::MAX.year(), 12, 31).succ_opt(), None);
435 }
436 
437 #[test]
test_date_pred()438 fn test_date_pred() {
439     let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
440     assert_eq!(ymd(2016, 3, 1).pred_opt(), Some(ymd(2016, 2, 29)));
441     assert_eq!(ymd(2015, 1, 1).pred_opt(), Some(ymd(2014, 12, 31)));
442     assert_eq!(ymd(2014, 6, 1).pred_opt(), Some(ymd(2014, 5, 31)));
443     assert_eq!(ymd(2014, 5, 7).pred_opt(), Some(ymd(2014, 5, 6)));
444     assert_eq!(ymd(NaiveDate::MIN.year(), 1, 1).pred_opt(), None);
445 }
446 
447 #[test]
test_date_checked_add_signed()448 fn test_date_checked_add_signed() {
449     fn check(lhs: Option<NaiveDate>, delta: TimeDelta, rhs: Option<NaiveDate>) {
450         assert_eq!(lhs.unwrap().checked_add_signed(delta), rhs);
451         assert_eq!(lhs.unwrap().checked_sub_signed(-delta), rhs);
452     }
453     let ymd = NaiveDate::from_ymd_opt;
454 
455     check(ymd(2014, 1, 1), TimeDelta::zero(), ymd(2014, 1, 1));
456     check(ymd(2014, 1, 1), TimeDelta::try_seconds(86399).unwrap(), ymd(2014, 1, 1));
457     // always round towards zero
458     check(ymd(2014, 1, 1), TimeDelta::try_seconds(-86399).unwrap(), ymd(2014, 1, 1));
459     check(ymd(2014, 1, 1), TimeDelta::try_days(1).unwrap(), ymd(2014, 1, 2));
460     check(ymd(2014, 1, 1), TimeDelta::try_days(-1).unwrap(), ymd(2013, 12, 31));
461     check(ymd(2014, 1, 1), TimeDelta::try_days(364).unwrap(), ymd(2014, 12, 31));
462     check(ymd(2014, 1, 1), TimeDelta::try_days(365 * 4 + 1).unwrap(), ymd(2018, 1, 1));
463     check(ymd(2014, 1, 1), TimeDelta::try_days(365 * 400 + 97).unwrap(), ymd(2414, 1, 1));
464 
465     check(ymd(-7, 1, 1), TimeDelta::try_days(365 * 12 + 3).unwrap(), ymd(5, 1, 1));
466 
467     // overflow check
468     check(
469         ymd(0, 1, 1),
470         TimeDelta::try_days(MAX_DAYS_FROM_YEAR_0 as i64).unwrap(),
471         ymd(MAX_YEAR, 12, 31),
472     );
473     check(ymd(0, 1, 1), TimeDelta::try_days(MAX_DAYS_FROM_YEAR_0 as i64 + 1).unwrap(), None);
474     check(ymd(0, 1, 1), TimeDelta::MAX, None);
475     check(
476         ymd(0, 1, 1),
477         TimeDelta::try_days(MIN_DAYS_FROM_YEAR_0 as i64).unwrap(),
478         ymd(MIN_YEAR, 1, 1),
479     );
480     check(ymd(0, 1, 1), TimeDelta::try_days(MIN_DAYS_FROM_YEAR_0 as i64 - 1).unwrap(), None);
481     check(ymd(0, 1, 1), TimeDelta::MIN, None);
482 }
483 
484 #[test]
test_date_signed_duration_since()485 fn test_date_signed_duration_since() {
486     fn check(lhs: Option<NaiveDate>, rhs: Option<NaiveDate>, delta: TimeDelta) {
487         assert_eq!(lhs.unwrap().signed_duration_since(rhs.unwrap()), delta);
488         assert_eq!(rhs.unwrap().signed_duration_since(lhs.unwrap()), -delta);
489     }
490     let ymd = NaiveDate::from_ymd_opt;
491 
492     check(ymd(2014, 1, 1), ymd(2014, 1, 1), TimeDelta::zero());
493     check(ymd(2014, 1, 2), ymd(2014, 1, 1), TimeDelta::try_days(1).unwrap());
494     check(ymd(2014, 12, 31), ymd(2014, 1, 1), TimeDelta::try_days(364).unwrap());
495     check(ymd(2015, 1, 3), ymd(2014, 1, 1), TimeDelta::try_days(365 + 2).unwrap());
496     check(ymd(2018, 1, 1), ymd(2014, 1, 1), TimeDelta::try_days(365 * 4 + 1).unwrap());
497     check(ymd(2414, 1, 1), ymd(2014, 1, 1), TimeDelta::try_days(365 * 400 + 97).unwrap());
498 
499     check(
500         ymd(MAX_YEAR, 12, 31),
501         ymd(0, 1, 1),
502         TimeDelta::try_days(MAX_DAYS_FROM_YEAR_0 as i64).unwrap(),
503     );
504     check(
505         ymd(MIN_YEAR, 1, 1),
506         ymd(0, 1, 1),
507         TimeDelta::try_days(MIN_DAYS_FROM_YEAR_0 as i64).unwrap(),
508     );
509 }
510 
511 #[test]
test_date_add_days()512 fn test_date_add_days() {
513     fn check(lhs: Option<NaiveDate>, days: Days, rhs: Option<NaiveDate>) {
514         assert_eq!(lhs.unwrap().checked_add_days(days), rhs);
515     }
516     let ymd = NaiveDate::from_ymd_opt;
517 
518     check(ymd(2014, 1, 1), Days::new(0), ymd(2014, 1, 1));
519     // always round towards zero
520     check(ymd(2014, 1, 1), Days::new(1), ymd(2014, 1, 2));
521     check(ymd(2014, 1, 1), Days::new(364), ymd(2014, 12, 31));
522     check(ymd(2014, 1, 1), Days::new(365 * 4 + 1), ymd(2018, 1, 1));
523     check(ymd(2014, 1, 1), Days::new(365 * 400 + 97), ymd(2414, 1, 1));
524 
525     check(ymd(-7, 1, 1), Days::new(365 * 12 + 3), ymd(5, 1, 1));
526 
527     // overflow check
528     check(ymd(0, 1, 1), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), ymd(MAX_YEAR, 12, 31));
529     check(ymd(0, 1, 1), Days::new(u64::try_from(MAX_DAYS_FROM_YEAR_0).unwrap() + 1), None);
530 }
531 
532 #[test]
test_date_sub_days()533 fn test_date_sub_days() {
534     fn check(lhs: Option<NaiveDate>, days: Days, rhs: Option<NaiveDate>) {
535         assert_eq!(lhs.unwrap().checked_sub_days(days), rhs);
536     }
537     let ymd = NaiveDate::from_ymd_opt;
538 
539     check(ymd(2014, 1, 1), Days::new(0), ymd(2014, 1, 1));
540     check(ymd(2014, 1, 2), Days::new(1), ymd(2014, 1, 1));
541     check(ymd(2014, 12, 31), Days::new(364), ymd(2014, 1, 1));
542     check(ymd(2015, 1, 3), Days::new(365 + 2), ymd(2014, 1, 1));
543     check(ymd(2018, 1, 1), Days::new(365 * 4 + 1), ymd(2014, 1, 1));
544     check(ymd(2414, 1, 1), Days::new(365 * 400 + 97), ymd(2014, 1, 1));
545 
546     check(ymd(MAX_YEAR, 12, 31), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), ymd(0, 1, 1));
547     check(
548         ymd(0, 1, 1),
549         Days::new((-MIN_DAYS_FROM_YEAR_0).try_into().unwrap()),
550         ymd(MIN_YEAR, 1, 1),
551     );
552 }
553 
554 #[test]
test_date_addassignment()555 fn test_date_addassignment() {
556     let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
557     let mut date = ymd(2016, 10, 1);
558     date += TimeDelta::try_days(10).unwrap();
559     assert_eq!(date, ymd(2016, 10, 11));
560     date += TimeDelta::try_days(30).unwrap();
561     assert_eq!(date, ymd(2016, 11, 10));
562 }
563 
564 #[test]
test_date_subassignment()565 fn test_date_subassignment() {
566     let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
567     let mut date = ymd(2016, 10, 11);
568     date -= TimeDelta::try_days(10).unwrap();
569     assert_eq!(date, ymd(2016, 10, 1));
570     date -= TimeDelta::try_days(2).unwrap();
571     assert_eq!(date, ymd(2016, 9, 29));
572 }
573 
574 #[test]
test_date_fmt()575 fn test_date_fmt() {
576     assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2012, 3, 4).unwrap()), "2012-03-04");
577     assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(0, 3, 4).unwrap()), "0000-03-04");
578     assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(-307, 3, 4).unwrap()), "-0307-03-04");
579     assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(12345, 3, 4).unwrap()), "+12345-03-04");
580 
581     assert_eq!(NaiveDate::from_ymd_opt(2012, 3, 4).unwrap().to_string(), "2012-03-04");
582     assert_eq!(NaiveDate::from_ymd_opt(0, 3, 4).unwrap().to_string(), "0000-03-04");
583     assert_eq!(NaiveDate::from_ymd_opt(-307, 3, 4).unwrap().to_string(), "-0307-03-04");
584     assert_eq!(NaiveDate::from_ymd_opt(12345, 3, 4).unwrap().to_string(), "+12345-03-04");
585 
586     // the format specifier should have no effect on `NaiveTime`
587     assert_eq!(format!("{:+30?}", NaiveDate::from_ymd_opt(1234, 5, 6).unwrap()), "1234-05-06");
588     assert_eq!(format!("{:30?}", NaiveDate::from_ymd_opt(12345, 6, 7).unwrap()), "+12345-06-07");
589 }
590 
591 #[test]
test_date_from_str()592 fn test_date_from_str() {
593     // valid cases
594     let valid = [
595         "-0000000123456-1-2",
596         "    -123456 - 1 - 2    ",
597         "-12345-1-2",
598         "-1234-12-31",
599         "-7-6-5",
600         "350-2-28",
601         "360-02-29",
602         "0360-02-29",
603         "2015-2 -18",
604         "2015-02-18",
605         "+70-2-18",
606         "+70000-2-18",
607         "+00007-2-18",
608     ];
609     for &s in &valid {
610         eprintln!("test_date_from_str valid {:?}", s);
611         let d = match s.parse::<NaiveDate>() {
612             Ok(d) => d,
613             Err(e) => panic!("parsing `{}` has failed: {}", s, e),
614         };
615         eprintln!("d {:?} (NaiveDate)", d);
616         let s_ = format!("{:?}", d);
617         eprintln!("s_ {:?}", s_);
618         // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
619         let d_ = match s_.parse::<NaiveDate>() {
620             Ok(d) => d,
621             Err(e) => {
622                 panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
623             }
624         };
625         eprintln!("d_ {:?} (NaiveDate)", d_);
626         assert!(
627             d == d_,
628             "`{}` is parsed into `{:?}`, but reparsed result \
629                             `{:?}` does not match",
630             s,
631             d,
632             d_
633         );
634     }
635 
636     // some invalid cases
637     // since `ParseErrorKind` is private, all we can do is to check if there was an error
638     let invalid = [
639         "",                     // empty
640         "x",                    // invalid
641         "Fri, 09 Aug 2013 GMT", // valid date, wrong format
642         "Sat Jun 30 2012",      // valid date, wrong format
643         "1441497364.649",       // valid datetime, wrong format
644         "+1441497364.649",      // valid datetime, wrong format
645         "+1441497364",          // valid datetime, wrong format
646         "2014/02/03",           // valid date, wrong format
647         "2014",                 // datetime missing data
648         "2014-01",              // datetime missing data
649         "2014-01-00",           // invalid day
650         "2014-11-32",           // invalid day
651         "2014-13-01",           // invalid month
652         "2014-13-57",           // invalid month, day
653         "9999999-9-9",          // invalid year (out of bounds)
654     ];
655     for &s in &invalid {
656         eprintln!("test_date_from_str invalid {:?}", s);
657         assert!(s.parse::<NaiveDate>().is_err());
658     }
659 }
660 
661 #[test]
test_date_parse_from_str()662 fn test_date_parse_from_str() {
663     let ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
664     assert_eq!(
665         NaiveDate::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
666         Ok(ymd(2014, 5, 7))
667     ); // ignore time and offset
668     assert_eq!(
669         NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"),
670         Ok(ymd(2015, 2, 2))
671     );
672     assert_eq!(NaiveDate::parse_from_str("Fri, 09 Aug 13", "%a, %d %b %y"), Ok(ymd(2013, 8, 9)));
673     assert!(NaiveDate::parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err());
674     assert!(NaiveDate::parse_from_str("2014-57", "%Y-%m-%d").is_err());
675     assert!(NaiveDate::parse_from_str("2014", "%Y").is_err()); // insufficient
676 
677     assert_eq!(
678         NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(),
679         NaiveDate::from_ymd_opt(2020, 1, 12),
680     );
681 
682     assert_eq!(
683         NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(),
684         NaiveDate::from_ymd_opt(2019, 1, 13),
685     );
686 }
687 
688 #[test]
test_day_iterator_limit()689 fn test_day_iterator_limit() {
690     assert_eq!(NaiveDate::from_ymd_opt(MAX_YEAR, 12, 29).unwrap().iter_days().take(4).count(), 2);
691     assert_eq!(
692         NaiveDate::from_ymd_opt(MIN_YEAR, 1, 3).unwrap().iter_days().rev().take(4).count(),
693         2
694     );
695 }
696 
697 #[test]
test_week_iterator_limit()698 fn test_week_iterator_limit() {
699     assert_eq!(NaiveDate::from_ymd_opt(MAX_YEAR, 12, 12).unwrap().iter_weeks().take(4).count(), 2);
700     assert_eq!(
701         NaiveDate::from_ymd_opt(MIN_YEAR, 1, 15).unwrap().iter_weeks().rev().take(4).count(),
702         2
703     );
704 }
705 
706 #[test]
test_weeks_from()707 fn test_weeks_from() {
708     // tests per: https://github.com/chronotope/chrono/issues/961
709     // these internally use `weeks_from` via the parsing infrastructure
710     assert_eq!(
711         NaiveDate::parse_from_str("2020-01-0", "%Y-%W-%w").ok(),
712         NaiveDate::from_ymd_opt(2020, 1, 12),
713     );
714     assert_eq!(
715         NaiveDate::parse_from_str("2019-01-0", "%Y-%W-%w").ok(),
716         NaiveDate::from_ymd_opt(2019, 1, 13),
717     );
718 
719     // direct tests
720     for (y, starts_on) in &[
721         (2019, Weekday::Tue),
722         (2020, Weekday::Wed),
723         (2021, Weekday::Fri),
724         (2022, Weekday::Sat),
725         (2023, Weekday::Sun),
726         (2024, Weekday::Mon),
727         (2025, Weekday::Wed),
728         (2026, Weekday::Thu),
729     ] {
730         for day in &[
731             Weekday::Mon,
732             Weekday::Tue,
733             Weekday::Wed,
734             Weekday::Thu,
735             Weekday::Fri,
736             Weekday::Sat,
737             Weekday::Sun,
738         ] {
739             assert_eq!(
740                 NaiveDate::from_ymd_opt(*y, 1, 1).map(|d| d.weeks_from(*day)),
741                 Some(if day == starts_on { 1 } else { 0 })
742             );
743 
744             // last day must always be in week 52 or 53
745             assert!(
746                 [52, 53].contains(&NaiveDate::from_ymd_opt(*y, 12, 31).unwrap().weeks_from(*day)),
747             );
748         }
749     }
750 
751     let base = NaiveDate::from_ymd_opt(2019, 1, 1).unwrap();
752 
753     // 400 years covers all year types
754     for day in &[
755         Weekday::Mon,
756         Weekday::Tue,
757         Weekday::Wed,
758         Weekday::Thu,
759         Weekday::Fri,
760         Weekday::Sat,
761         Weekday::Sun,
762     ] {
763         // must always be below 54
764         for dplus in 1..(400 * 366) {
765             assert!((base + Days::new(dplus)).weeks_from(*day) < 54)
766         }
767     }
768 }
769 
770 #[test]
test_with_0_overflow()771 fn test_with_0_overflow() {
772     let dt = NaiveDate::from_ymd_opt(2023, 4, 18).unwrap();
773     assert!(dt.with_month0(4294967295).is_none());
774     assert!(dt.with_day0(4294967295).is_none());
775     assert!(dt.with_ordinal0(4294967295).is_none());
776 }
777 
778 #[test]
test_leap_year()779 fn test_leap_year() {
780     for year in 0..=MAX_YEAR {
781         let date = NaiveDate::from_ymd_opt(year, 1, 1).unwrap();
782         let is_leap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
783         assert_eq!(date.leap_year(), is_leap);
784         assert_eq!(date.leap_year(), date.with_ordinal(366).is_some());
785     }
786 }
787 
788 #[test]
test_date_yearflags()789 fn test_date_yearflags() {
790     for (year, year_flags, _) in YEAR_FLAGS {
791         assert_eq!(NaiveDate::from_yo_opt(year, 1).unwrap().year_flags(), year_flags);
792     }
793 }
794 
795 #[test]
test_weekday_with_yearflags()796 fn test_weekday_with_yearflags() {
797     for (year, year_flags, first_weekday) in YEAR_FLAGS {
798         let first_day_of_year = NaiveDate::from_yo_opt(year, 1).unwrap();
799         dbg!(year);
800         assert_eq!(first_day_of_year.year_flags(), year_flags);
801         assert_eq!(first_day_of_year.weekday(), first_weekday);
802 
803         let mut prev = first_day_of_year.weekday();
804         for ordinal in 2u32..=year_flags.ndays() {
805             let date = NaiveDate::from_yo_opt(year, ordinal).unwrap();
806             let expected = prev.succ();
807             assert_eq!(date.weekday(), expected);
808             prev = expected;
809         }
810     }
811 }
812 
813 #[test]
test_isoweekdate_with_yearflags()814 fn test_isoweekdate_with_yearflags() {
815     for (year, year_flags, _) in YEAR_FLAGS {
816         // January 4 should be in the first week
817         let jan4 = NaiveDate::from_ymd_opt(year, 1, 4).unwrap();
818         let iso_week = jan4.iso_week();
819         assert_eq!(jan4.year_flags(), year_flags);
820         assert_eq!(iso_week.week(), 1);
821     }
822 }
823 
824 #[test]
test_date_to_mdf_to_date()825 fn test_date_to_mdf_to_date() {
826     for (year, year_flags, _) in YEAR_FLAGS {
827         for ordinal in 1..=year_flags.ndays() {
828             let date = NaiveDate::from_yo_opt(year, ordinal).unwrap();
829             assert_eq!(date, NaiveDate::from_mdf(date.year(), date.mdf()).unwrap());
830         }
831     }
832 }
833 
834 // Used for testing some methods with all combinations of `YearFlags`.
835 // (year, flags, first weekday of year)
836 const YEAR_FLAGS: [(i32, YearFlags, Weekday); 14] = [
837     (2006, A, Weekday::Sun),
838     (2005, B, Weekday::Sat),
839     (2010, C, Weekday::Fri),
840     (2009, D, Weekday::Thu),
841     (2003, E, Weekday::Wed),
842     (2002, F, Weekday::Tue),
843     (2001, G, Weekday::Mon),
844     (2012, AG, Weekday::Sun),
845     (2000, BA, Weekday::Sat),
846     (2016, CB, Weekday::Fri),
847     (2004, DC, Weekday::Thu),
848     (2020, ED, Weekday::Wed),
849     (2008, FE, Weekday::Tue),
850     (2024, GF, Weekday::Mon),
851 ];
852 
853 #[test]
854 #[cfg(feature = "rkyv-validation")]
test_rkyv_validation()855 fn test_rkyv_validation() {
856     let date_min = NaiveDate::MIN;
857     let bytes = rkyv::to_bytes::<_, 4>(&date_min).unwrap();
858     assert_eq!(rkyv::from_bytes::<NaiveDate>(&bytes).unwrap(), date_min);
859 
860     let date_max = NaiveDate::MAX;
861     let bytes = rkyv::to_bytes::<_, 4>(&date_max).unwrap();
862     assert_eq!(rkyv::from_bytes::<NaiveDate>(&bytes).unwrap(), date_max);
863 }
864 
865 //   MAX_YEAR-12-31 minus 0000-01-01
866 // = (MAX_YEAR-12-31 minus 0000-12-31) + (0000-12-31 - 0000-01-01)
867 // = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365
868 // = (MAX_YEAR + 1) * 365 + (# of leap years from 0001 to MAX_YEAR)
869 const MAX_DAYS_FROM_YEAR_0: i32 =
870     (MAX_YEAR + 1) * 365 + MAX_YEAR / 4 - MAX_YEAR / 100 + MAX_YEAR / 400;
871 
872 //   MIN_YEAR-01-01 minus 0000-01-01
873 // = MIN_YEAR * 365 + (# of leap years from MIN_YEAR to 0000)
874 const MIN_DAYS_FROM_YEAR_0: i32 = MIN_YEAR * 365 + MIN_YEAR / 4 - MIN_YEAR / 100 + MIN_YEAR / 400;
875 
876 // only used for testing, but duplicated in naive::datetime
877 const MAX_BITS: usize = 44;
878