diff --git a/CHANGELOG.md b/CHANGELOG.md index 16a9063b60..2cf4b6c719 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Versions with only mechanical changes will be omitted from the following list. * Add support for microseconds timestamps serde serialization/deserialization (#304) * Fix `DurationRound` is not TZ aware (#495) * Implement `DurationRound` for `NaiveDateTime` +* Add `DateTime::from_local()` to construct from given local date and time (#572) ## 0.4.19 diff --git a/src/datetime.rs b/src/datetime.rs index 2eeb2e47c3..766cdca51d 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -96,6 +96,37 @@ impl DateTime { DateTime { datetime: datetime, offset: offset } } + /// Makes a new `DateTime` with given **local** datetime and offset that + /// presents local timezone. + /// + /// # Example + /// + /// ``` + /// use chrono::DateTime; + /// use chrono::naive::NaiveDate; + /// use chrono::offset::{Utc, FixedOffset}; + /// + /// let naivedatetime_utc = NaiveDate::from_ymd(2000, 1, 12).and_hms(2, 0, 0); + /// let datetime_utc = DateTime::::from_utc(naivedatetime_utc, Utc); + /// + /// let timezone_east = FixedOffset::east(8 * 60 * 60); + /// let naivedatetime_east = NaiveDate::from_ymd(2000, 1, 12).and_hms(10, 0, 0); + /// let datetime_east = DateTime::::from_local(naivedatetime_east, timezone_east); + /// + /// let timezone_west = FixedOffset::west(7 * 60 * 60); + /// let naivedatetime_west = NaiveDate::from_ymd(2000, 1, 11).and_hms(19, 0, 0); + /// let datetime_west = DateTime::::from_local(naivedatetime_west, timezone_west); + + /// assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)); + /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); + /// ``` + #[inline] + pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { + let datetime_utc = datetime - offset.fix(); + + DateTime { datetime: datetime_utc, offset: offset } + } + /// Retrieves a date component /// /// Unless you are immediately planning on turning this into a `DateTime` @@ -2999,4 +3030,24 @@ mod tests { assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd)); assert_eq!(format!(" {} ", ymd_formatted), format!("{:^17}", ymd)); } + + #[test] + fn test_datetime_from_local() { + // 2000-01-12T02:00:00Z + let naivedatetime_utc = NaiveDate::from_ymd(2000, 1, 12).and_hms(2, 0, 0); + let datetime_utc = DateTime::::from_utc(naivedatetime_utc, Utc); + + // 2000-01-12T10:00:00+8:00:00 + let timezone_east = FixedOffset::east(8 * 60 * 60); + let naivedatetime_east = NaiveDate::from_ymd(2000, 1, 12).and_hms(10, 0, 0); + let datetime_east = DateTime::::from_local(naivedatetime_east, timezone_east); + + // 2000-01-11T19:00:00-7:00:00 + let timezone_west = FixedOffset::west(7 * 60 * 60); + let naivedatetime_west = NaiveDate::from_ymd(2000, 1, 11).and_hms(19, 0, 0); + let datetime_west = DateTime::::from_local(naivedatetime_west, timezone_west); + + assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east)); + assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); + } }