diff --git a/src/date.rs b/src/date.rs index 5dfa58d..c8a32de 100644 --- a/src/date.rs +++ b/src/date.rs @@ -21,6 +21,28 @@ use datetime::DateTime; use format::{Item, DelayedFormat, StrftimeItems}; /// ISO 8601 calendar date with time zone. +/// +/// This type should be considered ambiguous at best, +/// due to the inherent lack of precision required for the time zone resolution. +/// There are some guarantees on the usage of `Date`: +/// +/// - If properly constructed via `TimeZone::ymd` and others without an error, +/// the corresponding local date should exist for at least a moment. +/// (It may still have a gap from the offset changes.) +/// +/// - The `TimeZone` is free to assign *any* `Offset` to the local date, +/// as long as that offset did occur in given day. +/// For example, if `2015-03-08T01:59-08:00` is followed by `2015-03-08T03:00-07:00`, +/// it may produce either `2015-03-08-08:00` or `2015-03-08-07:00` +/// but *not* `2015-03-08+00:00` and others. +/// +/// - Once constructed as a full `DateTime`, +/// `DateTime::date` and other associated methods should return those for the original `Date`. +/// For example, if `dt = tz.ymd(y,m,d).hms(h,n,s)` were valid, `dt.date() == tz.ymd(y,m,d)`. +/// +/// - The date is timezone-agnostic up to one day (i.e. practically always), +/// so the local date and UTC date should be equal for most cases +/// even though the raw calculation between `NaiveDate` and `Duration` may not. #[derive(Clone)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] pub struct Date { diff --git a/src/datetime.rs b/src/datetime.rs index f7eb63f..51a2ac8 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -43,7 +43,7 @@ impl DateTime { /// Retrieves a date component. #[inline] pub fn date(&self) -> Date { - Date::from_utc(self.datetime.date().clone(), self.offset.clone()) + Date::from_utc(self.naive_local().date(), self.offset.clone()) } /// Retrieves a time component. @@ -429,6 +429,7 @@ mod tests { use super::DateTime; use Datelike; use naive::time::NaiveTime; + use naive::date::NaiveDate; use duration::Duration; use offset::TimeZone; use offset::utc::UTC; @@ -481,9 +482,27 @@ mod tests { } #[test] - fn test_datetime_time() { - assert_eq!(FixedOffset::east(5*60*60).ymd(2014, 5, 6).and_hms(7, 8, 9).time(), - NaiveTime::from_hms(7, 8, 9)); + fn test_datetime_date_and_time() { + let tz = FixedOffset::east(5*60*60); + let d = tz.ymd(2014, 5, 6).and_hms(7, 8, 9); + assert_eq!(d.time(), NaiveTime::from_hms(7, 8, 9)); + assert_eq!(d.date(), tz.ymd(2014, 5, 6)); + assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2014, 5, 6)); + assert_eq!(d.date().and_time(d.time()), Some(d)); + + let tz = FixedOffset::east(4*60*60); + let d = tz.ymd(2016, 5, 4).and_hms(3, 2, 1); + assert_eq!(d.time(), NaiveTime::from_hms(3, 2, 1)); + assert_eq!(d.date(), tz.ymd(2016, 5, 4)); + assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2016, 5, 4)); + assert_eq!(d.date().and_time(d.time()), Some(d)); + + let tz = FixedOffset::west(13*60*60); + let d = tz.ymd(2017, 8, 9).and_hms(12, 34, 56); + assert_eq!(d.time(), NaiveTime::from_hms(12, 34, 56)); + assert_eq!(d.date(), tz.ymd(2017, 8, 9)); + assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2017, 8, 9)); + assert_eq!(d.date().and_time(d.time()), Some(d)); } #[test]