Skip to content

Commit

Permalink
Merge branch 'main'
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Mar 14, 2024
2 parents 0fa2a7f + 236b7ad commit d286f93
Show file tree
Hide file tree
Showing 17 changed files with 302 additions and 234 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Chrono aims to provide all functionality needed to do correct operations on date
* The [`DateTime`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) type is timezone-aware
by default, with separate timezone-naive types.
* Operations that may produce an invalid or ambiguous date and time return `Option` or
[`LocalResult`](https://docs.rs/chrono/latest/chrono/offset/enum.LocalResult.html).
[`MappedLocalTime`](https://docs.rs/chrono/latest/chrono/offset/enum.MappedLocalTime.html).
* Configurable parsing and formatting with an `strftime` inspired date and time formatting syntax.
* The [`Local`](https://docs.rs/chrono/latest/chrono/offset/struct.Local.html) timezone works with
the current timezone of the OS.
Expand Down
28 changes: 27 additions & 1 deletion src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::format::{write_rfc2822, write_rfc3339, DelayedFormat, SecondsFormat};
use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
#[cfg(feature = "clock")]
use crate::offset::Local;
use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
use crate::offset::{FixedOffset, MappedLocalTime, Offset, TimeZone, Utc};
#[cfg(any(feature = "clock", feature = "std"))]
use crate::OutOfRange;
use crate::{try_err, try_ok_or, Datelike, Error, Months, TimeDelta, Timelike, Weekday};
Expand Down Expand Up @@ -673,6 +673,32 @@ impl<Tz: TimeZone> DateTime<Tz> {
map_local(self, |datetime| datetime.with_ordinal0(ordinal0))
}

/// Set the time to a new fixed time on the existing date.
///
/// # Errors
///
/// Returns `MappedLocalTime::None` if the datetime is at the edge of the representable range
/// for a `DateTime`, and `with_time` would push the value in UTC out of range.
///
/// # Example
///
#[cfg_attr(not(feature = "clock"), doc = "```ignore")]
#[cfg_attr(feature = "clock", doc = "```rust")]
/// use chrono::{Local, NaiveTime};
///
/// let noon = NaiveTime::from_hms(12, 0, 0)?;
/// let today_noon = Local::now().with_time(noon);
/// let today_midnight = Local::now().with_time(NaiveTime::MIN);
///
/// assert_eq!(today_noon.single().unwrap().time(), noon);
/// assert_eq!(today_midnight.single().unwrap().time(), NaiveTime::MIN);
/// # Ok::<(), chrono::Error>(())
/// ```
#[must_use]
pub fn with_time(&self, time: NaiveTime) -> MappedLocalTime<Self> {
self.timezone().from_local_datetime(&self.overflowing_naive_local().date().and_time(time))
}

/// Makes a new `DateTime` with the hour number changed.
///
/// See also the [`NaiveTime::with_hour`] method.
Expand Down
6 changes: 3 additions & 3 deletions src/datetime/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1235,7 +1235,7 @@ mod tests {

#[test]
fn test_serde_no_offset_debug() {
use crate::{LocalResult, NaiveDateTime, Offset};
use crate::{MappedLocalTime, NaiveDateTime, Offset};
use core::fmt::Debug;

#[derive(Clone)]
Expand All @@ -1253,8 +1253,8 @@ mod tests {
fn offset_from_local_datetime(
&self,
_local: &NaiveDateTime,
) -> LocalResult<TestTimeZone> {
LocalResult::Single(TestTimeZone)
) -> MappedLocalTime<TestTimeZone> {
MappedLocalTime::Single(TestTimeZone)
}
fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> TestTimeZone {
TestTimeZone
Expand Down
14 changes: 7 additions & 7 deletions src/datetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::offset::{FixedOffset, TimeZone, Utc};
#[cfg(feature = "clock")]
use crate::offset::{Local, Offset};
use crate::{
Datelike, Days, Error, LocalResult, Months, NaiveDateTime, TimeDelta, Timelike, Weekday,
Datelike, Days, Error, MappedLocalTime, Months, NaiveDateTime, TimeDelta, Timelike, Weekday,
};

#[derive(Clone)]
Expand Down Expand Up @@ -36,7 +36,7 @@ impl TimeZone for DstTester {
fn offset_from_local_datetime(
&self,
local: &NaiveDateTime,
) -> crate::LocalResult<Self::Offset> {
) -> crate::MappedLocalTime<Self::Offset> {
let local_to_winter_transition_start = NaiveDate::from_ymd(
local.year(),
DstTester::TO_WINTER_MONTH_DAY.0,
Expand Down Expand Up @@ -70,19 +70,19 @@ impl TimeZone for DstTester {
.and_time(DstTester::transition_start_local() + TimeDelta::hours(1));

if *local < local_to_winter_transition_end || *local >= local_to_summer_transition_end {
LocalResult::Single(DstTester::summer_offset())
MappedLocalTime::Single(DstTester::summer_offset())
} else if *local >= local_to_winter_transition_start
&& *local < local_to_summer_transition_start
{
LocalResult::Single(DstTester::winter_offset())
MappedLocalTime::Single(DstTester::winter_offset())
} else if *local >= local_to_winter_transition_end
&& *local < local_to_winter_transition_start
{
LocalResult::Ambiguous(DstTester::winter_offset(), DstTester::summer_offset())
MappedLocalTime::Ambiguous(DstTester::winter_offset(), DstTester::summer_offset())

Check warning on line 81 in src/datetime/tests.rs

View check run for this annotation

Codecov / codecov/patch

src/datetime/tests.rs#L81

Added line #L81 was not covered by tests
} else if *local >= local_to_summer_transition_start
&& *local < local_to_summer_transition_end
{
LocalResult::None
MappedLocalTime::None

Check warning on line 85 in src/datetime/tests.rs

View check run for this annotation

Codecov / codecov/patch

src/datetime/tests.rs#L85

Added line #L85 was not covered by tests
} else {
panic!("Unexpected local time {}", local)
}
Expand Down Expand Up @@ -592,7 +592,7 @@ fn signed_duration_since_autoref() {
let diff2 = dt2.signed_duration_since(&dt1); // Take by reference
assert_eq!(diff1, -diff2);

let diff1 = dt1 - &dt2; // We can choose to substract rhs by reference
let diff1 = dt1 - &dt2; // We can choose to subtract rhs by reference
let diff2 = dt2 - dt1; // Or consume rhs
assert_eq!(diff1, -diff2);
}
Expand Down
14 changes: 7 additions & 7 deletions src/format/parsed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone};
use crate::offset::{FixedOffset, MappedLocalTime, Offset, TimeZone};
use crate::{DateTime, Datelike, TimeDelta, Timelike, Weekday};

/// A type to hold parsed fields of date and time that can check all fields are consistent.
Expand Down Expand Up @@ -859,9 +859,9 @@ impl Parsed {
let offset = FixedOffset::east(offset).map_err(|_| OUT_OF_RANGE)?;

match offset.from_local_datetime(&datetime) {
LocalResult::None => Err(IMPOSSIBLE),
LocalResult::Single(t) => Ok(t),
LocalResult::Ambiguous(..) => Err(NOT_ENOUGH),
MappedLocalTime::None => Err(IMPOSSIBLE),

Check warning on line 862 in src/format/parsed.rs

View check run for this annotation

Codecov / codecov/patch

src/format/parsed.rs#L862

Added line #L862 was not covered by tests
MappedLocalTime::Single(t) => Ok(t),
MappedLocalTime::Ambiguous(..) => Err(NOT_ENOUGH),

Check warning on line 864 in src/format/parsed.rs

View check run for this annotation

Codecov / codecov/patch

src/format/parsed.rs#L864

Added line #L864 was not covered by tests
}
}

Expand Down Expand Up @@ -915,15 +915,15 @@ impl Parsed {
// it will be 0 otherwise, but this is fine as the algorithm ignores offset for that case.
let datetime = self.to_naive_datetime_with_offset(guessed_offset)?;
match tz.from_local_datetime(&datetime) {
LocalResult::None => Err(IMPOSSIBLE),
LocalResult::Single(t) => {
MappedLocalTime::None => Err(IMPOSSIBLE),

Check warning on line 918 in src/format/parsed.rs

View check run for this annotation

Codecov / codecov/patch

src/format/parsed.rs#L918

Added line #L918 was not covered by tests
MappedLocalTime::Single(t) => {
if check_offset(&t) {
Ok(t)
} else {
Err(IMPOSSIBLE)
}
}
LocalResult::Ambiguous(min, max) => {
MappedLocalTime::Ambiguous(min, max) => {

Check warning on line 926 in src/format/parsed.rs

View check run for this annotation

Codecov / codecov/patch

src/format/parsed.rs#L926

Added line #L926 was not covered by tests
// try to disambiguate two possible local dates by offset.
match (check_offset(&min), check_offset(&max)) {
(false, false) => Err(IMPOSSIBLE),
Expand Down
18 changes: 11 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! * The [`DateTime`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) type is timezone-aware
//! by default, with separate timezone-naive types.
//! * Operations that may produce an invalid or ambiguous date and time return `Option` or
//! [`LocalResult`](https://docs.rs/chrono/latest/chrono/offset/enum.LocalResult.html).
//! [`MappedLocalTime`](https://docs.rs/chrono/latest/chrono/offset/enum.MappedLocalTime.html).
//! * Configurable parsing and formatting with a `strftime` inspired date and time formatting syntax.
//! * The [`Local`](https://docs.rs/chrono/latest/chrono/offset/struct.Local.html) timezone works with
//! the current timezone of the OS.
Expand Down Expand Up @@ -129,7 +129,7 @@
//!
#![cfg_attr(not(feature = "now"), doc = "```ignore")]
#![cfg_attr(feature = "now", doc = "```rust")]
//! use chrono::offset::LocalResult;
//! use chrono::offset::MappedLocalTime;
//! use chrono::prelude::*;
//!
//! # fn doctest() -> Option<()> {
Expand All @@ -147,10 +147,14 @@
//! assert_eq!(dt, NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms_nano(9, 10, 11, 12_000_000).unwrap().and_local_timezone(Utc).unwrap());
//!
//! // dynamic verification
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33),
//! LocalResult::Single(NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms(21, 15, 33).unwrap().and_utc()));
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 80, 15, 33), LocalResult::None);
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 38, 21, 15, 33), LocalResult::None);
//! assert_eq!(
//! Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33),
//! MappedLocalTime::Single(
//! NaiveDate::from_ymd(2014, 7, 8).unwrap().and_hms(21, 15, 33).unwrap().and_utc()
//! )
//! );
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 8, 80, 15, 33), MappedLocalTime::None);
//! assert_eq!(Utc.with_ymd_and_hms(2014, 7, 38, 21, 15, 33), MappedLocalTime::None);
//!
//! # #[cfg(feature = "clock")] {
//! // other time zone objects can be used to construct a local datetime.
Expand Down Expand Up @@ -512,7 +516,7 @@ pub mod offset;
#[cfg(feature = "clock")]
#[doc(inline)]
pub use offset::Local;
pub use offset::LocalResult;
pub use offset::MappedLocalTime;
#[doc(inline)]
pub use offset::{FixedOffset, Offset, TimeZone, Utc};

Expand Down
8 changes: 4 additions & 4 deletions src/naive/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use crate::format::{Fixed, Item, Numeric, Pad};
use crate::naive::{Days, IsoWeek, NaiveDate, NaiveTime};
use crate::offset::Utc;
use crate::{
expect, ok, try_err, try_ok_or, try_opt, DateTime, Datelike, Error, FixedOffset, LocalResult,
Months, TimeDelta, TimeZone, Timelike, Weekday,
expect, ok, try_err, try_ok_or, try_opt, DateTime, Datelike, Error, FixedOffset,
MappedLocalTime, Months, TimeDelta, TimeZone, Timelike, Weekday,
};

/// Tools to help serializing/deserializing `NaiveDateTime`s
Expand Down Expand Up @@ -686,7 +686,7 @@ impl NaiveDateTime {
/// This can fail in cases where the local time represented by the `NaiveDateTime`
/// is not a valid local timestamp in the target timezone due to an offset transition
/// for example if the target timezone had a change from +00:00 to +01:00
/// occuring at 2015-09-05 22:59:59, then a local time of 2015-09-05 23:56:04
/// occurring at 2015-09-05 22:59:59, then a local time of 2015-09-05 23:56:04
/// could never occur. Similarly, if the offset transitioned in the opposite direction
/// then there would be two local times of 2015-09-05 23:56:04, one at +00:00 and one
/// at +01:00.
Expand All @@ -706,7 +706,7 @@ impl NaiveDateTime {
/// assert_eq!(dt.timezone(), tz);
/// ```
#[must_use]
pub fn and_local_timezone<Tz: TimeZone>(&self, tz: Tz) -> LocalResult<DateTime<Tz>> {
pub fn and_local_timezone<Tz: TimeZone>(&self, tz: Tz) -> MappedLocalTime<DateTime<Tz>> {
tz.from_local_datetime(self)
}

Expand Down
6 changes: 3 additions & 3 deletions src/naive/datetime/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::NaiveDateTime;
use crate::{Datelike, Error, FixedOffset, LocalResult, NaiveDate, TimeDelta, Utc};
use crate::{Datelike, Error, FixedOffset, MappedLocalTime, NaiveDate, TimeDelta, Utc};

#[test]
fn test_datetime_add() -> Result<(), Error> {
Expand Down Expand Up @@ -385,13 +385,13 @@ fn test_and_timezone_min_max_dates() {
if offset_hour >= 0 {
assert_eq!(local_max.unwrap().naive_local(), NaiveDateTime::MAX);
} else {
assert_eq!(local_max, LocalResult::None);
assert_eq!(local_max, MappedLocalTime::None);
}
let local_min = NaiveDateTime::MIN.and_local_timezone(offset);
if offset_hour <= 0 {
assert_eq!(local_min.unwrap().naive_local(), NaiveDateTime::MIN);
} else {
assert_eq!(local_min, LocalResult::None);
assert_eq!(local_min, MappedLocalTime::None);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/offset/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use core::str::FromStr;
#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
use rkyv::{Archive, Deserialize, Serialize};

use super::{LocalResult, Offset, TimeZone};
use super::{MappedLocalTime, Offset, TimeZone};
use crate::format::{scan, OUT_OF_RANGE};
use crate::{Error, NaiveDateTime, ParseError};

Expand Down Expand Up @@ -113,8 +113,8 @@ impl TimeZone for FixedOffset {
*offset
}

fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult<FixedOffset> {
LocalResult::Single(*self)
fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> MappedLocalTime<FixedOffset> {
MappedLocalTime::Single(*self)
}

fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> FixedOffset {
Expand Down
Loading

0 comments on commit d286f93

Please sign in to comment.