datetime/cal/
datetime.rs

1//! Dates, times, datetimes, months, and weekdays.
2
3use std::cmp::{Ordering, PartialOrd};
4use std::error::Error as ErrorTrait;
5use std::fmt;
6use std::ops::{Add, Sub};
7use std::ops::Deref;
8use std::ops::{Range, RangeFrom, RangeTo, RangeFull};
9use std::slice::Iter as SliceIter;
10
11use cal::{DatePiece, TimePiece};
12use cal::fmt::ISO;
13use duration::Duration;
14use instant::Instant;
15use system::sys_time;
16use util::RangeExt;
17
18use self::Month::*;
19use self::Weekday::*;
20
21
22/// A single year.
23///
24/// This is just a wrapper around `i64` that performs year-related tests.
25#[derive(PartialEq, Debug, Copy, Clone)]
26pub struct Year(pub i64);
27
28impl Year {
29
30    /// Returns whether this year is a leap year.
31    ///
32    /// ### Examples
33    ///
34    /// ```
35    /// use datetime::Year;
36    ///
37    /// assert_eq!(Year(2000).is_leap_year(), true);
38    /// assert_eq!(Year(1900).is_leap_year(), false);
39    /// ```
40    pub fn is_leap_year(self) -> bool {
41        self.leap_year_calculations().1
42    }
43
44    /// Returns an iterator over a continuous span of months in this year,
45    /// returning year-month pairs.
46    ///
47    /// This method takes one argument that can be of four different types,
48    /// depending on the months you wish to iterate over:
49    ///
50    /// - The `RangeFull` type (such as `..`), which iterates over every
51    ///   month;
52    /// - The `RangeFrom` type (such as `April ..`), which iterates over
53    ///   the months starting from the month given;
54    /// - The `RangeTo` type (such as `.. June`), which iterates over the
55    ///   months stopping at *but not including* the month given;
56    /// - The `Range` type (such as `April .. June`), which iterates over
57    ///   the months starting from the left one and stopping at *but not
58    ///   including* the right one.
59    ///
60    /// ### Examples
61    ///
62    /// ```
63    /// use datetime::Year;
64    /// use datetime::Month::{April, June};
65    ///
66    /// let year = Year(1999);
67    /// assert_eq!(year.months(..).count(), 12);
68    /// assert_eq!(year.months(April ..).count(), 9);
69    /// assert_eq!(year.months(April .. June).count(), 2);
70    /// assert_eq!(year.months(.. June).count(), 5);
71    /// ```
72    pub fn months<S: MonthSpan>(self, span: S) -> YearMonths {
73        YearMonths {
74            year: self,
75            iter: span.get_slice().iter(),
76        }
77    }
78
79    /// Returns a year-month, pairing this year with the given month.
80    ///
81    /// ### Examples
82    ///
83    /// ```
84    /// use datetime::{Year, Month};
85    ///
86    /// let expiry_date = Year(2017).month(Month::February);
87    /// assert_eq!(*expiry_date.year, 2017);
88    /// assert_eq!(expiry_date.month, Month::February);
89    /// ```
90    pub fn month(self, month: Month) -> YearMonth {
91        YearMonth {
92            year: self,
93            month,
94        }
95    }
96
97    /// Performs two related calculations for leap years, returning the
98    /// results as a two-part tuple:
99    ///
100    /// 1. The number of leap years that have elapsed prior to this year;
101    /// 2. Whether this year is a leap year or not.
102    fn leap_year_calculations(self) -> (i64, bool) {
103        let year = self.0 - 2000;
104
105        // This calculation is the reverse of LocalDate::from_days_since_epoch.
106        let (num_400y_cycles, mut remainder) = split_cycles(year, 400);
107
108        // Standard leap-year calculations, performed on the remainder
109        let currently_leap_year = remainder == 0 || (remainder % 100 != 0 && remainder % 4 == 0);
110
111        let num_100y_cycles = remainder / 100;
112        remainder -= num_100y_cycles * 100;
113
114        let leap_years_elapsed = remainder / 4
115            + 97 * num_400y_cycles  // There are 97 leap years in 400 years
116            + 24 * num_100y_cycles  // There are 24 leap years in 100 years
117            - if currently_leap_year { 1 } else { 0 };
118
119        (leap_years_elapsed, currently_leap_year)
120    }
121}
122
123impl Deref for Year {
124    type Target = i64;
125
126    fn deref(&self) -> &Self::Target {
127        &self.0
128    }
129}
130
131/// A span of months, which gets used to construct a `YearMonths` iterator.
132///
133/// See the `months` method of `Year` for more information.
134pub trait MonthSpan {
135
136    /// Returns a static slice of `Month` values contained by this span.
137    fn get_slice(&self) -> &'static [Month];
138}
139
140static MONTHS: &[Month] = &[
141    January,  February,  March,
142    April,    May,       June,
143    July,     August,    September,
144    October,  November,  December,
145];
146
147impl MonthSpan for RangeFull {
148    fn get_slice(&self) -> &'static [Month] {
149        MONTHS
150    }
151}
152
153impl MonthSpan for RangeFrom<Month> {
154    fn get_slice(&self) -> &'static [Month] {
155        &MONTHS[self.start.months_from_january() ..]
156    }
157}
158
159impl MonthSpan for RangeTo<Month> {
160    fn get_slice(&self) -> &'static [Month] {
161        &MONTHS[.. self.end.months_from_january()]
162    }
163}
164
165impl MonthSpan for Range<Month> {
166    fn get_slice(&self) -> &'static [Month] {
167        &MONTHS[self.start.months_from_january() .. self.end.months_from_january()]
168    }
169}
170
171
172/// An iterator over a continuous span of months in a year.
173///
174/// Use the `months` method on `Year` to create instances of this iterator.
175pub struct YearMonths {
176    year: Year,
177    iter: SliceIter<'static, Month>,
178}
179
180impl Iterator for YearMonths {
181    type Item = YearMonth;
182
183    fn next(&mut self) -> Option<YearMonth> {
184        self.iter.next().map(|m| YearMonth {
185            year: self.year,
186            month: *m,
187        })
188    }
189}
190
191impl DoubleEndedIterator for YearMonths {
192    fn next_back(&mut self) -> Option<Self::Item> {
193        self.iter.next_back().map(|m| YearMonth {
194            year: self.year,
195            month: *m,
196        })
197    }
198}
199
200impl fmt::Debug for YearMonths {
201    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
202        write!(f, "YearMonths({}, {:?})", self.year.0, self.iter.as_slice())
203    }
204}
205
206/// A month-year pair.
207#[derive(PartialEq, Debug, Copy, Clone)]
208pub struct YearMonth {
209    pub year: Year,
210    pub month: Month,
211}
212
213impl YearMonth {
214
215    /// Returns the number of days in this month. This can be definitely
216    /// known, as the paired year determines whether it’s a leap year, so
217    /// there’s no chance of being caught out by February.
218    ///
219    /// ### Examples
220    ///
221    /// ```
222    /// use datetime::Year;
223    /// use datetime::Month::February;
224    ///
225    /// assert_eq!(Year(2000).month(February).day_count(), 29);
226    /// assert_eq!(Year(1900).month(February).day_count(), 28);
227    /// ```
228    pub fn day_count(&self) -> i8 {
229        self.month.days_in_month(self.year.is_leap_year())
230    }
231
232    /// Returns an iterator over a continuous span of days in this month,
233    /// returning `LocalDate` values.
234    ///
235    /// ### Examples
236    ///
237    /// ```
238    /// use datetime::Year;
239    /// use datetime::Month::September;
240    ///
241    /// let ym = Year(1999).month(September);
242    /// assert_eq!(ym.days(..).count(), 30);
243    /// assert_eq!(ym.days(10 ..).count(), 21);
244    /// assert_eq!(ym.days(10 .. 20).count(), 10);
245    /// assert_eq!(ym.days(.. 20).count(), 19);
246    /// ```
247    pub fn days<S: DaySpan>(&self, span: S) -> MonthDays {
248        MonthDays {
249            ym: *self,
250            range: span.get_range(self)
251        }
252    }
253
254    /// Returns a `LocalDate` based on the day of this month.
255    ///
256    /// This is just a short-cut for the `LocalDate::ymd` constructor.
257    pub fn day(&self, day: i8) -> Result<LocalDate, Error> {
258        LocalDate::ymd(self.year.0, self.month, day)
259    }
260}
261
262
263/// A span of days, which gets used to construct a `MonthDays` iterator.
264pub trait DaySpan {
265
266    /// Returns a `Range` of the day numbers specified for the given year-month pair.
267    fn get_range(&self, ym: &YearMonth) -> Range<i8>;
268}
269
270impl DaySpan for RangeFull {
271    fn get_range(&self, ym: &YearMonth) -> Range<i8> {
272        1 .. ym.day_count() + 1
273    }
274}
275
276impl DaySpan for RangeFrom<i8> {
277    fn get_range(&self, ym: &YearMonth) -> Range<i8> {
278        self.start .. ym.day_count() + 1
279    }
280}
281
282impl DaySpan for RangeTo<i8> {
283    fn get_range(&self, _ym: &YearMonth) -> Range<i8> {
284        1 .. self.end
285    }
286}
287
288impl DaySpan for Range<i8> {
289    fn get_range(&self, _ym: &YearMonth) -> Range<i8> {
290        self.clone()
291    }
292}
293
294
295/// An iterator over a continuous span of days in a month.
296///
297/// Use the `days` method on `YearMonth` to create instances of this iterator.
298#[derive(PartialEq, Debug)]
299pub struct MonthDays {
300    ym: YearMonth,
301    range: Range<i8>,
302}
303
304impl Iterator for MonthDays {
305    type Item = LocalDate;
306
307    fn next(&mut self) -> Option<Self::Item> {
308        self.range.next().and_then(|d| LocalDate::ymd(self.ym.year.0, self.ym.month, d).ok())
309    }
310}
311
312impl DoubleEndedIterator for MonthDays {
313    fn next_back(&mut self) -> Option<Self::Item> {
314        self.range.next_back().and_then(|d| LocalDate::ymd(self.ym.year.0, self.ym.month, d).ok())
315    }
316}
317
318
319/// Number of days guaranteed to be in four years.
320const DAYS_IN_4Y:   i64 = 365 *   4 +  1;
321
322/// Number of days guaranteed to be in a hundred years.
323const DAYS_IN_100Y: i64 = 365 * 100 + 24;
324
325/// Number of days guaranteed to be in four hundred years.
326const DAYS_IN_400Y: i64 = 365 * 400 + 97;
327
328/// Number of seconds in a day. As everywhere in this library, leap seconds
329/// are simply ignored.
330const SECONDS_IN_DAY: i64 = 86400;
331
332
333/// Number of days between  **1st January, 1970** and **1st March, 2000**.
334///
335/// This might seem like an odd number to calculate, instead of using the
336/// 1st of January as a reference point, but it turs out that by having the
337/// reference point immediately after a possible leap-year day, the maths
338/// needed to calculate the day/week/month of an instant comes out a *lot*
339/// simpler!
340///
341/// The Gregorian calendar operates on a 400-year cycle, so the combination
342/// of having it on a year that’s a multiple of 400, and having the leap
343/// day at the very end of one of these cycles, means that the calculations
344/// are reduced to simple division (of course, with a bit of date-shifting
345/// to base a date around this reference point).
346///
347/// Rust has the luxury of having been started *after* this date. In Win32,
348/// the epoch is midnight, the 1st of January, 1601, for much the same
349/// reasons - except that it was developed before the year 2000, so they
350/// had to go all the way back to the *previous* 400-year multiple.[^win32]
351///
352/// The only problem is that many people assume the Unix epoch to be
353/// midnight on the 1st January 1970, so this value (and any functions that
354/// depend on it) aren’t exposed to users of this library.
355///
356/// [^win32]: http://blogs.msdn.com/b/oldnewthing/archive/2009/03/06/9461176.aspx
357///
358const EPOCH_DIFFERENCE: i64 = 30 * 365   // 30 years between 2000 and 1970...
359                            + 7          // plus seven days for leap years...
360                            + 31 + 29;   // plus all the days in January and February in 2000.
361
362
363/// This rather strange triangle is an array of the number of days elapsed
364/// at the end of each month, starting at the beginning of March (the first
365/// month after the EPOCH above), going backwards, ignoring February.
366const TIME_TRIANGLE: &[i64; 11] =
367    &[31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 + 31,  // January
368      31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,  // December
369      31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,  // November
370      31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,  // October
371      31 + 30 + 31 + 30 + 31 + 31 + 30,  // September
372      31 + 30 + 31 + 30 + 31 + 31,  // August
373      31 + 30 + 31 + 30 + 31,  // July
374      31 + 30 + 31 + 30,  // June
375      31 + 30 + 31,  // May
376      31 + 30,  // April
377      31]; // March
378
379
380
381/// A **local date** is a day-long span on the timeline, *without a time
382/// zone*.
383#[derive(Eq, Clone, Copy)]
384pub struct LocalDate {
385    ymd:     YMD,
386    yearday: i16,
387    weekday: Weekday,
388}
389
390/// A **local time** is a time on the timeline that recurs once a day,
391/// *without a time zone*.
392#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
393pub struct LocalTime {
394    hour:   i8,
395    minute: i8,
396    second: i8,
397    millisecond: i16,
398}
399
400/// A **local date-time** is an exact instant on the timeline, *without a
401/// time zone*.
402#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
403pub struct LocalDateTime {
404    date: LocalDate,
405    time: LocalTime,
406}
407
408
409impl LocalDate {
410
411    /// Creates a new local date instance from the given year, month, and day
412    /// fields.
413    ///
414    /// The values are checked for validity before instantiation, and
415    /// passing in values out of range will return an error.
416    ///
417    /// ### Examples
418    ///
419    /// Instantiate the 20th of July 1969 based on its year,
420    /// week-of-year, and weekday.
421    ///
422    /// ```rust
423    /// use datetime::{LocalDate, Month, DatePiece};
424    ///
425    /// let date = LocalDate::ymd(1969, Month::July, 20).unwrap();
426    /// assert_eq!(date.year(), 1969);
427    /// assert_eq!(date.month(), Month::July);
428    /// assert_eq!(date.day(), 20);
429    ///
430    /// assert!(LocalDate::ymd(2100, Month::February, 29).is_err());
431    /// ```
432    pub fn ymd(year: i64, month: Month, day: i8) -> Result<Self, Error> {
433        YMD { year, month, day }
434            .to_days_since_epoch()
435            .map(|days| Self::from_days_since_epoch(days - EPOCH_DIFFERENCE))
436    }
437
438    /// Creates a new local date instance from the given year and day-of-year
439    /// values.
440    ///
441    /// The values are checked for validity before instantiation, and
442    /// passing in values out of range will return an error.
443    ///
444    /// ### Examples
445    ///
446    /// Instantiate the 13th of September 2015 based on its year
447    /// and day-of-year.
448    ///
449    /// ```rust
450    /// use datetime::{LocalDate, Weekday, Month, DatePiece};
451    ///
452    /// let date = LocalDate::yd(2015, 0x100).unwrap();
453    /// assert_eq!(date.year(), 2015);
454    /// assert_eq!(date.month(), Month::September);
455    /// assert_eq!(date.day(), 13);
456    /// ```
457    pub fn yd(year: i64, yearday: i64) -> Result<Self, Error> {
458        if yearday.is_within(0..367) {
459            let jan_1 = YMD { year, month: January, day: 1 };
460            let days = jan_1.to_days_since_epoch()?;
461            Ok(Self::from_days_since_epoch(days + yearday - 1 - EPOCH_DIFFERENCE))
462        }
463        else {
464            Err(Error::OutOfRange)
465        }
466    }
467
468    /// Creates a new local date instance from the given year, week-of-year,
469    /// and weekday values.
470    ///
471    /// The values are checked for validity before instantiation, and
472    /// passing in values out of range will return an error.
473    ///
474    /// ### Examples
475    ///
476    /// Instantiate the 11th of September 2015 based on its year,
477    /// week-of-year, and weekday.
478    ///
479    /// ```rust
480    /// use datetime::{LocalDate, Weekday, Month, DatePiece};
481    ///
482    /// let date = LocalDate::ywd(2015, 37, Weekday::Friday).unwrap();
483    /// assert_eq!(date.year(), 2015);
484    /// assert_eq!(date.month(), Month::September);
485    /// assert_eq!(date.day(), 11);
486    /// assert_eq!(date.weekday(), Weekday::Friday);
487    /// ```
488    ///
489    /// Note that according to the ISO-8601 standard, the year will change
490    /// when working with dates early in week 1, or late in week 53:
491    ///
492    /// ```rust
493    /// use datetime::{LocalDate, Weekday, Month, DatePiece};
494    ///
495    /// let date = LocalDate::ywd(2009, 1, Weekday::Monday).unwrap();
496    /// assert_eq!(date.year(), 2008);
497    /// assert_eq!(date.month(), Month::December);
498    /// assert_eq!(date.day(), 29);
499    /// assert_eq!(date.weekday(), Weekday::Monday);
500    ///
501    /// let date = LocalDate::ywd(2009, 53, Weekday::Sunday).unwrap();
502    /// assert_eq!(date.year(), 2010);
503    /// assert_eq!(date.month(), Month::January);
504    /// assert_eq!(date.day(), 3);
505    /// assert_eq!(date.weekday(), Weekday::Sunday);
506    /// ```
507    pub fn ywd(year: i64, week: i64, weekday: Weekday) -> Result<Self, Error> {
508        let jan_4 = YMD { year, month: January, day: 4 };
509        let correction = days_to_weekday(jan_4.to_days_since_epoch().unwrap() - EPOCH_DIFFERENCE).days_from_monday_as_one() as i64 + 3;
510
511        let yearday = 7 * week + weekday.days_from_monday_as_one() as i64 - correction;
512
513        if yearday <= 0 {
514            let days_in_year = if Year(year - 1).is_leap_year() { 366 } else { 365 };
515            Self::yd(year - 1, days_in_year + yearday)
516        }
517        else {
518            let days_in_year = if Year(year).is_leap_year() { 366 } else { 365 };
519
520            if yearday >= days_in_year {
521                Self::yd(year + 1, yearday - days_in_year)
522            }
523            else {
524                Self::yd(year, yearday)
525            }
526        }
527    }
528
529    /// Computes a LocalDate - year, month, day, weekday, and yearday -
530    /// given the number of days that have passed since the EPOCH.
531    ///
532    /// This is used by all the other constructor functions.
533    /// ### Examples
534    ///
535    /// Instantiate the 25th of September 2015 given its day-of-year (268).
536    ///
537    /// ```rust
538    /// use datetime::{LocalDate, Month, DatePiece};
539    ///
540    /// let date = LocalDate::yd(2015, 268).unwrap();
541    /// assert_eq!(date.year(), 2015);
542    /// assert_eq!(date.month(), Month::September);
543    /// assert_eq!(date.day(), 25);
544    /// ```
545    ///
546    /// Remember that on leap years, the number of days in a year changes:
547    ///
548    /// ```rust
549    /// use datetime::{LocalDate, Month, DatePiece};
550    ///
551    /// let date = LocalDate::yd(2016, 268).unwrap();
552    /// assert_eq!(date.year(), 2016);
553    /// assert_eq!(date.month(), Month::September);
554    /// assert_eq!(date.day(), 24);  // not the 25th!
555    /// ```
556    fn from_days_since_epoch(days: i64) -> Self {
557
558        // The Gregorian calendar works in 400-year cycles, which repeat
559        // themselves ever after.
560        //
561        // This calculation works by finding the number of 400-year,
562        // 100-year, and 4-year cycles, then constantly subtracting the
563        // number of leftover days.
564        let (num_400y_cycles, mut remainder) = split_cycles(days, DAYS_IN_400Y);
565
566        // Calculate the numbers of 100-year cycles, 4-year cycles, and
567        // leftover years, continually reducing the number of days left to
568        // think about.
569        let num_100y_cycles = remainder / DAYS_IN_100Y;
570        remainder -= num_100y_cycles * DAYS_IN_100Y;  // remainder is now days left in this 100-year cycle
571
572        let num_4y_cycles = remainder / DAYS_IN_4Y;
573        remainder -= num_4y_cycles * DAYS_IN_4Y;  // remainder is now days left in this 4-year cycle
574
575        let mut years = std::cmp::min(remainder / 365, 3);
576        remainder -= years * 365;  // remainder is now days left in this year
577
578        // Leap year calculation goes thusly:
579        //
580        // 1. If the year is a multiple of 400, it’s a leap year.
581        // 2. Else, if the year is a multiple of 100, it’s *not* a leap year.
582        // 3. Else, if the year is a multiple of 4, it’s a leap year again!
583        //
584        // We already have the values for the numbers of multiples at this
585        // point, and it’s safe to re-use them.
586        let days_this_year =
587            if years == 0 && !(num_4y_cycles == 0 && num_100y_cycles != 0) { 366 }
588                                                                      else { 365 };
589
590        // Find out which number day of the year it is.
591        // The 306 here refers to the number of days in a year excluding
592        // January and February (which are excluded because of the EPOCH)
593        let mut day_of_year = remainder + days_this_year - 306;
594        if day_of_year >= days_this_year {
595            day_of_year -= days_this_year;  // wrap around for January and February
596        }
597
598        // Turn all those cycles into an actual number of years.
599        years +=   4 * num_4y_cycles
600               + 100 * num_100y_cycles
601               + 400 * num_400y_cycles;
602
603        // Work out the month and number of days into the month by scanning
604        // the time triangle, finding the month that has the correct number
605        // of days elapsed at the end of it.
606        // (it’s “11 - index” below because the triangle goes backwards)
607        let result = TIME_TRIANGLE.iter()
608                                  .enumerate()
609                                  .find(|&(_, days)| *days <= remainder);
610
611        let (mut month, month_days) = match result {
612            Some((index, days)) => (11 - index, remainder - *days),
613            None => (0, remainder),  // No month found? Then it’s February.
614        };
615
616        // Need to add 2 to the month in order to compensate for the EPOCH
617        // being in March.
618        month += 2;
619
620        if month >= 12 {
621            years += 1;   // wrap around for January and February
622            month -= 12;  // (yes, again)
623        }
624
625        // The check immediately above means we can `unwrap` this, as the
626        // month number is guaranteed to be in the range (0..12).
627        let month_variant = Month::from_zero(month as i8).unwrap();
628
629        // Finally, adjust the day numbers for human reasons: the first day
630        // of the month is the 1st, rather than the 0th, and the year needs
631        // to be adjusted relative to the EPOCH.
632        Self {
633            yearday: (day_of_year + 1) as i16,
634            weekday: days_to_weekday(days),
635            ymd: YMD {
636                year:  years + 2000,
637                month: month_variant,
638                day:   (month_days + 1) as i8,
639            },
640        }
641    }
642
643    /// Creates a new datestamp instance with the given year, month, day,
644    /// weekday, and yearday fields.
645    ///
646    /// This function is unsafe because **the values are not checked for
647    /// validity!** It’s possible to pass the wrong values in, such as having
648    /// a wrong day value for a month, or having the yearday value out of
649    /// step. Before using it, check that the values are all correct - or just
650    /// use the `date!()` macro, which does this for you at compile-time.
651    ///
652    /// For this reason, the function is marked as `unsafe`, even though it
653    /// (technically) uses unsafe components.
654    pub unsafe fn _new_with_prefilled_values(year: i64, month: Month, day: i8, weekday: Weekday, yearday: i16) -> Self {
655        Self {
656            ymd: YMD { year, month, day },
657            weekday,
658            yearday,
659        }
660    }
661
662    // I’m not 100% convinced on using `unsafe` for something that doesn’t
663    // technically *need* to be unsafe, but I’ll stick with it for now.
664}
665
666impl DatePiece for LocalDate {
667    fn year(&self) -> i64 { self.ymd.year }
668    fn month(&self) -> Month { self.ymd.month }
669    fn day(&self) -> i8 { self.ymd.day }
670    fn yearday(&self) -> i16 { self.yearday }
671    fn weekday(&self) -> Weekday { self.weekday }
672}
673
674impl fmt::Debug for LocalDate {
675    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
676        write!(f, "LocalDate({})", self.iso())
677    }
678}
679
680impl PartialEq for LocalDate {
681    fn eq(&self, other: &Self) -> bool {
682        self.ymd == other.ymd
683    }
684}
685
686impl PartialOrd for LocalDate {
687    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
688        self.ymd.partial_cmp(&other.ymd)
689    }
690}
691
692impl Ord for LocalDate {
693    fn cmp(&self, other: &Self) -> Ordering {
694        self.ymd.cmp(&other.ymd)
695    }
696}
697
698impl LocalTime {
699
700    /// Computes the number of hours, minutes, and seconds, based on the
701    /// number of seconds that have elapsed since midnight.
702    pub fn from_seconds_since_midnight(seconds: i64) -> Self {
703        Self::from_seconds_and_milliseconds_since_midnight(seconds, 0)
704    }
705
706    /// Computes the number of hours, minutes, and seconds, based on the
707    /// number of seconds that have elapsed since midnight.
708    pub fn from_seconds_and_milliseconds_since_midnight(seconds: i64, millisecond_of_second: i16) -> Self {
709        Self {
710            hour:   (seconds / 60 / 60) as i8,
711            minute: (seconds / 60 % 60) as i8,
712            second: (seconds % 60) as i8,
713            millisecond: millisecond_of_second,
714        }
715    }
716
717    /// Returns the time at midnight, with all fields initialised to 0.
718    pub fn midnight() -> Self {
719        Self { hour: 0, minute: 0, second: 0, millisecond: 0 }
720    }
721
722    /// Creates a new timestamp instance with the given hour and minute
723    /// fields. The second and millisecond fields are set to 0.
724    ///
725    /// The values are checked for validity before instantiation, and
726    /// passing in values out of range will return an `Err`.
727    pub fn hm(hour: i8, minute: i8) -> Result<Self, Error> {
728        if (hour.is_within(0..24) && minute.is_within(0..60))
729        || (hour == 24 && minute == 00) {
730            Ok(Self { hour, minute, second: 0, millisecond: 0 })
731        }
732        else {
733            Err(Error::OutOfRange)
734        }
735    }
736
737    /// Creates a new timestamp instance with the given hour, minute, and
738    /// second fields. The millisecond field is set to 0.
739    ///
740    /// The values are checked for validity before instantiation, and
741    /// passing in values out of range will return an `Err`.
742    pub fn hms(hour: i8, minute: i8, second: i8) -> Result<Self, Error> {
743        if (hour.is_within(0..24) && minute.is_within(0..60) && second.is_within(0..60))
744        || (hour == 24 && minute == 00 && second == 00) {
745            Ok(Self { hour, minute, second, millisecond: 0 })
746        }
747        else {
748            Err(Error::OutOfRange)
749        }
750    }
751
752    /// Creates a new timestamp instance with the given hour, minute,
753    /// second, and millisecond fields.
754    ///
755    /// The values are checked for validity before instantiation, and
756    /// passing in values out of range will return an `Err`.
757    pub fn hms_ms(hour: i8, minute: i8, second: i8, millisecond: i16) -> Result<Self, Error> {
758        if hour.is_within(0..24)   && minute.is_within(0..60)
759        && second.is_within(0..60) && millisecond.is_within(0..1000)
760        {
761            Ok(Self { hour, minute, second, millisecond })
762        }
763        else {
764            Err(Error::OutOfRange)
765        }
766    }
767
768    /// Calculate the number of seconds since midnight this time is at,
769    /// ignoring milliseconds.
770    pub fn to_seconds(self) -> i64 {
771        self.hour as i64 * 3600
772            + self.minute as i64 * 60
773            + self.second as i64
774    }
775}
776
777impl TimePiece for LocalTime {
778    fn hour(&self) -> i8 { self.hour }
779    fn minute(&self) -> i8 { self.minute }
780    fn second(&self) -> i8 { self.second }
781    fn millisecond(&self) -> i16 { self.millisecond }
782}
783
784impl fmt::Debug for LocalTime {
785    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
786        write!(f, "LocalTime({})", self.iso())
787    }
788}
789
790
791impl LocalDateTime {
792
793    /// Computes a complete date-time based on the values in the given
794    /// Instant parameter.
795    pub fn from_instant(instant: Instant) -> Self {
796        Self::at_ms(instant.seconds(), instant.milliseconds())
797    }
798
799    /// Computes a complete date-time based on the number of seconds that
800    /// have elapsed since **midnight, 1st January, 1970**, setting the
801    /// number of milliseconds to 0.
802    pub fn at(seconds_since_1970_epoch: i64) -> Self {
803        Self::at_ms(seconds_since_1970_epoch, 0)
804    }
805
806    /// Computes a complete date-time based on the number of seconds that
807    /// have elapsed since **midnight, 1st January, 1970**,
808    pub fn at_ms(seconds_since_1970_epoch: i64, millisecond_of_second: i16) -> Self {
809        let seconds = seconds_since_1970_epoch - EPOCH_DIFFERENCE * SECONDS_IN_DAY;
810
811        // Just split the input value into days and seconds, and let
812        // LocalDate and LocalTime do all the hard work.
813        let (days, secs) = split_cycles(seconds, SECONDS_IN_DAY);
814
815        Self {
816            date: LocalDate::from_days_since_epoch(days),
817            time: LocalTime::from_seconds_and_milliseconds_since_midnight(secs, millisecond_of_second),
818        }
819    }
820
821    /// Creates a new local date time from a local date and a local time.
822    pub fn new(date: LocalDate, time: LocalTime) -> Self {
823        Self {
824            date,
825            time,
826        }
827    }
828
829    /// Returns the date portion of this date-time stamp.
830    pub fn date(&self) -> LocalDate {
831        self.date
832    }
833
834    /// Returns the time portion of this date-time stamp.
835    pub fn time(&self) -> LocalTime {
836        self.time
837    }
838
839    /// Creates a new date-time stamp set to the current time.
840    #[cfg_attr(target_os = "redox", allow(unused_unsafe))]
841    pub fn now() -> Self {
842        let (s, ms) = unsafe { sys_time() };
843        Self::at_ms(s, ms)
844    }
845
846    pub fn to_instant(&self) -> Instant {
847        let seconds = self.date.ymd.to_days_since_epoch().unwrap() * SECONDS_IN_DAY + self.time.to_seconds();
848        Instant::at_ms(seconds, self.time.millisecond)
849    }
850
851    pub fn add_seconds(&self, seconds: i64) -> Self {
852        Self::from_instant(self.to_instant() + Duration::of(seconds))
853    }
854}
855
856impl DatePiece for LocalDateTime {
857    fn year(&self) -> i64 { self.date.ymd.year }
858    fn month(&self) -> Month { self.date.ymd.month }
859    fn day(&self) -> i8 { self.date.ymd.day }
860    fn yearday(&self) -> i16 { self.date.yearday }
861    fn weekday(&self) -> Weekday { self.date.weekday }
862}
863
864impl TimePiece for LocalDateTime {
865    fn hour(&self) -> i8 { self.time.hour }
866    fn minute(&self) -> i8 { self.time.minute }
867    fn second(&self) -> i8 { self.time.second }
868    fn millisecond(&self) -> i16 { self.time.millisecond }
869}
870
871impl fmt::Debug for LocalDateTime {
872    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
873        write!(f, "LocalDateTime({})", self.iso())
874    }
875}
876
877impl Add<Duration> for LocalDateTime {
878    type Output = Self;
879
880    fn add(self, duration: Duration) -> Self {
881        Self::from_instant(self.to_instant() + duration)
882    }
883}
884
885impl Sub<Duration> for LocalDateTime {
886    type Output = Self;
887
888    fn sub(self, duration: Duration) -> Self {
889        Self::from_instant(self.to_instant() - duration)
890    }
891}
892
893
894/// A **YMD** is an implementation detail of `LocalDate`. It provides
895/// helper methods relating to the construction of `LocalDate` instances.
896///
897/// The main difference is that while all `LocalDate` values get checked
898/// for validity before they are used, there is no such check for `YMD`.
899/// The interface to `LocalDate` ensures that it should be impossible to
900/// create an instance of the 74th of March, for example, but you’re
901/// free to create such an instance of `YMD`. For this reason, it is not
902/// exposed to implementors of this library.
903#[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Debug, Copy)]
904struct YMD {
905    year:    i64,
906    month:   Month,
907    day:     i8,
908}
909
910impl YMD {
911
912    /// Calculates the number of days that have elapsed since the 1st
913    /// January, 1970. Returns the number of days if this datestamp is
914    /// valid; None otherwise.
915    ///
916    /// This method returns a Result instead of exposing is_valid to
917    /// the user, because the leap year calculations are used in both
918    /// functions, so it makes more sense to only do them once.
919    fn to_days_since_epoch(&self) -> Result<i64, Error> {
920        let years = self.year - 2000;
921        let (leap_days_elapsed, is_leap_year) = Year(self.year).leap_year_calculations();
922
923        if !self.is_valid(is_leap_year) {
924            return Err(Error::OutOfRange);
925        }
926
927        // Work out the number of days from the start of 1970 to now,
928        // which is a multiple of the number of years...
929        let days = years * 365
930
931            // Plus the number of days between the start of 2000 and the
932            // start of 1970, to make up the difference because our
933            // dates start at 2000 and instants start at 1970...
934            + 10958
935
936            // Plus the number of leap years that have elapsed between
937            // now and the start of 2000...
938            + leap_days_elapsed
939
940            // Plus the number of days in all the months leading up to
941            // the current month...
942            + self.month.days_before_start() as i64
943
944            // Plus an extra leap day for *this* year...
945            + if is_leap_year && self.month >= March { 1 } else { 0 }
946
947            // Plus the number of days in the month so far! (Days are
948            // 1-indexed, so we make them 0-indexed here)
949            + (self.day - 1) as i64;
950
951        Ok(days)
952    }
953
954    /// Returns whether this datestamp is valid, which basically means
955    /// whether the day is in the range allowed by the month.
956    ///
957    /// Whether the current year is a leap year should already have been
958    /// calculated at this point, so the value is passed in rather than
959    /// calculating it afresh.
960    fn is_valid(&self, is_leap_year: bool) -> bool {
961        self.day >= 1 && self.day <= self.month.days_in_month(is_leap_year)
962    }
963}
964
965/// Computes the weekday, given the number of days that have passed
966/// since the EPOCH.
967fn days_to_weekday(days: i64) -> Weekday {
968    // March 1st, 2000 was a Wednesday, so add 3 to the number of days.
969    let weekday = (days + 3) % 7;
970
971    // We can unwrap since we’ve already done the bounds checking.
972    Weekday::from_zero(if weekday < 0 { weekday + 7 } else { weekday } as i8).unwrap()
973}
974
975/// Split a number of years into a number of year-cycles, and the number
976/// of years left over that don’t fit into a cycle. This is also used
977/// for day-cycles.
978///
979/// This is essentially a division operation with the result and the
980/// remainder, with the difference that a negative value gets ‘wrapped
981/// around’ to be a positive value, owing to the way the modulo operator
982/// works for negative values.
983fn split_cycles(number_of_periods: i64, cycle_length: i64) -> (i64, i64) {
984    let mut cycles    = number_of_periods / cycle_length;
985    let mut remainder = number_of_periods % cycle_length;
986
987    if remainder < 0 {
988        remainder += cycle_length;
989        cycles    -= 1;
990    }
991
992    (cycles, remainder)
993}
994
995
996#[derive(PartialEq, Debug, Copy, Clone)]
997pub enum Error {
998    OutOfRange,
999}
1000
1001impl fmt::Display for Error {
1002    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1003        write!(f, "datetime field out of range")
1004    }
1005}
1006
1007impl ErrorTrait for Error {
1008}
1009
1010
1011/// A month of the year, starting with January, and ending with December.
1012///
1013/// This is stored as an enum instead of just a number to prevent
1014/// off-by-one errors: is month 2 February (1-indexed) or March (0-indexed)?
1015/// In this case, it’s 1-indexed, to have January become 1 when you use
1016/// `as i32` in code.
1017#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
1018pub enum Month {
1019    January =  1, February =  2, March     =  3,
1020    April   =  4, May      =  5, June      =  6,
1021    July    =  7, August   =  8, September =  9,
1022    October = 10, November = 11, December  = 12,
1023}
1024
1025#[allow(clippy::match_same_arms)]
1026impl Month {
1027
1028    /// Returns the number of days in this month, depending on whether it’s
1029    /// a leap year or not.
1030    pub fn days_in_month(self, leap_year: bool) -> i8 {
1031        match self {
1032            January   => 31, February  => if leap_year { 29 } else { 28 },
1033            March     => 31, April     => 30,
1034            May       => 31, June      => 30,
1035            July      => 31, August    => 31,
1036            September => 30, October   => 31,
1037            November  => 30, December  => 31,
1038        }
1039    }
1040
1041    /// Returns the number of days that have elapsed in a year *before* this
1042    /// month begins, with no leap year check.
1043    fn days_before_start(self) -> i16 {
1044        match self {
1045            January =>   0, February =>  31, March     =>  59,
1046            April   =>  90, May      => 120, June      => 151,
1047            July    => 181, August   => 212, September => 243,
1048            October => 273, November => 304, December  => 334,
1049        }
1050    }
1051
1052    pub fn months_from_january(self) -> usize {
1053        match self {
1054            January =>   0, February =>   1, March     =>  2,
1055            April   =>   3, May      =>   4, June      =>  5,
1056            July    =>   6, August   =>   7, September =>  8,
1057            October =>   9, November =>  10, December  => 11,
1058        }
1059    }
1060
1061    /// Returns the month based on a number, with January as **Month 1**,
1062    /// February as **Month 2**, and so on.
1063    ///
1064    /// ```rust
1065    /// use datetime::Month;
1066    /// assert_eq!(Month::from_one(5), Ok(Month::May));
1067    /// assert!(Month::from_one(0).is_err());
1068    /// ```
1069    pub fn from_one(month: i8) -> Result<Self, Error> {
1070        Ok(match month {
1071             1 => January,   2 => February,   3 => March,
1072             4 => April,     5 => May,        6 => June,
1073             7 => July,      8 => August,     9 => September,
1074            10 => October,  11 => November,  12 => December,
1075             _ => return Err(Error::OutOfRange),
1076        })
1077    }
1078
1079    /// Returns the month based on a number, with January as **Month 0**,
1080    /// February as **Month 1**, and so on.
1081    ///
1082    /// ```rust
1083    /// use datetime::Month;
1084    /// assert_eq!(Month::from_zero(5), Ok(Month::June));
1085    /// assert!(Month::from_zero(12).is_err());
1086    /// ```
1087    pub fn from_zero(month: i8) -> Result<Self, Error> {
1088        Ok(match month {
1089            0 => January,   1 => February,   2 => March,
1090            3 => April,     4 => May,        5 => June,
1091            6 => July,      7 => August,     8 => September,
1092            9 => October,  10 => November,  11 => December,
1093            _ => return Err(Error::OutOfRange),
1094        })
1095    }
1096}
1097
1098
1099/// A named day of the week.
1100#[derive(PartialEq, Eq, Debug, Clone, Copy)]
1101pub enum Weekday {
1102    Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday,
1103}
1104
1105// Sunday is Day 0. This seems to be a North American thing? It’s pretty
1106// much an arbitrary choice, and as you can’t use the `from_zero` method,
1107// it won’t affect you at all. If you want to change it, the only thing
1108// that should be affected is `LocalDate::days_to_weekday`.
1109//
1110// I’m not going to give weekdays an Ord instance because there’s no
1111// real standard as to whether Sunday should come before Monday, or the
1112// other way around. Luckily, they don’t need one, as the field is
1113// ignored when comparing LocalDates.
1114
1115impl Weekday {
1116    fn days_from_monday_as_one(self) -> i8 {
1117        match self {
1118            Sunday   => 7,  Monday    => 1,
1119            Tuesday  => 2,  Wednesday => 3,
1120            Thursday => 4,  Friday    => 5,
1121            Saturday => 6,
1122        }
1123    }
1124
1125    /// Return the weekday based on a number, with Sunday as Day 0, Monday as
1126    /// Day 1, and so on.
1127    ///
1128    /// ```rust
1129    /// use datetime::Weekday;
1130    /// assert_eq!(Weekday::from_zero(4), Ok(Weekday::Thursday));
1131    /// assert!(Weekday::from_zero(7).is_err());
1132    /// ```
1133    pub fn from_zero(weekday: i8) -> Result<Self, Error> {
1134        Ok(match weekday {
1135            0 => Sunday,     1 => Monday,    2 => Tuesday,
1136            3 => Wednesday,  4 => Thursday,  5 => Friday,
1137            6 => Saturday,   _ => return Err(Error::OutOfRange),
1138        })
1139    }
1140
1141    pub fn from_one(weekday: i8) -> Result<Self, Error> {
1142        Ok(match weekday {
1143            7 => Sunday,     1 => Monday,    2 => Tuesday,
1144            3 => Wednesday,  4 => Thursday,  5 => Friday,
1145            6 => Saturday,   _ => return Err(Error::OutOfRange),
1146        })
1147    }
1148}
1149
1150
1151/// Misc tests that don’t seem to fit anywhere.
1152#[cfg(test)]
1153mod test {
1154    pub(crate) use super::{LocalDateTime, LocalDate, LocalTime, Month};
1155
1156
1157    #[test]
1158    fn some_leap_years() {
1159        for year in [2004,2008,2012,2016].iter() {
1160            assert!(LocalDate::ymd(*year, Month::February, 29).is_ok());
1161            assert!(LocalDate::ymd(*year + 1, Month::February, 29).is_err());
1162        }
1163        assert!(LocalDate::ymd(1600,Month::February,29).is_ok());
1164        assert!(LocalDate::ymd(1601,Month::February,29).is_err());
1165        assert!(LocalDate::ymd(1602,Month::February,29).is_err());
1166    }
1167
1168    #[test]
1169    fn new() {
1170        for year in 1..3000 {
1171            assert!(LocalDate::ymd(year, Month::from_one( 1).unwrap(), 32).is_err()); assert!(LocalDate::ymd(year, Month::from_one( 2).unwrap(), 30).is_err()); assert!(LocalDate::ymd(year, Month::from_one( 3).unwrap(), 32).is_err());
1172            assert!(LocalDate::ymd(year, Month::from_one( 4).unwrap(), 31).is_err()); assert!(LocalDate::ymd(year, Month::from_one( 5).unwrap(), 32).is_err()); assert!(LocalDate::ymd(year, Month::from_one( 6).unwrap(), 31).is_err());
1173            assert!(LocalDate::ymd(year, Month::from_one( 7).unwrap(), 32).is_err()); assert!(LocalDate::ymd(year, Month::from_one( 8).unwrap(), 32).is_err()); assert!(LocalDate::ymd(year, Month::from_one( 9).unwrap(), 31).is_err());
1174            assert!(LocalDate::ymd(year, Month::from_one(10).unwrap(), 32).is_err()); assert!(LocalDate::ymd(year, Month::from_one(11).unwrap(), 31).is_err()); assert!(LocalDate::ymd(year, Month::from_one(12).unwrap(), 32).is_err());
1175        }
1176    }
1177
1178    #[test]
1179    fn to_from_days_since_epoch() {
1180        let epoch_difference: i64 = 30 * 365 + 7 + 31 + 29;  // see EPOCH_DIFFERENCE
1181        for date in  vec![
1182            LocalDate::ymd(1970, Month::from_one(01).unwrap(), 01).unwrap(),
1183            LocalDate::ymd(  01, Month::from_one(01).unwrap(), 01).unwrap(),
1184            LocalDate::ymd(1971, Month::from_one(01).unwrap(), 01).unwrap(),
1185            LocalDate::ymd(1973, Month::from_one(01).unwrap(), 01).unwrap(),
1186            LocalDate::ymd(1977, Month::from_one(01).unwrap(), 01).unwrap(),
1187            LocalDate::ymd(1989, Month::from_one(11).unwrap(), 10).unwrap(),
1188            LocalDate::ymd(1990, Month::from_one( 7).unwrap(),  8).unwrap(),
1189            LocalDate::ymd(2014, Month::from_one( 7).unwrap(), 13).unwrap(),
1190            LocalDate::ymd(2001, Month::from_one( 2).unwrap(), 03).unwrap()
1191        ]{
1192            assert_eq!( date,
1193                LocalDate::from_days_since_epoch(
1194                    date.ymd.to_days_since_epoch().unwrap() - epoch_difference));
1195        }
1196    }
1197
1198    mod debug {
1199        use super::*;
1200
1201        #[test]
1202        fn recently() {
1203            let date = LocalDate::ymd(1600, Month::February, 28).unwrap();
1204            let debugged = format!("{:?}", date);
1205
1206            assert_eq!(debugged, "LocalDate(1600-02-28)");
1207        }
1208
1209        #[test]
1210        fn just_then() {
1211            let date = LocalDate::ymd(-753, Month::December, 1).unwrap();
1212            let debugged = format!("{:?}", date);
1213
1214            assert_eq!(debugged, "LocalDate(-0753-12-01)");
1215        }
1216
1217        #[test]
1218        fn far_far_future() {
1219            let date = LocalDate::ymd(10601, Month::January, 31).unwrap();
1220            let debugged = format!("{:?}", date);
1221
1222            assert_eq!(debugged, "LocalDate(+10601-01-31)");
1223        }
1224
1225        #[test]
1226        fn midday() {
1227            let time = LocalTime::hms(12, 0, 0).unwrap();
1228            let debugged = format!("{:?}", time);
1229
1230            assert_eq!(debugged, "LocalTime(12:00:00.000)");
1231        }
1232
1233        #[test]
1234        fn ascending() {
1235            let then = LocalDateTime::new(
1236                        LocalDate::ymd(2009, Month::February, 13).unwrap(),
1237                        LocalTime::hms(23, 31, 30).unwrap());
1238            let debugged = format!("{:?}", then);
1239
1240            assert_eq!(debugged, "LocalDateTime(2009-02-13T23:31:30.000)");
1241        }
1242    }
1243}