]>
Commit | Line | Data |
---|---|---|
2c00a5a8 XL |
1 | // This is a part of Chrono. |
2 | // See README.md and LICENSE.txt for details. | |
3 | ||
4 | //! ISO 8601 calendar date without timezone. | |
5 | ||
6 | use std::{str, fmt, hash}; | |
7 | use std::ops::{Add, Sub, AddAssign, SubAssign}; | |
8 | use num::traits::ToPrimitive; | |
9 | use oldtime::Duration as OldDuration; | |
10 | ||
11 | use {Weekday, Datelike}; | |
12 | use div::div_mod_floor; | |
13 | use naive::{NaiveTime, NaiveDateTime, IsoWeek}; | |
14 | use format::{Item, Numeric, Pad}; | |
15 | use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; | |
16 | ||
17 | use super::isoweek; | |
18 | use super::internals::{self, DateImpl, Of, Mdf, YearFlags}; | |
19 | ||
20 | const MAX_YEAR: i32 = internals::MAX_YEAR; | |
21 | const MIN_YEAR: i32 = internals::MIN_YEAR; | |
22 | ||
23 | // MAX_YEAR-12-31 minus 0000-01-01 | |
24 | // = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + (0001-01-01 minus 0000-01-01) - 1 day | |
25 | // = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + 365 days | |
26 | // = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365 days | |
27 | #[cfg(test)] // only used for testing | |
28 | const MAX_DAYS_FROM_YEAR_0: i32 = MAX_YEAR * 365 + | |
29 | MAX_YEAR / 4 - | |
30 | MAX_YEAR / 100 + | |
31 | MAX_YEAR / 400 + 365; | |
32 | ||
33 | // MIN_YEAR-01-01 minus 0000-01-01 | |
34 | // = (MIN_YEAR+400n+1)-01-01 minus (400n+1)-01-01 | |
35 | // = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - ((400n+1)-01-01 minus 0001-01-01) | |
36 | // = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - 146097n days | |
37 | // | |
38 | // n is set to 1000 for convenience. | |
39 | #[cfg(test)] // only used for testing | |
40 | const MIN_DAYS_FROM_YEAR_0: i32 = (MIN_YEAR + 400_000) * 365 + | |
41 | (MIN_YEAR + 400_000) / 4 - | |
42 | (MIN_YEAR + 400_000) / 100 + | |
43 | (MIN_YEAR + 400_000) / 400 - 146097_000; | |
44 | ||
45 | #[cfg(test)] // only used for testing, but duplicated in naive::datetime | |
46 | const MAX_BITS: usize = 44; | |
47 | ||
48 | /// ISO 8601 calendar date without timezone. | |
49 | /// Allows for every [proleptic Gregorian date](#calendar-date) | |
50 | /// from Jan 1, 262145 BCE to Dec 31, 262143 CE. | |
51 | /// Also supports the conversion from ISO 8601 ordinal and week date. | |
52 | /// | |
53 | /// # Calendar Date | |
54 | /// | |
55 | /// The ISO 8601 **calendar date** follows the proleptic Gregorian calendar. | |
56 | /// It is like a normal civil calendar but note some slight differences: | |
57 | /// | |
58 | /// * Dates before the Gregorian calendar's inception in 1582 are defined via the extrapolation. | |
59 | /// Be careful, as historical dates are often noted in the Julian calendar and others | |
60 | /// and the transition to Gregorian may differ across countries (as late as early 20C). | |
61 | /// | |
62 | /// (Some example: Both Shakespeare from Britain and Cervantes from Spain seemingly died | |
63 | /// on the same calendar date---April 23, 1616---but in the different calendar. | |
64 | /// Britain used the Julian calendar at that time, so Shakespeare's death is later.) | |
65 | /// | |
66 | /// * ISO 8601 calendars has the year 0, which is 1 BCE (a year before 1 CE). | |
67 | /// If you need a typical BCE/BC and CE/AD notation for year numbers, | |
68 | /// use the [`Datelike::year_ce`](../trait.Datelike.html#method.year_ce) method. | |
69 | /// | |
70 | /// # Week Date | |
71 | /// | |
72 | /// The ISO 8601 **week date** is a triple of year number, week number | |
73 | /// and [day of the week](../enum.Weekday.html) with the following rules: | |
74 | /// | |
75 | /// * A week consists of Monday through Sunday, and is always numbered within some year. | |
76 | /// The week number ranges from 1 to 52 or 53 depending on the year. | |
77 | /// | |
78 | /// * The week 1 of given year is defined as the first week containing January 4 of that year, | |
79 | /// or equivalently, the first week containing four or more days in that year. | |
80 | /// | |
81 | /// * The year number in the week date may *not* correspond to the actual Gregorian year. | |
82 | /// For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015. | |
83 | /// | |
84 | /// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date), | |
85 | /// but [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) and | |
86 | /// [`Datelike::weekday`](../trait.Datelike.html#tymethod.weekday) methods | |
87 | /// can be used to get the corresponding week date. | |
88 | /// | |
89 | /// # Ordinal Date | |
90 | /// | |
91 | /// The ISO 8601 **ordinal date** is a pair of year number and day of the year ("ordinal"). | |
92 | /// The ordinal number ranges from 1 to 365 or 366 depending on the year. | |
93 | /// The year number is same to that of the [calendar date](#calendar-date). | |
94 | /// | |
95 | /// This is currently the internal format of Chrono's date types. | |
96 | #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] | |
97 | pub struct NaiveDate { | |
98 | ymdf: DateImpl, // (year << 13) | of | |
99 | } | |
100 | ||
101 | /// The minimum possible `NaiveDate` (January 1, 262145 BCE). | |
102 | pub const MIN_DATE: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ }; | |
103 | /// The maximum possible `NaiveDate` (December 31, 262143 CE). | |
104 | pub const MAX_DATE: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ }; | |
105 | ||
106 | // as it is hard to verify year flags in `MIN_DATE` and `MAX_DATE`, | |
107 | // we use a separate run-time test. | |
108 | #[test] | |
109 | fn test_date_bounds() { | |
110 | let calculated_min = NaiveDate::from_ymd(MIN_YEAR, 1, 1); | |
111 | let calculated_max = NaiveDate::from_ymd(MAX_YEAR, 12, 31); | |
112 | assert!(MIN_DATE == calculated_min, | |
113 | "`MIN_DATE` should have a year flag {:?}", calculated_min.of().flags()); | |
114 | assert!(MAX_DATE == calculated_max, | |
115 | "`MAX_DATE` should have a year flag {:?}", calculated_max.of().flags()); | |
116 | ||
117 | // let's also check that the entire range do not exceed 2^44 seconds | |
118 | // (sometimes used for bounding `Duration` against overflow) | |
119 | let maxsecs = MAX_DATE.signed_duration_since(MIN_DATE).num_seconds(); | |
120 | let maxsecs = maxsecs + 86401; // also take care of DateTime | |
121 | assert!(maxsecs < (1 << MAX_BITS), | |
122 | "The entire `NaiveDate` range somehow exceeds 2^{} seconds", MAX_BITS); | |
123 | } | |
124 | ||
125 | impl NaiveDate { | |
126 | /// Makes a new `NaiveDate` from year and packed ordinal-flags, with a verification. | |
127 | fn from_of(year: i32, of: Of) -> Option<NaiveDate> { | |
128 | if year >= MIN_YEAR && year <= MAX_YEAR && of.valid() { | |
129 | let Of(of) = of; | |
130 | Some(NaiveDate { ymdf: (year << 13) | (of as DateImpl) }) | |
131 | } else { | |
132 | None | |
133 | } | |
134 | } | |
135 | ||
136 | /// Makes a new `NaiveDate` from year and packed month-day-flags, with a verification. | |
137 | fn from_mdf(year: i32, mdf: Mdf) -> Option<NaiveDate> { | |
138 | NaiveDate::from_of(year, mdf.to_of()) | |
139 | } | |
140 | ||
141 | /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) | |
142 | /// (year, month and day). | |
143 | /// | |
144 | /// Panics on the out-of-range date, invalid month and/or day. | |
145 | /// | |
146 | /// # Example | |
147 | /// | |
148 | /// ~~~~ | |
149 | /// use chrono::{NaiveDate, Datelike, Weekday}; | |
150 | /// | |
151 | /// let d = NaiveDate::from_ymd(2015, 3, 14); | |
152 | /// assert_eq!(d.year(), 2015); | |
153 | /// assert_eq!(d.month(), 3); | |
154 | /// assert_eq!(d.day(), 14); | |
155 | /// assert_eq!(d.ordinal(), 73); // day of year | |
156 | /// assert_eq!(d.iso_week().year(), 2015); | |
157 | /// assert_eq!(d.iso_week().week(), 11); | |
158 | /// assert_eq!(d.weekday(), Weekday::Sat); | |
159 | /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE | |
160 | /// ~~~~ | |
161 | pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate { | |
162 | NaiveDate::from_ymd_opt(year, month, day).expect("invalid or out-of-range date") | |
163 | } | |
164 | ||
165 | /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) | |
166 | /// (year, month and day). | |
167 | /// | |
168 | /// Returns `None` on the out-of-range date, invalid month and/or day. | |
169 | /// | |
170 | /// # Example | |
171 | /// | |
172 | /// ~~~~ | |
173 | /// use chrono::NaiveDate; | |
174 | /// | |
175 | /// let from_ymd_opt = NaiveDate::from_ymd_opt; | |
176 | /// | |
177 | /// assert!(from_ymd_opt(2015, 3, 14).is_some()); | |
178 | /// assert!(from_ymd_opt(2015, 0, 14).is_none()); | |
179 | /// assert!(from_ymd_opt(2015, 2, 29).is_none()); | |
180 | /// assert!(from_ymd_opt(-4, 2, 29).is_some()); // 5 BCE is a leap year | |
181 | /// assert!(from_ymd_opt(400000, 1, 1).is_none()); | |
182 | /// assert!(from_ymd_opt(-400000, 1, 1).is_none()); | |
183 | /// ~~~~ | |
184 | pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> { | |
185 | let flags = YearFlags::from_year(year); | |
186 | NaiveDate::from_mdf(year, Mdf::new(month, day, flags)) | |
187 | } | |
188 | ||
189 | /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) | |
190 | /// (year and day of the year). | |
191 | /// | |
192 | /// Panics on the out-of-range date and/or invalid day of year. | |
193 | /// | |
194 | /// # Example | |
195 | /// | |
196 | /// ~~~~ | |
197 | /// use chrono::{NaiveDate, Datelike, Weekday}; | |
198 | /// | |
199 | /// let d = NaiveDate::from_yo(2015, 73); | |
200 | /// assert_eq!(d.ordinal(), 73); | |
201 | /// assert_eq!(d.year(), 2015); | |
202 | /// assert_eq!(d.month(), 3); | |
203 | /// assert_eq!(d.day(), 14); | |
204 | /// assert_eq!(d.iso_week().year(), 2015); | |
205 | /// assert_eq!(d.iso_week().week(), 11); | |
206 | /// assert_eq!(d.weekday(), Weekday::Sat); | |
207 | /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE | |
208 | /// ~~~~ | |
209 | pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate { | |
210 | NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date") | |
211 | } | |
212 | ||
213 | /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) | |
214 | /// (year and day of the year). | |
215 | /// | |
216 | /// Returns `None` on the out-of-range date and/or invalid day of year. | |
217 | /// | |
218 | /// # Example | |
219 | /// | |
220 | /// ~~~~ | |
221 | /// use chrono::NaiveDate; | |
222 | /// | |
223 | /// let from_yo_opt = NaiveDate::from_yo_opt; | |
224 | /// | |
225 | /// assert!(from_yo_opt(2015, 100).is_some()); | |
226 | /// assert!(from_yo_opt(2015, 0).is_none()); | |
227 | /// assert!(from_yo_opt(2015, 365).is_some()); | |
228 | /// assert!(from_yo_opt(2015, 366).is_none()); | |
229 | /// assert!(from_yo_opt(-4, 366).is_some()); // 5 BCE is a leap year | |
230 | /// assert!(from_yo_opt(400000, 1).is_none()); | |
231 | /// assert!(from_yo_opt(-400000, 1).is_none()); | |
232 | /// ~~~~ | |
233 | pub fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> { | |
234 | let flags = YearFlags::from_year(year); | |
235 | NaiveDate::from_of(year, Of::new(ordinal, flags)) | |
236 | } | |
237 | ||
238 | /// Makes a new `NaiveDate` from the [ISO week date](#week-date) | |
239 | /// (year, week number and day of the week). | |
240 | /// The resulting `NaiveDate` may have a different year from the input year. | |
241 | /// | |
242 | /// Panics on the out-of-range date and/or invalid week number. | |
243 | /// | |
244 | /// # Example | |
245 | /// | |
246 | /// ~~~~ | |
247 | /// use chrono::{NaiveDate, Datelike, Weekday}; | |
248 | /// | |
249 | /// let d = NaiveDate::from_isoywd(2015, 11, Weekday::Sat); | |
250 | /// assert_eq!(d.iso_week().year(), 2015); | |
251 | /// assert_eq!(d.iso_week().week(), 11); | |
252 | /// assert_eq!(d.weekday(), Weekday::Sat); | |
253 | /// assert_eq!(d.year(), 2015); | |
254 | /// assert_eq!(d.month(), 3); | |
255 | /// assert_eq!(d.day(), 14); | |
256 | /// assert_eq!(d.ordinal(), 73); // day of year | |
257 | /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE | |
258 | /// ~~~~ | |
259 | pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate { | |
260 | NaiveDate::from_isoywd_opt(year, week, weekday).expect("invalid or out-of-range date") | |
261 | } | |
262 | ||
263 | /// Makes a new `NaiveDate` from the [ISO week date](#week-date) | |
264 | /// (year, week number and day of the week). | |
265 | /// The resulting `NaiveDate` may have a different year from the input year. | |
266 | /// | |
267 | /// Returns `None` on the out-of-range date and/or invalid week number. | |
268 | /// | |
269 | /// # Example | |
270 | /// | |
271 | /// ~~~~ | |
272 | /// use chrono::{NaiveDate, Weekday}; | |
273 | /// | |
274 | /// let from_ymd = NaiveDate::from_ymd; | |
275 | /// let from_isoywd_opt = NaiveDate::from_isoywd_opt; | |
276 | /// | |
277 | /// assert_eq!(from_isoywd_opt(2015, 0, Weekday::Sun), None); | |
278 | /// assert_eq!(from_isoywd_opt(2015, 10, Weekday::Sun), Some(from_ymd(2015, 3, 8))); | |
279 | /// assert_eq!(from_isoywd_opt(2015, 30, Weekday::Mon), Some(from_ymd(2015, 7, 20))); | |
280 | /// assert_eq!(from_isoywd_opt(2015, 60, Weekday::Mon), None); | |
281 | /// | |
282 | /// assert_eq!(from_isoywd_opt(400000, 10, Weekday::Fri), None); | |
283 | /// assert_eq!(from_isoywd_opt(-400000, 10, Weekday::Sat), None); | |
284 | /// ~~~~ | |
285 | /// | |
286 | /// The year number of ISO week date may differ from that of the calendar date. | |
287 | /// | |
288 | /// ~~~~ | |
289 | /// # use chrono::{NaiveDate, Weekday}; | |
290 | /// # let from_ymd = NaiveDate::from_ymd; | |
291 | /// # let from_isoywd_opt = NaiveDate::from_isoywd_opt; | |
292 | /// // Mo Tu We Th Fr Sa Su | |
293 | /// // 2014-W52 22 23 24 25 26 27 28 has 4+ days of new year, | |
294 | /// // 2015-W01 29 30 31 1 2 3 4 <- so this is the first week | |
295 | /// assert_eq!(from_isoywd_opt(2014, 52, Weekday::Sun), Some(from_ymd(2014, 12, 28))); | |
296 | /// assert_eq!(from_isoywd_opt(2014, 53, Weekday::Mon), None); | |
297 | /// assert_eq!(from_isoywd_opt(2015, 1, Weekday::Mon), Some(from_ymd(2014, 12, 29))); | |
298 | /// | |
299 | /// // 2015-W52 21 22 23 24 25 26 27 has 4+ days of old year, | |
300 | /// // 2015-W53 28 29 30 31 1 2 3 <- so this is the last week | |
301 | /// // 2016-W01 4 5 6 7 8 9 10 | |
302 | /// assert_eq!(from_isoywd_opt(2015, 52, Weekday::Sun), Some(from_ymd(2015, 12, 27))); | |
303 | /// assert_eq!(from_isoywd_opt(2015, 53, Weekday::Sun), Some(from_ymd(2016, 1, 3))); | |
304 | /// assert_eq!(from_isoywd_opt(2015, 54, Weekday::Mon), None); | |
305 | /// assert_eq!(from_isoywd_opt(2016, 1, Weekday::Mon), Some(from_ymd(2016, 1, 4))); | |
306 | /// ~~~~ | |
307 | pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<NaiveDate> { | |
308 | let flags = YearFlags::from_year(year); | |
309 | let nweeks = flags.nisoweeks(); | |
310 | if 1 <= week && week <= nweeks { | |
311 | // ordinal = week ordinal - delta | |
312 | let weekord = week * 7 + weekday as u32; | |
313 | let delta = flags.isoweek_delta(); | |
314 | if weekord <= delta { // ordinal < 1, previous year | |
315 | let prevflags = YearFlags::from_year(year - 1); | |
316 | NaiveDate::from_of(year - 1, Of::new(weekord + prevflags.ndays() - delta, | |
317 | prevflags)) | |
318 | } else { | |
319 | let ordinal = weekord - delta; | |
320 | let ndays = flags.ndays(); | |
321 | if ordinal <= ndays { // this year | |
322 | NaiveDate::from_of(year, Of::new(ordinal, flags)) | |
323 | } else { // ordinal > ndays, next year | |
324 | let nextflags = YearFlags::from_year(year + 1); | |
325 | NaiveDate::from_of(year + 1, Of::new(ordinal - ndays, nextflags)) | |
326 | } | |
327 | } | |
328 | } else { | |
329 | None | |
330 | } | |
331 | } | |
332 | ||
333 | /// Makes a new `NaiveDate` from the number of days since January 1, 1 (Day 1) | |
334 | /// in the proleptic Gregorian calendar. | |
335 | /// | |
336 | /// Panics on the out-of-range date. | |
337 | /// | |
338 | /// # Example | |
339 | /// | |
340 | /// ~~~~ | |
341 | /// use chrono::{NaiveDate, Datelike, Weekday}; | |
342 | /// | |
343 | /// let d = NaiveDate::from_num_days_from_ce(735671); | |
344 | /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE | |
345 | /// assert_eq!(d.year(), 2015); | |
346 | /// assert_eq!(d.month(), 3); | |
347 | /// assert_eq!(d.day(), 14); | |
348 | /// assert_eq!(d.ordinal(), 73); // day of year | |
349 | /// assert_eq!(d.iso_week().year(), 2015); | |
350 | /// assert_eq!(d.iso_week().week(), 11); | |
351 | /// assert_eq!(d.weekday(), Weekday::Sat); | |
352 | /// ~~~~ | |
353 | /// | |
354 | /// While not directly supported by Chrono, | |
355 | /// it is easy to convert from the Julian day number | |
356 | /// (January 1, 4713 BCE in the *Julian* calendar being Day 0) | |
357 | /// to Gregorian with this method. | |
358 | /// (Note that this panics when `jd` is out of range.) | |
359 | /// | |
360 | /// ~~~~ | |
361 | /// use chrono::NaiveDate; | |
362 | /// | |
363 | /// fn jd_to_date(jd: i32) -> NaiveDate { | |
364 | /// // keep in mind that the Julian day number is 0-based | |
365 | /// // while this method requires an 1-based number. | |
366 | /// NaiveDate::from_num_days_from_ce(jd - 1721425) | |
367 | /// } | |
368 | /// | |
369 | /// // January 1, 4713 BCE in Julian = November 24, 4714 BCE in Gregorian | |
370 | /// assert_eq!(jd_to_date(0), NaiveDate::from_ymd(-4713, 11, 24)); | |
371 | /// | |
372 | /// assert_eq!(jd_to_date(1721426), NaiveDate::from_ymd(1, 1, 1)); | |
373 | /// assert_eq!(jd_to_date(2450000), NaiveDate::from_ymd(1995, 10, 9)); | |
374 | /// assert_eq!(jd_to_date(2451545), NaiveDate::from_ymd(2000, 1, 1)); | |
375 | /// ~~~~ | |
376 | #[inline] | |
377 | pub fn from_num_days_from_ce(days: i32) -> NaiveDate { | |
378 | NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date") | |
379 | } | |
380 | ||
381 | /// Makes a new `NaiveDate` from the number of days since January 1, 1 (Day 1) | |
382 | /// in the proleptic Gregorian calendar. | |
383 | /// | |
384 | /// Returns `None` on the out-of-range date. | |
385 | /// | |
386 | /// # Example | |
387 | /// | |
388 | /// ~~~~ | |
389 | /// use chrono::NaiveDate; | |
390 | /// | |
391 | /// let from_ndays_opt = NaiveDate::from_num_days_from_ce_opt; | |
392 | /// let from_ymd = NaiveDate::from_ymd; | |
393 | /// | |
394 | /// assert_eq!(from_ndays_opt(730_000), Some(from_ymd(1999, 9, 3))); | |
395 | /// assert_eq!(from_ndays_opt(1), Some(from_ymd(1, 1, 1))); | |
396 | /// assert_eq!(from_ndays_opt(0), Some(from_ymd(0, 12, 31))); | |
397 | /// assert_eq!(from_ndays_opt(-1), Some(from_ymd(0, 12, 30))); | |
398 | /// assert_eq!(from_ndays_opt(100_000_000), None); | |
399 | /// assert_eq!(from_ndays_opt(-100_000_000), None); | |
400 | /// ~~~~ | |
401 | pub fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> { | |
402 | let days = days + 365; // make December 31, 1 BCE equal to day 0 | |
403 | let (year_div_400, cycle) = div_mod_floor(days, 146097); | |
404 | let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); | |
405 | let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); | |
406 | NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, | |
407 | Of::new(ordinal, flags)) | |
408 | } | |
409 | ||
410 | /// Parses a string with the specified format string and returns a new `NaiveDate`. | |
411 | /// See the [`format::strftime` module](../format/strftime/index.html) | |
412 | /// on the supported escape sequences. | |
413 | /// | |
414 | /// # Example | |
415 | /// | |
416 | /// ~~~~ | |
417 | /// use chrono::NaiveDate; | |
418 | /// | |
419 | /// let parse_from_str = NaiveDate::parse_from_str; | |
420 | /// | |
421 | /// assert_eq!(parse_from_str("2015-09-05", "%Y-%m-%d"), | |
422 | /// Ok(NaiveDate::from_ymd(2015, 9, 5))); | |
423 | /// assert_eq!(parse_from_str("5sep2015", "%d%b%Y"), | |
424 | /// Ok(NaiveDate::from_ymd(2015, 9, 5))); | |
425 | /// ~~~~ | |
426 | /// | |
427 | /// Time and offset is ignored for the purpose of parsing. | |
428 | /// | |
429 | /// ~~~~ | |
430 | /// # use chrono::NaiveDate; | |
431 | /// # let parse_from_str = NaiveDate::parse_from_str; | |
432 | /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), | |
433 | /// Ok(NaiveDate::from_ymd(2014, 5, 17))); | |
434 | /// ~~~~ | |
435 | /// | |
436 | /// Out-of-bound dates or insufficient fields are errors. | |
437 | /// | |
438 | /// ~~~~ | |
439 | /// # use chrono::NaiveDate; | |
440 | /// # let parse_from_str = NaiveDate::parse_from_str; | |
441 | /// assert!(parse_from_str("2015/9", "%Y/%m").is_err()); | |
442 | /// assert!(parse_from_str("2015/9/31", "%Y/%m/%d").is_err()); | |
443 | /// ~~~~ | |
444 | /// | |
445 | /// All parsed fields should be consistent to each other, otherwise it's an error. | |
446 | /// | |
447 | /// ~~~~ | |
448 | /// # use chrono::NaiveDate; | |
449 | /// # let parse_from_str = NaiveDate::parse_from_str; | |
450 | /// assert!(parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err()); | |
451 | /// ~~~~ | |
452 | pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<NaiveDate> { | |
453 | let mut parsed = Parsed::new(); | |
454 | try!(parse(&mut parsed, s, StrftimeItems::new(fmt))); | |
455 | parsed.to_naive_date() | |
456 | } | |
457 | ||
458 | /// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`. | |
459 | /// | |
460 | /// # Example | |
461 | /// | |
462 | /// ~~~~ | |
463 | /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime}; | |
464 | /// | |
465 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
466 | /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789); | |
467 | /// | |
468 | /// let dt: NaiveDateTime = d.and_time(t); | |
469 | /// assert_eq!(dt.date(), d); | |
470 | /// assert_eq!(dt.time(), t); | |
471 | /// ~~~~ | |
472 | #[inline] | |
473 | pub fn and_time(&self, time: NaiveTime) -> NaiveDateTime { | |
474 | NaiveDateTime::new(*self, time) | |
475 | } | |
476 | ||
477 | /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. | |
478 | /// | |
479 | /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; | |
480 | /// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead. | |
481 | /// | |
482 | /// Panics on invalid hour, minute and/or second. | |
483 | /// | |
484 | /// # Example | |
485 | /// | |
486 | /// ~~~~ | |
487 | /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; | |
488 | /// | |
489 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
490 | /// | |
491 | /// let dt: NaiveDateTime = d.and_hms(12, 34, 56); | |
492 | /// assert_eq!(dt.year(), 2015); | |
493 | /// assert_eq!(dt.weekday(), Weekday::Wed); | |
494 | /// assert_eq!(dt.second(), 56); | |
495 | /// ~~~~ | |
496 | #[inline] | |
497 | pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { | |
498 | self.and_hms_opt(hour, min, sec).expect("invalid time") | |
499 | } | |
500 | ||
501 | /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. | |
502 | /// | |
503 | /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; | |
504 | /// use `NaiveDate::and_hms_*_opt` methods with a subsecond parameter instead. | |
505 | /// | |
506 | /// Returns `None` on invalid hour, minute and/or second. | |
507 | /// | |
508 | /// # Example | |
509 | /// | |
510 | /// ~~~~ | |
511 | /// use chrono::NaiveDate; | |
512 | /// | |
513 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
514 | /// assert!(d.and_hms_opt(12, 34, 56).is_some()); | |
515 | /// assert!(d.and_hms_opt(12, 34, 60).is_none()); // use `and_hms_milli_opt` instead | |
516 | /// assert!(d.and_hms_opt(12, 60, 56).is_none()); | |
517 | /// assert!(d.and_hms_opt(24, 34, 56).is_none()); | |
518 | /// ~~~~ | |
519 | #[inline] | |
520 | pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<NaiveDateTime> { | |
521 | NaiveTime::from_hms_opt(hour, min, sec).map(|time| self.and_time(time)) | |
522 | } | |
523 | ||
524 | /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. | |
525 | /// | |
526 | /// The millisecond part can exceed 1,000 | |
527 | /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). | |
528 | /// | |
529 | /// Panics on invalid hour, minute, second and/or millisecond. | |
530 | /// | |
531 | /// # Example | |
532 | /// | |
533 | /// ~~~~ | |
534 | /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; | |
535 | /// | |
536 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
537 | /// | |
538 | /// let dt: NaiveDateTime = d.and_hms_milli(12, 34, 56, 789); | |
539 | /// assert_eq!(dt.year(), 2015); | |
540 | /// assert_eq!(dt.weekday(), Weekday::Wed); | |
541 | /// assert_eq!(dt.second(), 56); | |
542 | /// assert_eq!(dt.nanosecond(), 789_000_000); | |
543 | /// ~~~~ | |
544 | #[inline] | |
545 | pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime { | |
546 | self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") | |
547 | } | |
548 | ||
549 | /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. | |
550 | /// | |
551 | /// The millisecond part can exceed 1,000 | |
552 | /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). | |
553 | /// | |
554 | /// Returns `None` on invalid hour, minute, second and/or millisecond. | |
555 | /// | |
556 | /// # Example | |
557 | /// | |
558 | /// ~~~~ | |
559 | /// use chrono::NaiveDate; | |
560 | /// | |
561 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
562 | /// assert!(d.and_hms_milli_opt(12, 34, 56, 789).is_some()); | |
563 | /// assert!(d.and_hms_milli_opt(12, 34, 59, 1_789).is_some()); // leap second | |
564 | /// assert!(d.and_hms_milli_opt(12, 34, 59, 2_789).is_none()); | |
565 | /// assert!(d.and_hms_milli_opt(12, 34, 60, 789).is_none()); | |
566 | /// assert!(d.and_hms_milli_opt(12, 60, 56, 789).is_none()); | |
567 | /// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none()); | |
568 | /// ~~~~ | |
569 | #[inline] | |
570 | pub fn and_hms_milli_opt(&self, hour: u32, min: u32, sec: u32, | |
571 | milli: u32) -> Option<NaiveDateTime> { | |
572 | NaiveTime::from_hms_milli_opt(hour, min, sec, milli).map(|time| self.and_time(time)) | |
573 | } | |
574 | ||
575 | /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. | |
576 | /// | |
577 | /// The microsecond part can exceed 1,000,000 | |
578 | /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). | |
579 | /// | |
580 | /// Panics on invalid hour, minute, second and/or microsecond. | |
581 | /// | |
582 | /// # Example | |
583 | /// | |
584 | /// ~~~~ | |
585 | /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; | |
586 | /// | |
587 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
588 | /// | |
589 | /// let dt: NaiveDateTime = d.and_hms_micro(12, 34, 56, 789_012); | |
590 | /// assert_eq!(dt.year(), 2015); | |
591 | /// assert_eq!(dt.weekday(), Weekday::Wed); | |
592 | /// assert_eq!(dt.second(), 56); | |
593 | /// assert_eq!(dt.nanosecond(), 789_012_000); | |
594 | /// ~~~~ | |
595 | #[inline] | |
596 | pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime { | |
597 | self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") | |
598 | } | |
599 | ||
600 | /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. | |
601 | /// | |
602 | /// The microsecond part can exceed 1,000,000 | |
603 | /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). | |
604 | /// | |
605 | /// Returns `None` on invalid hour, minute, second and/or microsecond. | |
606 | /// | |
607 | /// # Example | |
608 | /// | |
609 | /// ~~~~ | |
610 | /// use chrono::NaiveDate; | |
611 | /// | |
612 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
613 | /// assert!(d.and_hms_micro_opt(12, 34, 56, 789_012).is_some()); | |
614 | /// assert!(d.and_hms_micro_opt(12, 34, 59, 1_789_012).is_some()); // leap second | |
615 | /// assert!(d.and_hms_micro_opt(12, 34, 59, 2_789_012).is_none()); | |
616 | /// assert!(d.and_hms_micro_opt(12, 34, 60, 789_012).is_none()); | |
617 | /// assert!(d.and_hms_micro_opt(12, 60, 56, 789_012).is_none()); | |
618 | /// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none()); | |
619 | /// ~~~~ | |
620 | #[inline] | |
621 | pub fn and_hms_micro_opt(&self, hour: u32, min: u32, sec: u32, | |
622 | micro: u32) -> Option<NaiveDateTime> { | |
623 | NaiveTime::from_hms_micro_opt(hour, min, sec, micro).map(|time| self.and_time(time)) | |
624 | } | |
625 | ||
626 | /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. | |
627 | /// | |
628 | /// The nanosecond part can exceed 1,000,000,000 | |
629 | /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). | |
630 | /// | |
631 | /// Panics on invalid hour, minute, second and/or nanosecond. | |
632 | /// | |
633 | /// # Example | |
634 | /// | |
635 | /// ~~~~ | |
636 | /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; | |
637 | /// | |
638 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
639 | /// | |
640 | /// let dt: NaiveDateTime = d.and_hms_nano(12, 34, 56, 789_012_345); | |
641 | /// assert_eq!(dt.year(), 2015); | |
642 | /// assert_eq!(dt.weekday(), Weekday::Wed); | |
643 | /// assert_eq!(dt.second(), 56); | |
644 | /// assert_eq!(dt.nanosecond(), 789_012_345); | |
645 | /// ~~~~ | |
646 | #[inline] | |
647 | pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime { | |
648 | self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") | |
649 | } | |
650 | ||
651 | /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. | |
652 | /// | |
653 | /// The nanosecond part can exceed 1,000,000,000 | |
654 | /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). | |
655 | /// | |
656 | /// Returns `None` on invalid hour, minute, second and/or nanosecond. | |
657 | /// | |
658 | /// # Example | |
659 | /// | |
660 | /// ~~~~ | |
661 | /// use chrono::NaiveDate; | |
662 | /// | |
663 | /// let d = NaiveDate::from_ymd(2015, 6, 3); | |
664 | /// assert!(d.and_hms_nano_opt(12, 34, 56, 789_012_345).is_some()); | |
665 | /// assert!(d.and_hms_nano_opt(12, 34, 59, 1_789_012_345).is_some()); // leap second | |
666 | /// assert!(d.and_hms_nano_opt(12, 34, 59, 2_789_012_345).is_none()); | |
667 | /// assert!(d.and_hms_nano_opt(12, 34, 60, 789_012_345).is_none()); | |
668 | /// assert!(d.and_hms_nano_opt(12, 60, 56, 789_012_345).is_none()); | |
669 | /// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none()); | |
670 | /// ~~~~ | |
671 | #[inline] | |
672 | pub fn and_hms_nano_opt(&self, hour: u32, min: u32, sec: u32, | |
673 | nano: u32) -> Option<NaiveDateTime> { | |
674 | NaiveTime::from_hms_nano_opt(hour, min, sec, nano).map(|time| self.and_time(time)) | |
675 | } | |
676 | ||
677 | /// Returns the packed month-day-flags. | |
678 | #[inline] | |
679 | fn mdf(&self) -> Mdf { | |
680 | self.of().to_mdf() | |
681 | } | |
682 | ||
683 | /// Returns the packed ordinal-flags. | |
684 | #[inline] | |
685 | fn of(&self) -> Of { | |
686 | Of((self.ymdf & 0b1111_11111_1111) as u32) | |
687 | } | |
688 | ||
689 | /// Makes a new `NaiveDate` with the packed month-day-flags changed. | |
690 | /// | |
691 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
692 | #[inline] | |
693 | fn with_mdf(&self, mdf: Mdf) -> Option<NaiveDate> { | |
694 | self.with_of(mdf.to_of()) | |
695 | } | |
696 | ||
697 | /// Makes a new `NaiveDate` with the packed ordinal-flags changed. | |
698 | /// | |
699 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
700 | #[inline] | |
701 | fn with_of(&self, of: Of) -> Option<NaiveDate> { | |
702 | if of.valid() { | |
703 | let Of(of) = of; | |
704 | Some(NaiveDate { ymdf: (self.ymdf & !0b111111111_1111) | of as DateImpl }) | |
705 | } else { | |
706 | None | |
707 | } | |
708 | } | |
709 | ||
710 | /// Makes a new `NaiveDate` for the next calendar date. | |
711 | /// | |
712 | /// Panics when `self` is the last representable date. | |
713 | /// | |
714 | /// # Example | |
715 | /// | |
716 | /// ~~~~ | |
717 | /// use chrono::NaiveDate; | |
718 | /// | |
719 | /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).succ(), NaiveDate::from_ymd(2015, 6, 4)); | |
720 | /// assert_eq!(NaiveDate::from_ymd(2015, 6, 30).succ(), NaiveDate::from_ymd(2015, 7, 1)); | |
721 | /// assert_eq!(NaiveDate::from_ymd(2015, 12, 31).succ(), NaiveDate::from_ymd(2016, 1, 1)); | |
722 | /// ~~~~ | |
723 | #[inline] | |
724 | pub fn succ(&self) -> NaiveDate { | |
725 | self.succ_opt().expect("out of bound") | |
726 | } | |
727 | ||
728 | /// Makes a new `NaiveDate` for the next calendar date. | |
729 | /// | |
730 | /// Returns `None` when `self` is the last representable date. | |
731 | /// | |
732 | /// # Example | |
733 | /// | |
734 | /// ~~~~ | |
735 | /// use chrono::NaiveDate; | |
736 | /// use chrono::naive::MAX_DATE; | |
737 | /// | |
738 | /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).succ_opt(), | |
739 | /// Some(NaiveDate::from_ymd(2015, 6, 4))); | |
740 | /// assert_eq!(MAX_DATE.succ_opt(), None); | |
741 | /// ~~~~ | |
742 | #[inline] | |
743 | pub fn succ_opt(&self) -> Option<NaiveDate> { | |
744 | self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1)) | |
745 | } | |
746 | ||
747 | /// Makes a new `NaiveDate` for the previous calendar date. | |
748 | /// | |
749 | /// Panics when `self` is the first representable date. | |
750 | /// | |
751 | /// # Example | |
752 | /// | |
753 | /// ~~~~ | |
754 | /// use chrono::NaiveDate; | |
755 | /// | |
756 | /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).pred(), NaiveDate::from_ymd(2015, 6, 2)); | |
757 | /// assert_eq!(NaiveDate::from_ymd(2015, 6, 1).pred(), NaiveDate::from_ymd(2015, 5, 31)); | |
758 | /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).pred(), NaiveDate::from_ymd(2014, 12, 31)); | |
759 | /// ~~~~ | |
760 | #[inline] | |
761 | pub fn pred(&self) -> NaiveDate { | |
762 | self.pred_opt().expect("out of bound") | |
763 | } | |
764 | ||
765 | /// Makes a new `NaiveDate` for the previous calendar date. | |
766 | /// | |
767 | /// Returns `None` when `self` is the first representable date. | |
768 | /// | |
769 | /// # Example | |
770 | /// | |
771 | /// ~~~~ | |
772 | /// use chrono::NaiveDate; | |
773 | /// use chrono::naive::MIN_DATE; | |
774 | /// | |
775 | /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).pred_opt(), | |
776 | /// Some(NaiveDate::from_ymd(2015, 6, 2))); | |
777 | /// assert_eq!(MIN_DATE.pred_opt(), None); | |
778 | /// ~~~~ | |
779 | #[inline] | |
780 | pub fn pred_opt(&self) -> Option<NaiveDate> { | |
781 | self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31)) | |
782 | } | |
783 | ||
784 | /// Adds the `days` part of given `Duration` to the current date. | |
785 | /// | |
786 | /// Returns `None` when it will result in overflow. | |
787 | /// | |
788 | /// # Example | |
789 | /// | |
790 | /// ~~~~ | |
791 | /// # extern crate chrono; extern crate time; fn main() { | |
792 | /// use chrono::NaiveDate; | |
793 | /// use chrono::naive::MAX_DATE; | |
794 | /// use time::Duration; | |
795 | /// | |
796 | /// let d = NaiveDate::from_ymd(2015, 9, 5); | |
797 | /// assert_eq!(d.checked_add_signed(Duration::days(40)), | |
798 | /// Some(NaiveDate::from_ymd(2015, 10, 15))); | |
799 | /// assert_eq!(d.checked_add_signed(Duration::days(-40)), | |
800 | /// Some(NaiveDate::from_ymd(2015, 7, 27))); | |
801 | /// assert_eq!(d.checked_add_signed(Duration::days(1_000_000_000)), None); | |
802 | /// assert_eq!(d.checked_add_signed(Duration::days(-1_000_000_000)), None); | |
803 | /// assert_eq!(MAX_DATE.checked_add_signed(Duration::days(1)), None); | |
804 | /// # } | |
805 | /// ~~~~ | |
806 | pub fn checked_add_signed(self, rhs: OldDuration) -> Option<NaiveDate> { | |
807 | let year = self.year(); | |
808 | let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); | |
809 | let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); | |
810 | let cycle = try_opt!((cycle as i32).checked_add(try_opt!(rhs.num_days().to_i32()))); | |
811 | let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146097); | |
812 | year_div_400 += cycle_div_400y; | |
813 | ||
814 | let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); | |
815 | let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); | |
816 | NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, | |
817 | Of::new(ordinal, flags)) | |
818 | } | |
819 | ||
820 | /// Subtracts the `days` part of given `Duration` from the current date. | |
821 | /// | |
822 | /// Returns `None` when it will result in overflow. | |
823 | /// | |
824 | /// # Example | |
825 | /// | |
826 | /// ~~~~ | |
827 | /// # extern crate chrono; extern crate time; fn main() { | |
828 | /// use chrono::NaiveDate; | |
829 | /// use chrono::naive::MIN_DATE; | |
830 | /// use time::Duration; | |
831 | /// | |
832 | /// let d = NaiveDate::from_ymd(2015, 9, 5); | |
833 | /// assert_eq!(d.checked_sub_signed(Duration::days(40)), | |
834 | /// Some(NaiveDate::from_ymd(2015, 7, 27))); | |
835 | /// assert_eq!(d.checked_sub_signed(Duration::days(-40)), | |
836 | /// Some(NaiveDate::from_ymd(2015, 10, 15))); | |
837 | /// assert_eq!(d.checked_sub_signed(Duration::days(1_000_000_000)), None); | |
838 | /// assert_eq!(d.checked_sub_signed(Duration::days(-1_000_000_000)), None); | |
839 | /// assert_eq!(MIN_DATE.checked_sub_signed(Duration::days(1)), None); | |
840 | /// # } | |
841 | /// ~~~~ | |
842 | pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<NaiveDate> { | |
843 | let year = self.year(); | |
844 | let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); | |
845 | let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); | |
846 | let cycle = try_opt!((cycle as i32).checked_sub(try_opt!(rhs.num_days().to_i32()))); | |
847 | let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146097); | |
848 | year_div_400 += cycle_div_400y; | |
849 | ||
850 | let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); | |
851 | let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); | |
852 | NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, | |
853 | Of::new(ordinal, flags)) | |
854 | } | |
855 | ||
856 | /// Subtracts another `NaiveDate` from the current date. | |
857 | /// Returns a `Duration` of integral numbers. | |
858 | /// | |
859 | /// This does not overflow or underflow at all, | |
860 | /// as all possible output fits in the range of `Duration`. | |
861 | /// | |
862 | /// # Example | |
863 | /// | |
864 | /// ~~~~ | |
865 | /// # extern crate chrono; extern crate time; fn main() { | |
866 | /// use chrono::NaiveDate; | |
867 | /// use time::Duration; | |
868 | /// | |
869 | /// let from_ymd = NaiveDate::from_ymd; | |
870 | /// let since = NaiveDate::signed_duration_since; | |
871 | /// | |
872 | /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), Duration::zero()); | |
873 | /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 12, 31)), Duration::days(1)); | |
874 | /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 2)), Duration::days(-1)); | |
875 | /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 9, 23)), Duration::days(100)); | |
876 | /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 1, 1)), Duration::days(365)); | |
877 | /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), Duration::days(365*4 + 1)); | |
878 | /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), Duration::days(365*400 + 97)); | |
879 | /// # } | |
880 | /// ~~~~ | |
881 | pub fn signed_duration_since(self, rhs: NaiveDate) -> OldDuration { | |
882 | let year1 = self.year(); | |
883 | let year2 = rhs.year(); | |
884 | let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400); | |
885 | let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400); | |
886 | let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal()) as i64; | |
887 | let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64; | |
888 | OldDuration::days((year1_div_400 as i64 - year2_div_400 as i64) * 146097 + | |
889 | (cycle1 - cycle2)) | |
890 | } | |
891 | ||
892 | /// Formats the date with the specified formatting items. | |
893 | /// Otherwise it is same to the ordinary `format` method. | |
894 | /// | |
895 | /// The `Iterator` of items should be `Clone`able, | |
896 | /// since the resulting `DelayedFormat` value may be formatted multiple times. | |
897 | /// | |
898 | /// # Example | |
899 | /// | |
900 | /// ~~~~ | |
901 | /// use chrono::NaiveDate; | |
902 | /// use chrono::format::strftime::StrftimeItems; | |
903 | /// | |
904 | /// let fmt = StrftimeItems::new("%Y-%m-%d"); | |
905 | /// let d = NaiveDate::from_ymd(2015, 9, 5); | |
906 | /// assert_eq!(d.format_with_items(fmt.clone()).to_string(), "2015-09-05"); | |
907 | /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); | |
908 | /// ~~~~ | |
909 | /// | |
910 | /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. | |
911 | /// | |
912 | /// ~~~~ | |
913 | /// # use chrono::NaiveDate; | |
914 | /// # use chrono::format::strftime::StrftimeItems; | |
915 | /// # let fmt = StrftimeItems::new("%Y-%m-%d").clone(); | |
916 | /// # let d = NaiveDate::from_ymd(2015, 9, 5); | |
917 | /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05"); | |
918 | /// ~~~~ | |
919 | #[inline] | |
920 | pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I> | |
921 | where I: Iterator<Item=Item<'a>> + Clone { | |
922 | DelayedFormat::new(Some(*self), None, items) | |
923 | } | |
924 | ||
925 | /// Formats the date with the specified format string. | |
926 | /// See the [`format::strftime` module](../format/strftime/index.html) | |
927 | /// on the supported escape sequences. | |
928 | /// | |
929 | /// This returns a `DelayedFormat`, | |
930 | /// which gets converted to a string only when actual formatting happens. | |
931 | /// You may use the `to_string` method to get a `String`, | |
932 | /// or just feed it into `print!` and other formatting macros. | |
933 | /// (In this way it avoids the redundant memory allocation.) | |
934 | /// | |
935 | /// A wrong format string does *not* issue an error immediately. | |
936 | /// Rather, converting or formatting the `DelayedFormat` fails. | |
937 | /// You are recommended to immediately use `DelayedFormat` for this reason. | |
938 | /// | |
939 | /// # Example | |
940 | /// | |
941 | /// ~~~~ | |
942 | /// use chrono::NaiveDate; | |
943 | /// | |
944 | /// let d = NaiveDate::from_ymd(2015, 9, 5); | |
945 | /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); | |
946 | /// assert_eq!(d.format("%A, %-d %B, %C%y").to_string(), "Saturday, 5 September, 2015"); | |
947 | /// ~~~~ | |
948 | /// | |
949 | /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. | |
950 | /// | |
951 | /// ~~~~ | |
952 | /// # use chrono::NaiveDate; | |
953 | /// # let d = NaiveDate::from_ymd(2015, 9, 5); | |
954 | /// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05"); | |
955 | /// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015"); | |
956 | /// ~~~~ | |
957 | #[inline] | |
958 | pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { | |
959 | self.format_with_items(StrftimeItems::new(fmt)) | |
960 | } | |
961 | } | |
962 | ||
963 | impl Datelike for NaiveDate { | |
964 | /// Returns the year number in the [calendar date](#calendar-date). | |
965 | /// | |
966 | /// # Example | |
967 | /// | |
968 | /// ~~~~ | |
969 | /// use chrono::{NaiveDate, Datelike}; | |
970 | /// | |
971 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).year(), 2015); | |
972 | /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).year(), -308); // 309 BCE | |
973 | /// ~~~~ | |
974 | #[inline] | |
975 | fn year(&self) -> i32 { | |
976 | self.ymdf >> 13 | |
977 | } | |
978 | ||
979 | /// Returns the month number starting from 1. | |
980 | /// | |
981 | /// The return value ranges from 1 to 12. | |
982 | /// | |
983 | /// # Example | |
984 | /// | |
985 | /// ~~~~ | |
986 | /// use chrono::{NaiveDate, Datelike}; | |
987 | /// | |
988 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month(), 9); | |
989 | /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month(), 3); | |
990 | /// ~~~~ | |
991 | #[inline] | |
992 | fn month(&self) -> u32 { | |
993 | self.mdf().month() | |
994 | } | |
995 | ||
996 | /// Returns the month number starting from 0. | |
997 | /// | |
998 | /// The return value ranges from 0 to 11. | |
999 | /// | |
1000 | /// # Example | |
1001 | /// | |
1002 | /// ~~~~ | |
1003 | /// use chrono::{NaiveDate, Datelike}; | |
1004 | /// | |
1005 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month0(), 8); | |
1006 | /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month0(), 2); | |
1007 | /// ~~~~ | |
1008 | #[inline] | |
1009 | fn month0(&self) -> u32 { | |
1010 | self.mdf().month() - 1 | |
1011 | } | |
1012 | ||
1013 | /// Returns the day of month starting from 1. | |
1014 | /// | |
1015 | /// The return value ranges from 1 to 31. (The last day of month differs by months.) | |
1016 | /// | |
1017 | /// # Example | |
1018 | /// | |
1019 | /// ~~~~ | |
1020 | /// use chrono::{NaiveDate, Datelike}; | |
1021 | /// | |
1022 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day(), 8); | |
1023 | /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day(), 14); | |
1024 | /// ~~~~ | |
1025 | /// | |
1026 | /// Combined with [`NaiveDate::pred`](#method.pred), | |
1027 | /// one can determine the number of days in a particular month. | |
1028 | /// (Note that this panics when `year` is out of range.) | |
1029 | /// | |
1030 | /// ~~~~ | |
1031 | /// use chrono::{NaiveDate, Datelike}; | |
1032 | /// | |
1033 | /// fn ndays_in_month(year: i32, month: u32) -> u32 { | |
1034 | /// // the first day of the next month... | |
1035 | /// let (y, m) = if month == 12 { (year + 1, 1) } else { (year, month + 1) }; | |
1036 | /// let d = NaiveDate::from_ymd(y, m, 1); | |
1037 | /// | |
1038 | /// // ...is preceded by the last day of the original month | |
1039 | /// d.pred().day() | |
1040 | /// } | |
1041 | /// | |
1042 | /// assert_eq!(ndays_in_month(2015, 8), 31); | |
1043 | /// assert_eq!(ndays_in_month(2015, 9), 30); | |
1044 | /// assert_eq!(ndays_in_month(2015, 12), 31); | |
1045 | /// assert_eq!(ndays_in_month(2016, 2), 29); | |
1046 | /// assert_eq!(ndays_in_month(2017, 2), 28); | |
1047 | /// ~~~~ | |
1048 | #[inline] | |
1049 | fn day(&self) -> u32 { | |
1050 | self.mdf().day() | |
1051 | } | |
1052 | ||
1053 | /// Returns the day of month starting from 0. | |
1054 | /// | |
1055 | /// The return value ranges from 0 to 30. (The last day of month differs by months.) | |
1056 | /// | |
1057 | /// # Example | |
1058 | /// | |
1059 | /// ~~~~ | |
1060 | /// use chrono::{NaiveDate, Datelike}; | |
1061 | /// | |
1062 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day0(), 7); | |
1063 | /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day0(), 13); | |
1064 | /// ~~~~ | |
1065 | #[inline] | |
1066 | fn day0(&self) -> u32 { | |
1067 | self.mdf().day() - 1 | |
1068 | } | |
1069 | ||
1070 | /// Returns the day of year starting from 1. | |
1071 | /// | |
1072 | /// The return value ranges from 1 to 366. (The last day of year differs by years.) | |
1073 | /// | |
1074 | /// # Example | |
1075 | /// | |
1076 | /// ~~~~ | |
1077 | /// use chrono::{NaiveDate, Datelike}; | |
1078 | /// | |
1079 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal(), 251); | |
1080 | /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal(), 74); | |
1081 | /// ~~~~ | |
1082 | /// | |
1083 | /// Combined with [`NaiveDate::pred`](#method.pred), | |
1084 | /// one can determine the number of days in a particular year. | |
1085 | /// (Note that this panics when `year` is out of range.) | |
1086 | /// | |
1087 | /// ~~~~ | |
1088 | /// use chrono::{NaiveDate, Datelike}; | |
1089 | /// | |
1090 | /// fn ndays_in_year(year: i32) -> u32 { | |
1091 | /// // the first day of the next year... | |
1092 | /// let d = NaiveDate::from_ymd(year + 1, 1, 1); | |
1093 | /// | |
1094 | /// // ...is preceded by the last day of the original year | |
1095 | /// d.pred().ordinal() | |
1096 | /// } | |
1097 | /// | |
1098 | /// assert_eq!(ndays_in_year(2015), 365); | |
1099 | /// assert_eq!(ndays_in_year(2016), 366); | |
1100 | /// assert_eq!(ndays_in_year(2017), 365); | |
1101 | /// assert_eq!(ndays_in_year(2000), 366); | |
1102 | /// assert_eq!(ndays_in_year(2100), 365); | |
1103 | /// ~~~~ | |
1104 | #[inline] | |
1105 | fn ordinal(&self) -> u32 { | |
1106 | self.of().ordinal() | |
1107 | } | |
1108 | ||
1109 | /// Returns the day of year starting from 0. | |
1110 | /// | |
1111 | /// The return value ranges from 0 to 365. (The last day of year differs by years.) | |
1112 | /// | |
1113 | /// # Example | |
1114 | /// | |
1115 | /// ~~~~ | |
1116 | /// use chrono::{NaiveDate, Datelike}; | |
1117 | /// | |
1118 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal0(), 250); | |
1119 | /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal0(), 73); | |
1120 | /// ~~~~ | |
1121 | #[inline] | |
1122 | fn ordinal0(&self) -> u32 { | |
1123 | self.of().ordinal() - 1 | |
1124 | } | |
1125 | ||
1126 | /// Returns the day of week. | |
1127 | /// | |
1128 | /// # Example | |
1129 | /// | |
1130 | /// ~~~~ | |
1131 | /// use chrono::{NaiveDate, Datelike, Weekday}; | |
1132 | /// | |
1133 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).weekday(), Weekday::Tue); | |
1134 | /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).weekday(), Weekday::Fri); | |
1135 | /// ~~~~ | |
1136 | #[inline] | |
1137 | fn weekday(&self) -> Weekday { | |
1138 | self.of().weekday() | |
1139 | } | |
1140 | ||
1141 | #[inline] | |
1142 | fn iso_week(&self) -> IsoWeek { | |
1143 | isoweek::iso_week_from_yof(self.year(), self.of()) | |
1144 | } | |
1145 | ||
1146 | /// Makes a new `NaiveDate` with the year number changed. | |
1147 | /// | |
1148 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
1149 | /// | |
1150 | /// # Example | |
1151 | /// | |
1152 | /// ~~~~ | |
1153 | /// use chrono::{NaiveDate, Datelike}; | |
1154 | /// | |
1155 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(2016), | |
1156 | /// Some(NaiveDate::from_ymd(2016, 9, 8))); | |
1157 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(-308), | |
1158 | /// Some(NaiveDate::from_ymd(-308, 9, 8))); | |
1159 | /// ~~~~ | |
1160 | /// | |
1161 | /// A leap day (February 29) is a good example that this method can return `None`. | |
1162 | /// | |
1163 | /// ~~~~ | |
1164 | /// # use chrono::{NaiveDate, Datelike}; | |
1165 | /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2015).is_none()); | |
1166 | /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2020).is_some()); | |
1167 | /// ~~~~ | |
1168 | #[inline] | |
1169 | fn with_year(&self, year: i32) -> Option<NaiveDate> { | |
1170 | // we need to operate with `mdf` since we should keep the month and day number as is | |
1171 | let mdf = self.mdf(); | |
1172 | ||
1173 | // adjust the flags as needed | |
1174 | let flags = YearFlags::from_year(year); | |
1175 | let mdf = mdf.with_flags(flags); | |
1176 | ||
1177 | NaiveDate::from_mdf(year, mdf) | |
1178 | } | |
1179 | ||
1180 | /// Makes a new `NaiveDate` with the month number (starting from 1) changed. | |
1181 | /// | |
1182 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
1183 | /// | |
1184 | /// # Example | |
1185 | /// | |
1186 | /// ~~~~ | |
1187 | /// use chrono::{NaiveDate, Datelike}; | |
1188 | /// | |
1189 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(10), | |
1190 | /// Some(NaiveDate::from_ymd(2015, 10, 8))); | |
1191 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(13), None); // no month 13 | |
1192 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month(2), None); // no February 30 | |
1193 | /// ~~~~ | |
1194 | #[inline] | |
1195 | fn with_month(&self, month: u32) -> Option<NaiveDate> { | |
1196 | self.with_mdf(self.mdf().with_month(month)) | |
1197 | } | |
1198 | ||
1199 | /// Makes a new `NaiveDate` with the month number (starting from 0) changed. | |
1200 | /// | |
1201 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
1202 | /// | |
1203 | /// # Example | |
1204 | /// | |
1205 | /// ~~~~ | |
1206 | /// use chrono::{NaiveDate, Datelike}; | |
1207 | /// | |
1208 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(9), | |
1209 | /// Some(NaiveDate::from_ymd(2015, 10, 8))); | |
1210 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(12), None); // no month 13 | |
1211 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month0(1), None); // no February 30 | |
1212 | /// ~~~~ | |
1213 | #[inline] | |
1214 | fn with_month0(&self, month0: u32) -> Option<NaiveDate> { | |
1215 | self.with_mdf(self.mdf().with_month(month0 + 1)) | |
1216 | } | |
1217 | ||
1218 | /// Makes a new `NaiveDate` with the day of month (starting from 1) changed. | |
1219 | /// | |
1220 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
1221 | /// | |
1222 | /// # Example | |
1223 | /// | |
1224 | /// ~~~~ | |
1225 | /// use chrono::{NaiveDate, Datelike}; | |
1226 | /// | |
1227 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(30), | |
1228 | /// Some(NaiveDate::from_ymd(2015, 9, 30))); | |
1229 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(31), | |
1230 | /// None); // no September 31 | |
1231 | /// ~~~~ | |
1232 | #[inline] | |
1233 | fn with_day(&self, day: u32) -> Option<NaiveDate> { | |
1234 | self.with_mdf(self.mdf().with_day(day)) | |
1235 | } | |
1236 | ||
1237 | /// Makes a new `NaiveDate` with the day of month (starting from 0) changed. | |
1238 | /// | |
1239 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
1240 | /// | |
1241 | /// # Example | |
1242 | /// | |
1243 | /// ~~~~ | |
1244 | /// use chrono::{NaiveDate, Datelike}; | |
1245 | /// | |
1246 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(29), | |
1247 | /// Some(NaiveDate::from_ymd(2015, 9, 30))); | |
1248 | /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(30), | |
1249 | /// None); // no September 31 | |
1250 | /// ~~~~ | |
1251 | #[inline] | |
1252 | fn with_day0(&self, day0: u32) -> Option<NaiveDate> { | |
1253 | self.with_mdf(self.mdf().with_day(day0 + 1)) | |
1254 | } | |
1255 | ||
1256 | /// Makes a new `NaiveDate` with the day of year (starting from 1) changed. | |
1257 | /// | |
1258 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
1259 | /// | |
1260 | /// # Example | |
1261 | /// | |
1262 | /// ~~~~ | |
1263 | /// use chrono::{NaiveDate, Datelike}; | |
1264 | /// | |
1265 | /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(60), | |
1266 | /// Some(NaiveDate::from_ymd(2015, 3, 1))); | |
1267 | /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(366), | |
1268 | /// None); // 2015 had only 365 days | |
1269 | /// | |
1270 | /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(60), | |
1271 | /// Some(NaiveDate::from_ymd(2016, 2, 29))); | |
1272 | /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(366), | |
1273 | /// Some(NaiveDate::from_ymd(2016, 12, 31))); | |
1274 | /// ~~~~ | |
1275 | #[inline] | |
1276 | fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDate> { | |
1277 | self.with_of(self.of().with_ordinal(ordinal)) | |
1278 | } | |
1279 | ||
1280 | /// Makes a new `NaiveDate` with the day of year (starting from 0) changed. | |
1281 | /// | |
1282 | /// Returns `None` when the resulting `NaiveDate` would be invalid. | |
1283 | /// | |
1284 | /// # Example | |
1285 | /// | |
1286 | /// ~~~~ | |
1287 | /// use chrono::{NaiveDate, Datelike}; | |
1288 | /// | |
1289 | /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(59), | |
1290 | /// Some(NaiveDate::from_ymd(2015, 3, 1))); | |
1291 | /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(365), | |
1292 | /// None); // 2015 had only 365 days | |
1293 | /// | |
1294 | /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(59), | |
1295 | /// Some(NaiveDate::from_ymd(2016, 2, 29))); | |
1296 | /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(365), | |
1297 | /// Some(NaiveDate::from_ymd(2016, 12, 31))); | |
1298 | /// ~~~~ | |
1299 | #[inline] | |
1300 | fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDate> { | |
1301 | self.with_of(self.of().with_ordinal(ordinal0 + 1)) | |
1302 | } | |
1303 | } | |
1304 | ||
1305 | /// `NaiveDate` can be used as a key to the hash maps. | |
1306 | impl hash::Hash for NaiveDate { | |
1307 | fn hash<H: hash::Hasher>(&self, state: &mut H) { | |
1308 | // don't need to strip flags, as we can safely assume that it is correct | |
1309 | self.ymdf.hash(state); | |
1310 | } | |
1311 | } | |
1312 | ||
1313 | /// An addition of `Duration` to `NaiveDate` discards the fractional days, | |
1314 | /// rounding to the closest integral number of days towards `Duration::zero()`. | |
1315 | /// | |
1316 | /// Panics on underflow or overflow. | |
1317 | /// Use [`NaiveDate::checked_add_signed`](#method.checked_add_signed) to detect that. | |
1318 | /// | |
1319 | /// # Example | |
1320 | /// | |
1321 | /// ~~~~ | |
1322 | /// # extern crate chrono; extern crate time; fn main() { | |
1323 | /// use chrono::NaiveDate; | |
1324 | /// use time::Duration; | |
1325 | /// | |
1326 | /// let from_ymd = NaiveDate::from_ymd; | |
1327 | /// | |
1328 | /// assert_eq!(from_ymd(2014, 1, 1) + Duration::zero(), from_ymd(2014, 1, 1)); | |
1329 | /// assert_eq!(from_ymd(2014, 1, 1) + Duration::seconds(86399), from_ymd(2014, 1, 1)); | |
1330 | /// assert_eq!(from_ymd(2014, 1, 1) + Duration::seconds(-86399), from_ymd(2014, 1, 1)); | |
1331 | /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(1), from_ymd(2014, 1, 2)); | |
1332 | /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(-1), from_ymd(2013, 12, 31)); | |
1333 | /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(364), from_ymd(2014, 12, 31)); | |
1334 | /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*4 + 1), from_ymd(2018, 1, 1)); | |
1335 | /// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*400 + 97), from_ymd(2414, 1, 1)); | |
1336 | /// # } | |
1337 | /// ~~~~ | |
1338 | impl Add<OldDuration> for NaiveDate { | |
1339 | type Output = NaiveDate; | |
1340 | ||
1341 | #[inline] | |
1342 | fn add(self, rhs: OldDuration) -> NaiveDate { | |
1343 | self.checked_add_signed(rhs).expect("`NaiveDate + Duration` overflowed") | |
1344 | } | |
1345 | } | |
1346 | ||
1347 | impl AddAssign<OldDuration> for NaiveDate { | |
1348 | #[inline] | |
1349 | fn add_assign(&mut self, rhs: OldDuration) { | |
1350 | *self = self.add(rhs); | |
1351 | } | |
1352 | } | |
1353 | ||
1354 | /// A subtraction of `Duration` from `NaiveDate` discards the fractional days, | |
1355 | /// rounding to the closest integral number of days towards `Duration::zero()`. | |
1356 | /// It is same to the addition with a negated `Duration`. | |
1357 | /// | |
1358 | /// Panics on underflow or overflow. | |
1359 | /// Use [`NaiveDate::checked_sub_signed`](#method.checked_sub_signed) to detect that. | |
1360 | /// | |
1361 | /// # Example | |
1362 | /// | |
1363 | /// ~~~~ | |
1364 | /// # extern crate chrono; extern crate time; fn main() { | |
1365 | /// use chrono::NaiveDate; | |
1366 | /// use time::Duration; | |
1367 | /// | |
1368 | /// let from_ymd = NaiveDate::from_ymd; | |
1369 | /// | |
1370 | /// assert_eq!(from_ymd(2014, 1, 1) - Duration::zero(), from_ymd(2014, 1, 1)); | |
1371 | /// assert_eq!(from_ymd(2014, 1, 1) - Duration::seconds(86399), from_ymd(2014, 1, 1)); | |
1372 | /// assert_eq!(from_ymd(2014, 1, 1) - Duration::seconds(-86399), from_ymd(2014, 1, 1)); | |
1373 | /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(1), from_ymd(2013, 12, 31)); | |
1374 | /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(-1), from_ymd(2014, 1, 2)); | |
1375 | /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(364), from_ymd(2013, 1, 2)); | |
1376 | /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*4 + 1), from_ymd(2010, 1, 1)); | |
1377 | /// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*400 + 97), from_ymd(1614, 1, 1)); | |
1378 | /// # } | |
1379 | /// ~~~~ | |
1380 | impl Sub<OldDuration> for NaiveDate { | |
1381 | type Output = NaiveDate; | |
1382 | ||
1383 | #[inline] | |
1384 | fn sub(self, rhs: OldDuration) -> NaiveDate { | |
1385 | self.checked_sub_signed(rhs).expect("`NaiveDate - Duration` overflowed") | |
1386 | } | |
1387 | } | |
1388 | ||
1389 | impl SubAssign<OldDuration> for NaiveDate { | |
1390 | #[inline] | |
1391 | fn sub_assign(&mut self, rhs: OldDuration) { | |
1392 | *self = self.sub(rhs); | |
1393 | } | |
1394 | } | |
1395 | ||
1396 | /// The `Debug` output of the naive date `d` is same to | |
1397 | /// [`d.format("%Y-%m-%d")`](../format/strftime/index.html). | |
1398 | /// | |
1399 | /// The string printed can be readily parsed via the `parse` method on `str`. | |
1400 | /// | |
1401 | /// # Example | |
1402 | /// | |
1403 | /// ~~~~ | |
1404 | /// use chrono::NaiveDate; | |
1405 | /// | |
1406 | /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05"); | |
1407 | /// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01"); | |
1408 | /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31"); | |
1409 | /// ~~~~ | |
1410 | /// | |
1411 | /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. | |
1412 | /// | |
1413 | /// ~~~~ | |
1414 | /// # use chrono::NaiveDate; | |
1415 | /// assert_eq!(format!("{:?}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01"); | |
1416 | /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31"); | |
1417 | /// ~~~~ | |
1418 | impl fmt::Debug for NaiveDate { | |
1419 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
1420 | let year = self.year(); | |
1421 | let mdf = self.mdf(); | |
1422 | if 0 <= year && year <= 9999 { | |
1423 | write!(f, "{:04}-{:02}-{:02}", year, mdf.month(), mdf.day()) | |
1424 | } else { | |
1425 | // ISO 8601 requires the explicit sign for out-of-range years | |
1426 | write!(f, "{:+05}-{:02}-{:02}", year, mdf.month(), mdf.day()) | |
1427 | } | |
1428 | } | |
1429 | } | |
1430 | ||
1431 | /// The `Display` output of the naive date `d` is same to | |
1432 | /// [`d.format("%Y-%m-%d")`](../format/strftime/index.html). | |
1433 | /// | |
1434 | /// The string printed can be readily parsed via the `parse` method on `str`. | |
1435 | /// | |
1436 | /// # Example | |
1437 | /// | |
1438 | /// ~~~~ | |
1439 | /// use chrono::NaiveDate; | |
1440 | /// | |
1441 | /// assert_eq!(format!("{}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05"); | |
1442 | /// assert_eq!(format!("{}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01"); | |
1443 | /// assert_eq!(format!("{}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31"); | |
1444 | /// ~~~~ | |
1445 | /// | |
1446 | /// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. | |
1447 | /// | |
1448 | /// ~~~~ | |
1449 | /// # use chrono::NaiveDate; | |
1450 | /// assert_eq!(format!("{}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01"); | |
1451 | /// assert_eq!(format!("{}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31"); | |
1452 | /// ~~~~ | |
1453 | impl fmt::Display for NaiveDate { | |
1454 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) } | |
1455 | } | |
1456 | ||
1457 | /// Parsing a `str` into a `NaiveDate` uses the same format, | |
1458 | /// [`%Y-%m-%d`](../format/strftime/index.html), as in `Debug` and `Display`. | |
1459 | /// | |
1460 | /// # Example | |
1461 | /// | |
1462 | /// ~~~~ | |
1463 | /// use chrono::NaiveDate; | |
1464 | /// | |
1465 | /// let d = NaiveDate::from_ymd(2015, 9, 18); | |
1466 | /// assert_eq!("2015-09-18".parse::<NaiveDate>(), Ok(d)); | |
1467 | /// | |
1468 | /// let d = NaiveDate::from_ymd(12345, 6, 7); | |
1469 | /// assert_eq!("+12345-6-7".parse::<NaiveDate>(), Ok(d)); | |
1470 | /// | |
1471 | /// assert!("foo".parse::<NaiveDate>().is_err()); | |
1472 | /// ~~~~ | |
1473 | impl str::FromStr for NaiveDate { | |
1474 | type Err = ParseError; | |
1475 | ||
1476 | fn from_str(s: &str) -> ParseResult<NaiveDate> { | |
1477 | const ITEMS: &'static [Item<'static>] = &[ | |
1478 | Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero), | |
1479 | Item::Space(""), Item::Literal("-"), | |
1480 | Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero), | |
1481 | Item::Space(""), Item::Literal("-"), | |
1482 | Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero), | |
1483 | Item::Space(""), | |
1484 | ]; | |
1485 | ||
1486 | let mut parsed = Parsed::new(); | |
1487 | try!(parse(&mut parsed, s, ITEMS.iter().cloned())); | |
1488 | parsed.to_naive_date() | |
1489 | } | |
1490 | } | |
1491 | ||
1492 | #[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] | |
1493 | fn test_encodable_json<F, E>(to_string: F) | |
1494 | where F: Fn(&NaiveDate) -> Result<String, E>, E: ::std::fmt::Debug | |
1495 | { | |
1496 | assert_eq!(to_string(&NaiveDate::from_ymd(2014, 7, 24)).ok(), | |
1497 | Some(r#""2014-07-24""#.into())); | |
1498 | assert_eq!(to_string(&NaiveDate::from_ymd(0, 1, 1)).ok(), | |
1499 | Some(r#""0000-01-01""#.into())); | |
1500 | assert_eq!(to_string(&NaiveDate::from_ymd(-1, 12, 31)).ok(), | |
1501 | Some(r#""-0001-12-31""#.into())); | |
1502 | assert_eq!(to_string(&MIN_DATE).ok(), | |
1503 | Some(r#""-262144-01-01""#.into())); | |
1504 | assert_eq!(to_string(&MAX_DATE).ok(), | |
1505 | Some(r#""+262143-12-31""#.into())); | |
1506 | } | |
1507 | ||
1508 | #[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] | |
1509 | fn test_decodable_json<F, E>(from_str: F) | |
1510 | where F: Fn(&str) -> Result<NaiveDate, E>, E: ::std::fmt::Debug | |
1511 | { | |
1512 | use std::{i32, i64}; | |
1513 | ||
1514 | assert_eq!(from_str(r#""2016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); | |
1515 | assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); | |
1516 | assert_eq!(from_str(r#""+002016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); | |
1517 | assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1))); | |
1518 | assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1))); | |
1519 | assert_eq!(from_str(r#""-0001-12-31""#).ok(), Some(NaiveDate::from_ymd(-1, 12, 31))); | |
1520 | assert_eq!(from_str(r#""-262144-01-01""#).ok(), Some(MIN_DATE)); | |
1521 | assert_eq!(from_str(r#""+262143-12-31""#).ok(), Some(MAX_DATE)); | |
1522 | ||
1523 | // bad formats | |
1524 | assert!(from_str(r#""""#).is_err()); | |
1525 | assert!(from_str(r#""20001231""#).is_err()); | |
1526 | assert!(from_str(r#""2000-00-00""#).is_err()); | |
1527 | assert!(from_str(r#""2000-02-30""#).is_err()); | |
1528 | assert!(from_str(r#""2001-02-29""#).is_err()); | |
1529 | assert!(from_str(r#""2002-002-28""#).is_err()); | |
1530 | assert!(from_str(r#""yyyy-mm-dd""#).is_err()); | |
1531 | assert!(from_str(r#"0"#).is_err()); | |
1532 | assert!(from_str(r#"20.01"#).is_err()); | |
1533 | assert!(from_str(&i32::MIN.to_string()).is_err()); | |
1534 | assert!(from_str(&i32::MAX.to_string()).is_err()); | |
1535 | assert!(from_str(&i64::MIN.to_string()).is_err()); | |
1536 | assert!(from_str(&i64::MAX.to_string()).is_err()); | |
1537 | assert!(from_str(r#"{}"#).is_err()); | |
1538 | // pre-0.3.0 rustc-serialize format is now invalid | |
1539 | assert!(from_str(r#"{"ymdf":20}"#).is_err()); | |
1540 | assert!(from_str(r#"null"#).is_err()); | |
1541 | } | |
1542 | ||
1543 | #[cfg(feature = "rustc-serialize")] | |
1544 | mod rustc_serialize { | |
1545 | use super::NaiveDate; | |
1546 | use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; | |
1547 | ||
1548 | impl Encodable for NaiveDate { | |
1549 | fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { | |
1550 | format!("{:?}", self).encode(s) | |
1551 | } | |
1552 | } | |
1553 | ||
1554 | impl Decodable for NaiveDate { | |
1555 | fn decode<D: Decoder>(d: &mut D) -> Result<NaiveDate, D::Error> { | |
1556 | d.read_str()?.parse().map_err(|_| d.error("invalid date")) | |
1557 | } | |
1558 | } | |
1559 | ||
1560 | #[cfg(test)] use rustc_serialize::json; | |
1561 | ||
1562 | #[test] | |
1563 | fn test_encodable() { | |
1564 | super::test_encodable_json(json::encode); | |
1565 | } | |
1566 | ||
1567 | #[test] | |
1568 | fn test_decodable() { | |
1569 | super::test_decodable_json(json::decode); | |
1570 | } | |
1571 | } | |
1572 | ||
1573 | #[cfg(feature = "serde")] | |
1574 | mod serde { | |
1575 | use std::fmt; | |
1576 | use super::NaiveDate; | |
1577 | use serdelib::{ser, de}; | |
1578 | ||
1579 | // TODO not very optimized for space (binary formats would want something better) | |
1580 | ||
1581 | impl ser::Serialize for NaiveDate { | |
1582 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |
1583 | where S: ser::Serializer | |
1584 | { | |
1585 | struct FormatWrapped<'a, D: 'a> { | |
1586 | inner: &'a D | |
1587 | } | |
1588 | ||
1589 | impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> { | |
1590 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
1591 | self.inner.fmt(f) | |
1592 | } | |
1593 | } | |
1594 | ||
1595 | serializer.collect_str(&FormatWrapped { inner: &self }) | |
1596 | } | |
1597 | } | |
1598 | ||
1599 | struct NaiveDateVisitor; | |
1600 | ||
1601 | impl<'de> de::Visitor<'de> for NaiveDateVisitor { | |
1602 | type Value = NaiveDate; | |
1603 | ||
1604 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result | |
1605 | { | |
1606 | write!(formatter, "a formatted date string") | |
1607 | } | |
1608 | ||
1609 | fn visit_str<E>(self, value: &str) -> Result<NaiveDate, E> | |
1610 | where E: de::Error | |
1611 | { | |
1612 | value.parse().map_err(|err| E::custom(format!("{}", err))) | |
1613 | } | |
1614 | } | |
1615 | ||
1616 | impl<'de> de::Deserialize<'de> for NaiveDate { | |
1617 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | |
1618 | where D: de::Deserializer<'de> | |
1619 | { | |
1620 | deserializer.deserialize_str(NaiveDateVisitor) | |
1621 | } | |
1622 | } | |
1623 | ||
1624 | #[cfg(test)] extern crate serde_json; | |
1625 | #[cfg(test)] extern crate bincode; | |
1626 | ||
1627 | #[test] | |
1628 | fn test_serde_serialize() { | |
1629 | super::test_encodable_json(self::serde_json::to_string); | |
1630 | } | |
1631 | ||
1632 | #[test] | |
1633 | fn test_serde_deserialize() { | |
1634 | super::test_decodable_json(|input| self::serde_json::from_str(&input)); | |
1635 | } | |
1636 | ||
1637 | #[test] | |
1638 | fn test_serde_bincode() { | |
1639 | // Bincode is relevant to test separately from JSON because | |
1640 | // it is not self-describing. | |
1641 | use self::bincode::{Infinite, serialize, deserialize}; | |
1642 | ||
1643 | let d = NaiveDate::from_ymd(2014, 7, 24); | |
1644 | let encoded = serialize(&d, Infinite).unwrap(); | |
1645 | let decoded: NaiveDate = deserialize(&encoded).unwrap(); | |
1646 | assert_eq!(d, decoded); | |
1647 | } | |
1648 | } | |
1649 | ||
1650 | #[cfg(test)] | |
1651 | mod tests { | |
1652 | use super::NaiveDate; | |
1653 | use super::{MIN_DATE, MIN_YEAR, MIN_DAYS_FROM_YEAR_0}; | |
1654 | use super::{MAX_DATE, MAX_YEAR, MAX_DAYS_FROM_YEAR_0}; | |
1655 | use {Datelike, Weekday}; | |
1656 | use std::{i32, u32}; | |
1657 | use oldtime::Duration; | |
1658 | ||
1659 | #[test] | |
1660 | fn test_date_from_ymd() { | |
1661 | let ymd_opt = |y,m,d| NaiveDate::from_ymd_opt(y, m, d); | |
1662 | ||
1663 | assert!(ymd_opt(2012, 0, 1).is_none()); | |
1664 | assert!(ymd_opt(2012, 1, 1).is_some()); | |
1665 | assert!(ymd_opt(2012, 2, 29).is_some()); | |
1666 | assert!(ymd_opt(2014, 2, 29).is_none()); | |
1667 | assert!(ymd_opt(2014, 3, 0).is_none()); | |
1668 | assert!(ymd_opt(2014, 3, 1).is_some()); | |
1669 | assert!(ymd_opt(2014, 3, 31).is_some()); | |
1670 | assert!(ymd_opt(2014, 3, 32).is_none()); | |
1671 | assert!(ymd_opt(2014, 12, 31).is_some()); | |
1672 | assert!(ymd_opt(2014, 13, 1).is_none()); | |
1673 | } | |
1674 | ||
1675 | #[test] | |
1676 | fn test_date_from_yo() { | |
1677 | let yo_opt = |y,o| NaiveDate::from_yo_opt(y, o); | |
1678 | let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); | |
1679 | ||
1680 | assert_eq!(yo_opt(2012, 0), None); | |
1681 | assert_eq!(yo_opt(2012, 1), Some(ymd(2012, 1, 1))); | |
1682 | assert_eq!(yo_opt(2012, 2), Some(ymd(2012, 1, 2))); | |
1683 | assert_eq!(yo_opt(2012, 32), Some(ymd(2012, 2, 1))); | |
1684 | assert_eq!(yo_opt(2012, 60), Some(ymd(2012, 2, 29))); | |
1685 | assert_eq!(yo_opt(2012, 61), Some(ymd(2012, 3, 1))); | |
1686 | assert_eq!(yo_opt(2012, 100), Some(ymd(2012, 4, 9))); | |
1687 | assert_eq!(yo_opt(2012, 200), Some(ymd(2012, 7, 18))); | |
1688 | assert_eq!(yo_opt(2012, 300), Some(ymd(2012, 10, 26))); | |
1689 | assert_eq!(yo_opt(2012, 366), Some(ymd(2012, 12, 31))); | |
1690 | assert_eq!(yo_opt(2012, 367), None); | |
1691 | ||
1692 | assert_eq!(yo_opt(2014, 0), None); | |
1693 | assert_eq!(yo_opt(2014, 1), Some(ymd(2014, 1, 1))); | |
1694 | assert_eq!(yo_opt(2014, 2), Some(ymd(2014, 1, 2))); | |
1695 | assert_eq!(yo_opt(2014, 32), Some(ymd(2014, 2, 1))); | |
1696 | assert_eq!(yo_opt(2014, 59), Some(ymd(2014, 2, 28))); | |
1697 | assert_eq!(yo_opt(2014, 60), Some(ymd(2014, 3, 1))); | |
1698 | assert_eq!(yo_opt(2014, 100), Some(ymd(2014, 4, 10))); | |
1699 | assert_eq!(yo_opt(2014, 200), Some(ymd(2014, 7, 19))); | |
1700 | assert_eq!(yo_opt(2014, 300), Some(ymd(2014, 10, 27))); | |
1701 | assert_eq!(yo_opt(2014, 365), Some(ymd(2014, 12, 31))); | |
1702 | assert_eq!(yo_opt(2014, 366), None); | |
1703 | } | |
1704 | ||
1705 | #[test] | |
1706 | fn test_date_from_isoywd() { | |
1707 | let isoywd_opt = |y,w,d| NaiveDate::from_isoywd_opt(y, w, d); | |
1708 | let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); | |
1709 | ||
1710 | assert_eq!(isoywd_opt(2004, 0, Weekday::Sun), None); | |
1711 | assert_eq!(isoywd_opt(2004, 1, Weekday::Mon), Some(ymd(2003, 12, 29))); | |
1712 | assert_eq!(isoywd_opt(2004, 1, Weekday::Sun), Some(ymd(2004, 1, 4))); | |
1713 | assert_eq!(isoywd_opt(2004, 2, Weekday::Mon), Some(ymd(2004, 1, 5))); | |
1714 | assert_eq!(isoywd_opt(2004, 2, Weekday::Sun), Some(ymd(2004, 1, 11))); | |
1715 | assert_eq!(isoywd_opt(2004, 52, Weekday::Mon), Some(ymd(2004, 12, 20))); | |
1716 | assert_eq!(isoywd_opt(2004, 52, Weekday::Sun), Some(ymd(2004, 12, 26))); | |
1717 | assert_eq!(isoywd_opt(2004, 53, Weekday::Mon), Some(ymd(2004, 12, 27))); | |
1718 | assert_eq!(isoywd_opt(2004, 53, Weekday::Sun), Some(ymd(2005, 1, 2))); | |
1719 | assert_eq!(isoywd_opt(2004, 54, Weekday::Mon), None); | |
1720 | ||
1721 | assert_eq!(isoywd_opt(2011, 0, Weekday::Sun), None); | |
1722 | assert_eq!(isoywd_opt(2011, 1, Weekday::Mon), Some(ymd(2011, 1, 3))); | |
1723 | assert_eq!(isoywd_opt(2011, 1, Weekday::Sun), Some(ymd(2011, 1, 9))); | |
1724 | assert_eq!(isoywd_opt(2011, 2, Weekday::Mon), Some(ymd(2011, 1, 10))); | |
1725 | assert_eq!(isoywd_opt(2011, 2, Weekday::Sun), Some(ymd(2011, 1, 16))); | |
1726 | ||
1727 | assert_eq!(isoywd_opt(2018, 51, Weekday::Mon), Some(ymd(2018, 12, 17))); | |
1728 | assert_eq!(isoywd_opt(2018, 51, Weekday::Sun), Some(ymd(2018, 12, 23))); | |
1729 | assert_eq!(isoywd_opt(2018, 52, Weekday::Mon), Some(ymd(2018, 12, 24))); | |
1730 | assert_eq!(isoywd_opt(2018, 52, Weekday::Sun), Some(ymd(2018, 12, 30))); | |
1731 | assert_eq!(isoywd_opt(2018, 53, Weekday::Mon), None); | |
1732 | } | |
1733 | ||
1734 | #[test] | |
1735 | fn test_date_from_isoywd_and_iso_week() { | |
1736 | for year in 2000..2401 { | |
1737 | for week in 1..54 { | |
1738 | for &weekday in [Weekday::Mon, Weekday::Tue, Weekday::Wed, Weekday::Thu, | |
1739 | Weekday::Fri, Weekday::Sat, Weekday::Sun].iter() { | |
1740 | let d = NaiveDate::from_isoywd_opt(year, week, weekday); | |
1741 | if d.is_some() { | |
1742 | let d = d.unwrap(); | |
1743 | assert_eq!(d.weekday(), weekday); | |
1744 | let w = d.iso_week(); | |
1745 | assert_eq!(w.year(), year); | |
1746 | assert_eq!(w.week(), week); | |
1747 | } | |
1748 | } | |
1749 | } | |
1750 | } | |
1751 | ||
1752 | for year in 2000..2401 { | |
1753 | for month in 1..13 { | |
1754 | for day in 1..32 { | |
1755 | let d = NaiveDate::from_ymd_opt(year, month, day); | |
1756 | if d.is_some() { | |
1757 | let d = d.unwrap(); | |
1758 | let w = d.iso_week(); | |
1759 | let d_ = NaiveDate::from_isoywd(w.year(), w.week(), d.weekday()); | |
1760 | assert_eq!(d, d_); | |
1761 | } | |
1762 | } | |
1763 | } | |
1764 | } | |
1765 | } | |
1766 | ||
1767 | #[test] | |
1768 | fn test_date_from_num_days_from_ce() { | |
1769 | let from_ndays_from_ce = |days| NaiveDate::from_num_days_from_ce_opt(days); | |
1770 | assert_eq!(from_ndays_from_ce(1), Some(NaiveDate::from_ymd(1, 1, 1))); | |
1771 | assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd(1, 1, 2))); | |
1772 | assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd(1, 1, 31))); | |
1773 | assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd(1, 2, 1))); | |
1774 | assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd(1, 2, 28))); | |
1775 | assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd(1, 3, 1))); | |
1776 | assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd(1, 12, 31))); | |
1777 | assert_eq!(from_ndays_from_ce(365*1 + 1), Some(NaiveDate::from_ymd(2, 1, 1))); | |
1778 | assert_eq!(from_ndays_from_ce(365*2 + 1), Some(NaiveDate::from_ymd(3, 1, 1))); | |
1779 | assert_eq!(from_ndays_from_ce(365*3 + 1), Some(NaiveDate::from_ymd(4, 1, 1))); | |
1780 | assert_eq!(from_ndays_from_ce(365*4 + 2), Some(NaiveDate::from_ymd(5, 1, 1))); | |
1781 | assert_eq!(from_ndays_from_ce(146097 + 1), Some(NaiveDate::from_ymd(401, 1, 1))); | |
1782 | assert_eq!(from_ndays_from_ce(146097*5 + 1), Some(NaiveDate::from_ymd(2001, 1, 1))); | |
1783 | assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd(1970, 1, 1))); | |
1784 | assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd(0, 12, 31))); // 1 BCE | |
1785 | assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd(0, 1, 1))); | |
1786 | assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd(-1, 12, 31))); // 2 BCE | |
1787 | ||
1788 | for days in (-9999..10001).map(|x| x * 100) { | |
1789 | assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Some(days)); | |
1790 | } | |
1791 | ||
1792 | assert_eq!(from_ndays_from_ce(MIN_DATE.num_days_from_ce()), Some(MIN_DATE)); | |
1793 | assert_eq!(from_ndays_from_ce(MIN_DATE.num_days_from_ce() - 1), None); | |
1794 | assert_eq!(from_ndays_from_ce(MAX_DATE.num_days_from_ce()), Some(MAX_DATE)); | |
1795 | assert_eq!(from_ndays_from_ce(MAX_DATE.num_days_from_ce() + 1), None); | |
1796 | } | |
1797 | ||
1798 | #[test] | |
1799 | fn test_date_fields() { | |
1800 | fn check(year: i32, month: u32, day: u32, ordinal: u32) { | |
1801 | let d1 = NaiveDate::from_ymd(year, month, day); | |
1802 | assert_eq!(d1.year(), year); | |
1803 | assert_eq!(d1.month(), month); | |
1804 | assert_eq!(d1.day(), day); | |
1805 | assert_eq!(d1.ordinal(), ordinal); | |
1806 | ||
1807 | let d2 = NaiveDate::from_yo(year, ordinal); | |
1808 | assert_eq!(d2.year(), year); | |
1809 | assert_eq!(d2.month(), month); | |
1810 | assert_eq!(d2.day(), day); | |
1811 | assert_eq!(d2.ordinal(), ordinal); | |
1812 | ||
1813 | assert_eq!(d1, d2); | |
1814 | } | |
1815 | ||
1816 | check(2012, 1, 1, 1); | |
1817 | check(2012, 1, 2, 2); | |
1818 | check(2012, 2, 1, 32); | |
1819 | check(2012, 2, 29, 60); | |
1820 | check(2012, 3, 1, 61); | |
1821 | check(2012, 4, 9, 100); | |
1822 | check(2012, 7, 18, 200); | |
1823 | check(2012, 10, 26, 300); | |
1824 | check(2012, 12, 31, 366); | |
1825 | ||
1826 | check(2014, 1, 1, 1); | |
1827 | check(2014, 1, 2, 2); | |
1828 | check(2014, 2, 1, 32); | |
1829 | check(2014, 2, 28, 59); | |
1830 | check(2014, 3, 1, 60); | |
1831 | check(2014, 4, 10, 100); | |
1832 | check(2014, 7, 19, 200); | |
1833 | check(2014, 10, 27, 300); | |
1834 | check(2014, 12, 31, 365); | |
1835 | } | |
1836 | ||
1837 | #[test] | |
1838 | fn test_date_weekday() { | |
1839 | assert_eq!(NaiveDate::from_ymd(1582, 10, 15).weekday(), Weekday::Fri); | |
1840 | // May 20, 1875 = ISO 8601 reference date | |
1841 | assert_eq!(NaiveDate::from_ymd(1875, 5, 20).weekday(), Weekday::Thu); | |
1842 | assert_eq!(NaiveDate::from_ymd(2000, 1, 1).weekday(), Weekday::Sat); | |
1843 | } | |
1844 | ||
1845 | #[test] | |
1846 | fn test_date_with_fields() { | |
1847 | let d = NaiveDate::from_ymd(2000, 2, 29); | |
1848 | assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd(-400, 2, 29))); | |
1849 | assert_eq!(d.with_year(-100), None); | |
1850 | assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd(1600, 2, 29))); | |
1851 | assert_eq!(d.with_year(1900), None); | |
1852 | assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd(2000, 2, 29))); | |
1853 | assert_eq!(d.with_year(2001), None); | |
1854 | assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd(2004, 2, 29))); | |
1855 | assert_eq!(d.with_year(i32::MAX), None); | |
1856 | ||
1857 | let d = NaiveDate::from_ymd(2000, 4, 30); | |
1858 | assert_eq!(d.with_month(0), None); | |
1859 | assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd(2000, 1, 30))); | |
1860 | assert_eq!(d.with_month(2), None); | |
1861 | assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd(2000, 3, 30))); | |
1862 | assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd(2000, 4, 30))); | |
1863 | assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd(2000, 12, 30))); | |
1864 | assert_eq!(d.with_month(13), None); | |
1865 | assert_eq!(d.with_month(u32::MAX), None); | |
1866 | ||
1867 | let d = NaiveDate::from_ymd(2000, 2, 8); | |
1868 | assert_eq!(d.with_day(0), None); | |
1869 | assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd(2000, 2, 1))); | |
1870 | assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd(2000, 2, 29))); | |
1871 | assert_eq!(d.with_day(30), None); | |
1872 | assert_eq!(d.with_day(u32::MAX), None); | |
1873 | ||
1874 | let d = NaiveDate::from_ymd(2000, 5, 5); | |
1875 | assert_eq!(d.with_ordinal(0), None); | |
1876 | assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd(2000, 1, 1))); | |
1877 | assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd(2000, 2, 29))); | |
1878 | assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd(2000, 3, 1))); | |
1879 | assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd(2000, 12, 31))); | |
1880 | assert_eq!(d.with_ordinal(367), None); | |
1881 | assert_eq!(d.with_ordinal(u32::MAX), None); | |
1882 | } | |
1883 | ||
1884 | #[test] | |
1885 | fn test_date_num_days_from_ce() { | |
1886 | assert_eq!(NaiveDate::from_ymd(1, 1, 1).num_days_from_ce(), 1); | |
1887 | ||
1888 | for year in -9999..10001 { | |
1889 | assert_eq!(NaiveDate::from_ymd(year, 1, 1).num_days_from_ce(), | |
1890 | NaiveDate::from_ymd(year - 1, 12, 31).num_days_from_ce() + 1); | |
1891 | } | |
1892 | } | |
1893 | ||
1894 | #[test] | |
1895 | fn test_date_succ() { | |
1896 | let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); | |
1897 | assert_eq!(ymd(2014, 5, 6).succ_opt(), Some(ymd(2014, 5, 7))); | |
1898 | assert_eq!(ymd(2014, 5, 31).succ_opt(), Some(ymd(2014, 6, 1))); | |
1899 | assert_eq!(ymd(2014, 12, 31).succ_opt(), Some(ymd(2015, 1, 1))); | |
1900 | assert_eq!(ymd(2016, 2, 28).succ_opt(), Some(ymd(2016, 2, 29))); | |
1901 | assert_eq!(ymd(MAX_DATE.year(), 12, 31).succ_opt(), None); | |
1902 | } | |
1903 | ||
1904 | #[test] | |
1905 | fn test_date_pred() { | |
1906 | let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); | |
1907 | assert_eq!(ymd(2016, 3, 1).pred_opt(), Some(ymd(2016, 2, 29))); | |
1908 | assert_eq!(ymd(2015, 1, 1).pred_opt(), Some(ymd(2014, 12, 31))); | |
1909 | assert_eq!(ymd(2014, 6, 1).pred_opt(), Some(ymd(2014, 5, 31))); | |
1910 | assert_eq!(ymd(2014, 5, 7).pred_opt(), Some(ymd(2014, 5, 6))); | |
1911 | assert_eq!(ymd(MIN_DATE.year(), 1, 1).pred_opt(), None); | |
1912 | } | |
1913 | ||
1914 | #[test] | |
1915 | fn test_date_add() { | |
1916 | fn check((y1,m1,d1): (i32, u32, u32), rhs: Duration, ymd: Option<(i32, u32, u32)>) { | |
1917 | let lhs = NaiveDate::from_ymd(y1, m1, d1); | |
1918 | let sum = ymd.map(|(y,m,d)| NaiveDate::from_ymd(y, m, d)); | |
1919 | assert_eq!(lhs.checked_add_signed(rhs), sum); | |
1920 | assert_eq!(lhs.checked_sub_signed(-rhs), sum); | |
1921 | } | |
1922 | ||
1923 | check((2014, 1, 1), Duration::zero(), Some((2014, 1, 1))); | |
1924 | check((2014, 1, 1), Duration::seconds(86399), Some((2014, 1, 1))); | |
1925 | // always round towards zero | |
1926 | check((2014, 1, 1), Duration::seconds(-86399), Some((2014, 1, 1))); | |
1927 | check((2014, 1, 1), Duration::days(1), Some((2014, 1, 2))); | |
1928 | check((2014, 1, 1), Duration::days(-1), Some((2013, 12, 31))); | |
1929 | check((2014, 1, 1), Duration::days(364), Some((2014, 12, 31))); | |
1930 | check((2014, 1, 1), Duration::days(365*4 + 1), Some((2018, 1, 1))); | |
1931 | check((2014, 1, 1), Duration::days(365*400 + 97), Some((2414, 1, 1))); | |
1932 | ||
1933 | check((-7, 1, 1), Duration::days(365*12 + 3), Some((5, 1, 1))); | |
1934 | ||
1935 | // overflow check | |
1936 | check((0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64), Some((MAX_YEAR, 12, 31))); | |
1937 | check((0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1), None); | |
1938 | check((0, 1, 1), Duration::max_value(), None); | |
1939 | check((0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64), Some((MIN_YEAR, 1, 1))); | |
1940 | check((0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1), None); | |
1941 | check((0, 1, 1), Duration::min_value(), None); | |
1942 | } | |
1943 | ||
1944 | #[test] | |
1945 | fn test_date_sub() { | |
1946 | fn check((y1,m1,d1): (i32, u32, u32), (y2,m2,d2): (i32, u32, u32), diff: Duration) { | |
1947 | let lhs = NaiveDate::from_ymd(y1, m1, d1); | |
1948 | let rhs = NaiveDate::from_ymd(y2, m2, d2); | |
1949 | assert_eq!(lhs.signed_duration_since(rhs), diff); | |
1950 | assert_eq!(rhs.signed_duration_since(lhs), -diff); | |
1951 | } | |
1952 | ||
1953 | check((2014, 1, 1), (2014, 1, 1), Duration::zero()); | |
1954 | check((2014, 1, 2), (2014, 1, 1), Duration::days(1)); | |
1955 | check((2014, 12, 31), (2014, 1, 1), Duration::days(364)); | |
1956 | check((2015, 1, 3), (2014, 1, 1), Duration::days(365 + 2)); | |
1957 | check((2018, 1, 1), (2014, 1, 1), Duration::days(365*4 + 1)); | |
1958 | check((2414, 1, 1), (2014, 1, 1), Duration::days(365*400 + 97)); | |
1959 | ||
1960 | check((MAX_YEAR, 12, 31), (0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64)); | |
1961 | check((MIN_YEAR, 1, 1), (0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64)); | |
1962 | } | |
1963 | ||
1964 | #[test] | |
1965 | fn test_date_addassignment() { | |
1966 | let ymd = NaiveDate::from_ymd; | |
1967 | let mut date = ymd(2016, 10, 1); | |
1968 | date += Duration::days(10); | |
1969 | assert_eq!(date, ymd(2016, 10, 11)); | |
1970 | date += Duration::days(30); | |
1971 | assert_eq!(date, ymd(2016, 11, 10)); | |
1972 | } | |
1973 | ||
1974 | #[test] | |
1975 | fn test_date_subassignment() { | |
1976 | let ymd = NaiveDate::from_ymd; | |
1977 | let mut date = ymd(2016, 10, 11); | |
1978 | date -= Duration::days(10); | |
1979 | assert_eq!(date, ymd(2016, 10, 1)); | |
1980 | date -= Duration::days(2); | |
1981 | assert_eq!(date, ymd(2016, 9, 29)); | |
1982 | } | |
1983 | ||
1984 | #[test] | |
1985 | fn test_date_fmt() { | |
1986 | assert_eq!(format!("{:?}", NaiveDate::from_ymd(2012, 3, 4)), "2012-03-04"); | |
1987 | assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 3, 4)), "0000-03-04"); | |
1988 | assert_eq!(format!("{:?}", NaiveDate::from_ymd(-307, 3, 4)), "-0307-03-04"); | |
1989 | assert_eq!(format!("{:?}", NaiveDate::from_ymd(12345, 3, 4)), "+12345-03-04"); | |
1990 | ||
1991 | assert_eq!(NaiveDate::from_ymd(2012, 3, 4).to_string(), "2012-03-04"); | |
1992 | assert_eq!(NaiveDate::from_ymd(0, 3, 4).to_string(), "0000-03-04"); | |
1993 | assert_eq!(NaiveDate::from_ymd(-307, 3, 4).to_string(), "-0307-03-04"); | |
1994 | assert_eq!(NaiveDate::from_ymd(12345, 3, 4).to_string(), "+12345-03-04"); | |
1995 | ||
1996 | // the format specifier should have no effect on `NaiveTime` | |
1997 | assert_eq!(format!("{:+30?}", NaiveDate::from_ymd(1234, 5, 6)), "1234-05-06"); | |
1998 | assert_eq!(format!("{:30?}", NaiveDate::from_ymd(12345, 6, 7)), "+12345-06-07"); | |
1999 | } | |
2000 | ||
2001 | #[test] | |
2002 | fn test_date_from_str() { | |
2003 | // valid cases | |
2004 | let valid = [ | |
2005 | "-0000000123456-1-2", | |
2006 | " -123456 - 1 - 2 ", | |
2007 | "-12345-1-2", | |
2008 | "-1234-12-31", | |
2009 | "-7-6-5", | |
2010 | "350-2-28", | |
2011 | "360-02-29", | |
2012 | "0360-02-29", | |
2013 | "2015-2 -18", | |
2014 | "+70-2-18", | |
2015 | "+70000-2-18", | |
2016 | "+00007-2-18", | |
2017 | ]; | |
2018 | for &s in &valid { | |
2019 | let d = match s.parse::<NaiveDate>() { | |
2020 | Ok(d) => d, | |
2021 | Err(e) => panic!("parsing `{}` has failed: {}", s, e) | |
2022 | }; | |
2023 | let s_ = format!("{:?}", d); | |
2024 | // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same | |
2025 | let d_ = match s_.parse::<NaiveDate>() { | |
2026 | Ok(d) => d, | |
2027 | Err(e) => panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", | |
2028 | s, d, e) | |
2029 | }; | |
2030 | assert!(d == d_, "`{}` is parsed into `{:?}`, but reparsed result \ | |
2031 | `{:?}` does not match", s, d, d_); | |
2032 | } | |
2033 | ||
2034 | // some invalid cases | |
2035 | // since `ParseErrorKind` is private, all we can do is to check if there was an error | |
2036 | assert!("".parse::<NaiveDate>().is_err()); | |
2037 | assert!("x".parse::<NaiveDate>().is_err()); | |
2038 | assert!("2014".parse::<NaiveDate>().is_err()); | |
2039 | assert!("2014-01".parse::<NaiveDate>().is_err()); | |
2040 | assert!("2014-01-00".parse::<NaiveDate>().is_err()); | |
2041 | assert!("2014-13-57".parse::<NaiveDate>().is_err()); | |
2042 | assert!("9999999-9-9".parse::<NaiveDate>().is_err()); // out-of-bounds | |
2043 | } | |
2044 | ||
2045 | #[test] | |
2046 | fn test_date_parse_from_str() { | |
2047 | let ymd = |y,m,d| NaiveDate::from_ymd(y,m,d); | |
2048 | assert_eq!(NaiveDate::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), | |
2049 | Ok(ymd(2014, 5, 7))); // ignore time and offset | |
2050 | assert_eq!(NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"), | |
2051 | Ok(ymd(2015, 2, 2))); | |
2052 | assert_eq!(NaiveDate::parse_from_str("Fri, 09 Aug 13", "%a, %d %b %y"), | |
2053 | Ok(ymd(2013, 8, 9))); | |
2054 | assert!(NaiveDate::parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err()); | |
2055 | assert!(NaiveDate::parse_from_str("2014-57", "%Y-%m-%d").is_err()); | |
2056 | assert!(NaiveDate::parse_from_str("2014", "%Y").is_err()); // insufficient | |
2057 | } | |
2058 | ||
2059 | #[test] | |
2060 | fn test_date_format() { | |
2061 | let d = NaiveDate::from_ymd(2012, 3, 4); | |
2062 | assert_eq!(d.format("%Y,%C,%y,%G,%g").to_string(), "2012,20,12,2012,12"); | |
2063 | assert_eq!(d.format("%m,%b,%h,%B").to_string(), "03,Mar,Mar,March"); | |
2064 | assert_eq!(d.format("%d,%e").to_string(), "04, 4"); | |
2065 | assert_eq!(d.format("%U,%W,%V").to_string(), "10,09,09"); | |
2066 | assert_eq!(d.format("%a,%A,%w,%u").to_string(), "Sun,Sunday,0,7"); | |
2067 | assert_eq!(d.format("%j").to_string(), "064"); // since 2012 is a leap year | |
2068 | assert_eq!(d.format("%D,%x").to_string(), "03/04/12,03/04/12"); | |
2069 | assert_eq!(d.format("%F").to_string(), "2012-03-04"); | |
2070 | assert_eq!(d.format("%v").to_string(), " 4-Mar-2012"); | |
2071 | assert_eq!(d.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); | |
2072 | ||
2073 | // non-four-digit years | |
2074 | assert_eq!(NaiveDate::from_ymd(12345, 1, 1).format("%Y").to_string(), "+12345"); | |
2075 | assert_eq!(NaiveDate::from_ymd(1234, 1, 1).format("%Y").to_string(), "1234"); | |
2076 | assert_eq!(NaiveDate::from_ymd(123, 1, 1).format("%Y").to_string(), "0123"); | |
2077 | assert_eq!(NaiveDate::from_ymd(12, 1, 1).format("%Y").to_string(), "0012"); | |
2078 | assert_eq!(NaiveDate::from_ymd(1, 1, 1).format("%Y").to_string(), "0001"); | |
2079 | assert_eq!(NaiveDate::from_ymd(0, 1, 1).format("%Y").to_string(), "0000"); | |
2080 | assert_eq!(NaiveDate::from_ymd(-1, 1, 1).format("%Y").to_string(), "-0001"); | |
2081 | assert_eq!(NaiveDate::from_ymd(-12, 1, 1).format("%Y").to_string(), "-0012"); | |
2082 | assert_eq!(NaiveDate::from_ymd(-123, 1, 1).format("%Y").to_string(), "-0123"); | |
2083 | assert_eq!(NaiveDate::from_ymd(-1234, 1, 1).format("%Y").to_string(), "-1234"); | |
2084 | assert_eq!(NaiveDate::from_ymd(-12345, 1, 1).format("%Y").to_string(), "-12345"); | |
2085 | ||
2086 | // corner cases | |
2087 | assert_eq!(NaiveDate::from_ymd(2007, 12, 31).format("%G,%g,%U,%W,%V").to_string(), | |
2088 | "2008,08,53,53,01"); | |
2089 | assert_eq!(NaiveDate::from_ymd(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(), | |
2090 | "2009,09,01,00,53"); | |
2091 | } | |
2092 | } | |
2093 |