diff --git a/src/date.rs b/src/date.rs index 4347d4c..d8c233b 100644 --- a/src/date.rs +++ b/src/date.rs @@ -350,10 +350,12 @@ impl fmt::Display for Date where Tz::Offset: fmt::Display { mod tests { use std::fmt; + use Datelike; use duration::Duration; use naive::date::NaiveDate; use naive::datetime::NaiveDateTime; use offset::{TimeZone, Offset, LocalResult}; + use offset::local::Local; #[derive(Copy, Clone, PartialEq, Eq)] struct UTC1y; // same to UTC but with an offset of 365 days @@ -396,5 +398,10 @@ mod tests { assert_eq!(format!("{:?}", UTC1y.ymd(2012, 3, 4).and_hms(5, 6, 7)), "2012-03-04T05:06:07+8760:00".to_string()); } + + #[test] + fn test_local_date_sanity_check() { // issue #27 + assert_eq!(Local.ymd(2999, 12, 28).day(), 28); + } } diff --git a/src/datetime.rs b/src/datetime.rs index 35a0d0f..08b296b 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -378,23 +378,42 @@ mod tests { #[test] #[allow(non_snake_case)] fn test_datetime_offset() { - let EST = FixedOffset::east(5*60*60); - let EDT = FixedOffset::east(4*60*60); + let EST = FixedOffset::west(5*60*60); + let EDT = FixedOffset::west(4*60*60); + let KST = FixedOffset::east(9*60*60); assert_eq!(format!("{}", UTC.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06 07:08:09 UTC"); assert_eq!(format!("{}", EDT.ymd(2014, 5, 6).and_hms(7, 8, 9)), - "2014-05-06 07:08:09 +04:00"); + "2014-05-06 07:08:09 -04:00"); + assert_eq!(format!("{}", KST.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06 07:08:09 +09:00"); assert_eq!(format!("{:?}", UTC.ymd(2014, 5, 6).and_hms(7, 8, 9)), "2014-05-06T07:08:09Z"); assert_eq!(format!("{:?}", EDT.ymd(2014, 5, 6).and_hms(7, 8, 9)), - "2014-05-06T07:08:09+04:00"); + "2014-05-06T07:08:09-04:00"); + assert_eq!(format!("{:?}", KST.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06T07:08:09+09:00"); - assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9), EDT.ymd(2014, 5, 6).and_hms(11, 8, 9)); + // edge cases + assert_eq!(format!("{:?}", UTC.ymd(2014, 5, 6).and_hms(0, 0, 0)), + "2014-05-06T00:00:00Z"); + assert_eq!(format!("{:?}", EDT.ymd(2014, 5, 6).and_hms(0, 0, 0)), + "2014-05-06T00:00:00-04:00"); + assert_eq!(format!("{:?}", KST.ymd(2014, 5, 6).and_hms(0, 0, 0)), + "2014-05-06T00:00:00+09:00"); + assert_eq!(format!("{:?}", UTC.ymd(2014, 5, 6).and_hms(23, 59, 59)), + "2014-05-06T23:59:59Z"); + assert_eq!(format!("{:?}", EDT.ymd(2014, 5, 6).and_hms(23, 59, 59)), + "2014-05-06T23:59:59-04:00"); + assert_eq!(format!("{:?}", KST.ymd(2014, 5, 6).and_hms(23, 59, 59)), + "2014-05-06T23:59:59+09:00"); + + assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9), EDT.ymd(2014, 5, 6).and_hms(3, 8, 9)); assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9) + Duration::seconds(3600 + 60 + 1), UTC.ymd(2014, 5, 6).and_hms(8, 9, 10)); assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9) - EDT.ymd(2014, 5, 6).and_hms(10, 11, 12), - Duration::seconds(3600 - 3*60 - 3)); + Duration::seconds(-7*3600 - 3*60 - 3)); assert_eq!(*UTC.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), UTC); assert_eq!(*EDT.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), EDT); diff --git a/src/offset/local.rs b/src/offset/local.rs index 2a74d85..403ca03 100644 --- a/src/offset/local.rs +++ b/src/offset/local.rs @@ -95,7 +95,11 @@ impl TimeZone for Local { // override them for avoiding redundant works fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { - self.from_local_datetime(&local.and_hms(0, 0, 0)).map(|datetime| datetime.date()) + // this sounds very strange, but required for keeping `TimeZone::ymd` sane. + // in the other words, we use the offset at the local midnight + // but keep the actual date unaltered (much like `FixedOffset`). + let midnight = self.from_local_datetime(&local.and_hms(0, 0, 0)); + midnight.map(|datetime| Date::from_utc(*local, datetime.offset().clone())) } fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { let timespec = datetime_to_timespec(local, true); @@ -103,7 +107,8 @@ impl TimeZone for Local { } fn from_utc_date(&self, utc: &NaiveDate) -> Date { - self.from_utc_datetime(&utc.and_hms(0, 0, 0)).date() + let midnight = self.from_utc_datetime(&utc.and_hms(0, 0, 0)); + Date::from_utc(*utc, midnight.offset().clone()) } fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { let timespec = datetime_to_timespec(utc, false);