mirror of
https://github.com/chronotope/chrono.git
synced 2025-09-30 22:42:08 +00:00
Merge 0.4.x into main
This commit is contained in:
commit
b1ab498363
@ -33,6 +33,7 @@ pure-rust-locales = { version = "0.5.2", optional = true }
|
|||||||
criterion = { version = "0.4.0", optional = true }
|
criterion = { version = "0.4.0", optional = true }
|
||||||
rkyv = {version = "0.7", optional = true}
|
rkyv = {version = "0.7", optional = true}
|
||||||
iana-time-zone = { version = "0.1.44", optional = true, features = ["fallback"] }
|
iana-time-zone = { version = "0.1.44", optional = true, features = ["fallback"] }
|
||||||
|
arbitrary = { version = "1.0.0", features = ["derive"], optional = true }
|
||||||
|
|
||||||
[target.'cfg(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi"))))'.dependencies]
|
[target.'cfg(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi"))))'.dependencies]
|
||||||
wasm-bindgen = { version = "0.2", optional = true }
|
wasm-bindgen = { version = "0.2", optional = true }
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
[![Chrono on docs.rs][docsrs-image]][docsrs]
|
[![Chrono on docs.rs][docsrs-image]][docsrs]
|
||||||
[![Join the chat at https://gitter.im/chrono-rs/chrono][gitter-image]][gitter]
|
[![Join the chat at https://gitter.im/chrono-rs/chrono][gitter-image]][gitter]
|
||||||
|
|
||||||
[gh-image]: https://github.com/chronotope/chrono/workflows/test/badge.svg
|
[gh-image]: https://github.com/chronotope/chrono/actions/workflows/test.yml/badge.svg
|
||||||
[gh-checks]: https://github.com/chronotope/chrono/actions?query=workflow%3Atest
|
[gh-checks]: https://github.com/chronotope/chrono/actions?query=workflow%3Atest
|
||||||
[cratesio-image]: https://img.shields.io/crates/v/chrono.svg
|
[cratesio-image]: https://img.shields.io/crates/v/chrono.svg
|
||||||
[cratesio]: https://crates.io/crates/chrono
|
[cratesio]: https://crates.io/crates/chrono
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||||
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use chrono::{DateTime, FixedOffset, Utc, __BenchYearFlags};
|
use chrono::{DateTime, FixedOffset, Local, Utc, __BenchYearFlags};
|
||||||
|
|
||||||
fn bench_datetime_parse_from_rfc2822(c: &mut Criterion) {
|
fn bench_datetime_parse_from_rfc2822(c: &mut Criterion) {
|
||||||
c.bench_function("bench_datetime_parse_from_rfc2822", |b| {
|
c.bench_function("bench_datetime_parse_from_rfc2822", |b| {
|
||||||
@ -36,13 +36,27 @@ fn bench_datetime_from_str(c: &mut Criterion) {
|
|||||||
|
|
||||||
fn bench_datetime_to_rfc2822(c: &mut Criterion) {
|
fn bench_datetime_to_rfc2822(c: &mut Criterion) {
|
||||||
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
||||||
let dt = pst.ymd_opt(2018, 1, 11).unwrap().and_hms_nano_opt(10, 5, 13, 84_660_000).unwrap();
|
let dt = pst
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2018, 1, 11)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(10, 5, 13, 84_660_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
c.bench_function("bench_datetime_to_rfc2822", |b| b.iter(|| black_box(dt).to_rfc2822()));
|
c.bench_function("bench_datetime_to_rfc2822", |b| b.iter(|| black_box(dt).to_rfc2822()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_datetime_to_rfc3339(c: &mut Criterion) {
|
fn bench_datetime_to_rfc3339(c: &mut Criterion) {
|
||||||
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
||||||
let dt = pst.ymd_opt(2018, 1, 11).and_hms_nano_opt(10, 5, 13, 84_660_000).unwrap();
|
let dt = pst
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2018, 1, 11)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(10, 5, 13, 84_660_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
c.bench_function("bench_datetime_to_rfc3339", |b| b.iter(|| black_box(dt).to_rfc3339()));
|
c.bench_function("bench_datetime_to_rfc3339", |b| b.iter(|| black_box(dt).to_rfc3339()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +70,14 @@ fn bench_year_flags_from_year(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bench_get_local_time(c: &mut Criterion) {
|
||||||
|
c.bench_function("bench_get_local_time", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let _ = Local::now();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the number of multiples of `div` in the range `start..end`.
|
/// Returns the number of multiples of `div` in the range `start..end`.
|
||||||
///
|
///
|
||||||
/// If the range `start..end` is back-to-front, i.e. `start` is greater than `end`, the
|
/// If the range `start..end` is back-to-front, i.e. `start` is greater than `end`, the
|
||||||
@ -109,6 +131,7 @@ criterion_group!(
|
|||||||
bench_datetime_to_rfc3339,
|
bench_datetime_to_rfc3339,
|
||||||
bench_year_flags_from_year,
|
bench_year_flags_from_year,
|
||||||
bench_num_days_from_ce,
|
bench_num_days_from_ce,
|
||||||
|
bench_get_local_time,
|
||||||
);
|
);
|
||||||
|
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
|
|
||||||
pub fn create_time() {
|
pub fn create_time() {
|
||||||
let _ = Utc.ymd_opt(2019, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
|
let _ = Utc.with_ymd_and_hms(2019, 1, 1, 0, 0, 0).unwrap();
|
||||||
}
|
}
|
||||||
|
42
src/date.rs
42
src/date.rs
@ -2,6 +2,7 @@
|
|||||||
// See README.md and LICENSE.txt for details.
|
// See README.md and LICENSE.txt for details.
|
||||||
|
|
||||||
//! ISO 8601 calendar date with time zone.
|
//! ISO 8601 calendar date with time zone.
|
||||||
|
#![allow(deprecated)]
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
@ -53,6 +54,7 @@ use crate::{Datelike, Weekday};
|
|||||||
/// - The date is timezone-agnostic up to one day (i.e. practically always),
|
/// - 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
|
/// so the local date and UTC date should be equal for most cases
|
||||||
/// even though the raw calculation between `NaiveDate` and `Duration` may not.
|
/// even though the raw calculation between `NaiveDate` and `Duration` may not.
|
||||||
|
#[deprecated(since = "0.4.23", note = "Use `NaiveDate` or `DateTime<Tz>` instead")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
||||||
pub struct Date<Tz: TimeZone> {
|
pub struct Date<Tz: TimeZone> {
|
||||||
@ -288,15 +290,7 @@ impl<Tz: TimeZone> Date<Tz> {
|
|||||||
|
|
||||||
/// Returns the number of whole years from the given `base` until `self`.
|
/// Returns the number of whole years from the given `base` until `self`.
|
||||||
pub fn years_since(&self, base: Self) -> Option<u32> {
|
pub fn years_since(&self, base: Self) -> Option<u32> {
|
||||||
let mut years = self.year() - base.year();
|
self.date.years_since(base.date)
|
||||||
if (self.month(), self.day()) < (base.month(), base.day()) {
|
|
||||||
years -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
match years >= 0 {
|
|
||||||
true => Some(years as u32),
|
|
||||||
false => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The minimum possible `Date`.
|
/// The minimum possible `Date`.
|
||||||
@ -332,15 +326,6 @@ where
|
|||||||
/// Formats the date with the specified format string.
|
/// Formats the date with the specified format string.
|
||||||
/// See the [`crate::format::strftime`] module
|
/// See the [`crate::format::strftime`] module
|
||||||
/// on the supported escape sequences.
|
/// on the supported escape sequences.
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```rust
|
|
||||||
/// use chrono::prelude::*;
|
|
||||||
///
|
|
||||||
/// let date_time: Date<Utc> = Utc.ymd_opt(2017, 04, 02).unwrap();
|
|
||||||
/// let formatted = format!("{}", date_time.format("%d/%m/%Y"));
|
|
||||||
/// assert_eq!(formatted, "02/04/2017");
|
|
||||||
/// ```
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -532,7 +517,8 @@ impl<Tz: TimeZone> Sub<Date<Tz>> for Date<Tz> {
|
|||||||
|
|
||||||
impl<Tz: TimeZone> fmt::Debug for Date<Tz> {
|
impl<Tz: TimeZone> fmt::Debug for Date<Tz> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{:?}{:?}", self.naive_local(), self.offset)
|
self.naive_local().fmt(f)?;
|
||||||
|
self.offset.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,7 +527,23 @@ where
|
|||||||
Tz::Offset: fmt::Display,
|
Tz::Offset: fmt::Display,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}{}", self.naive_local(), self.offset)
|
self.naive_local().fmt(f)?;
|
||||||
|
self.offset.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that implementation of Arbitrary cannot be automatically derived for Date<Tz>, due to
|
||||||
|
// the nontrivial bound <Tz as TimeZone>::Offset: Arbitrary.
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
impl<'a, Tz> arbitrary::Arbitrary<'a> for Date<Tz>
|
||||||
|
where
|
||||||
|
Tz: TimeZone,
|
||||||
|
<Tz as TimeZone>::Offset: arbitrary::Arbitrary<'a>,
|
||||||
|
{
|
||||||
|
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Date<Tz>> {
|
||||||
|
let date = NaiveDate::arbitrary(u)?;
|
||||||
|
let offset = <Tz as TimeZone>::Offset::arbitrary(u)?;
|
||||||
|
Ok(Date::from_utc(date, offset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use alloc::string::{String, ToString};
|
|||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
|
use core::fmt::Write;
|
||||||
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||||
use core::{fmt, hash, str};
|
use core::{fmt, hash, str};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -31,7 +32,9 @@ use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
|
|||||||
#[cfg(feature = "clock")]
|
#[cfg(feature = "clock")]
|
||||||
use crate::offset::Local;
|
use crate::offset::Local;
|
||||||
use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
|
use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
|
||||||
use crate::{Date, Datelike, Months, TimeDelta, Timelike, Weekday};
|
#[allow(deprecated)]
|
||||||
|
use crate::Date;
|
||||||
|
use crate::{Datelike, Months, TimeDelta, Timelike, Weekday};
|
||||||
|
|
||||||
/// documented at re-export site
|
/// documented at re-export site
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
@ -145,18 +148,9 @@ impl<Tz: TimeZone> DateTime<Tz> {
|
|||||||
/// Unless you are immediately planning on turning this into a `DateTime`
|
/// Unless you are immediately planning on turning this into a `DateTime`
|
||||||
/// with the same Timezone you should use the
|
/// with the same Timezone you should use the
|
||||||
/// [`date_naive`](DateTime::date_naive) method.
|
/// [`date_naive`](DateTime::date_naive) method.
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use chrono::prelude::*;
|
|
||||||
///
|
|
||||||
/// let date: Date<Utc> = Utc.ymd_opt(2020, 1, 1).unwrap();
|
|
||||||
/// let dt: DateTime<Utc> = date.and_hms_opt(0, 0, 0).unwrap();
|
|
||||||
///
|
|
||||||
/// assert_eq!(dt.date(), date);
|
|
||||||
///
|
|
||||||
/// assert_eq!(dt.date().and_hms_opt(1, 1, 1).unwrap(), date.and_hms_opt(1, 1, 1).unwrap());
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[deprecated(since = "0.4.23", note = "Use `date_naive()` instead")]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub fn date(&self) -> Date<Tz> {
|
pub fn date(&self) -> Date<Tz> {
|
||||||
Date::from_utc(self.naive_local().date(), self.offset.clone())
|
Date::from_utc(self.naive_local().date(), self.offset.clone())
|
||||||
}
|
}
|
||||||
@ -169,8 +163,8 @@ impl<Tz: TimeZone> DateTime<Tz> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use chrono::prelude::*;
|
/// use chrono::prelude::*;
|
||||||
///
|
///
|
||||||
/// let date: DateTime<Utc> = Utc.ymd_opt(2020, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
|
/// let date: DateTime<Utc> = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap();
|
||||||
/// let other: DateTime<FixedOffset> = FixedOffset::east_opt(23).unwrap().ymd_opt(2020, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
|
/// let other: DateTime<FixedOffset> = FixedOffset::east_opt(23).unwrap().with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap();
|
||||||
/// assert_eq!(date.date_naive(), other.date_naive());
|
/// assert_eq!(date.date_naive(), other.date_naive());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -203,13 +197,12 @@ impl<Tz: TimeZone> DateTime<Tz> {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use chrono::Utc;
|
/// use chrono::{Utc, TimeZone, NaiveDate};
|
||||||
/// use chrono::TimeZone;
|
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 444).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.timestamp_millis(), 1_444);
|
/// assert_eq!(dt.timestamp_millis(), 1_444);
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(2001, 9, 9).unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
|
/// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -227,13 +220,12 @@ impl<Tz: TimeZone> DateTime<Tz> {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use chrono::Utc;
|
/// use chrono::{Utc, TimeZone, NaiveDate};
|
||||||
/// use chrono::TimeZone;
|
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_micro_opt(0, 0, 1, 444).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_micro_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.timestamp_micros(), 1_000_444);
|
/// assert_eq!(dt.timestamp_micros(), 1_000_444);
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(2001, 9, 9).unwrap().and_hms_micro_opt(1, 46, 40, 555).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_micro_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555);
|
/// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -251,13 +243,12 @@ impl<Tz: TimeZone> DateTime<Tz> {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use chrono::Utc;
|
/// use chrono::{Utc, TimeZone, NaiveDate};
|
||||||
/// use chrono::TimeZone;
|
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_nano_opt(0, 0, 1, 444).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_nano_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.timestamp_nanos(), 1_000_000_444);
|
/// assert_eq!(dt.timestamp_nanos(), 1_000_000_444);
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 40, 555).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555);
|
/// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -533,10 +524,10 @@ impl DateTime<FixedOffset> {
|
|||||||
/// and email headers.
|
/// and email headers.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use chrono::{DateTime, FixedOffset, TimeZone};
|
/// # use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate};
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(),
|
/// DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(),
|
||||||
/// FixedOffset::east_opt(0).unwrap().ymd_opt(2015, 2, 18).unwrap().and_hms_opt(23, 16, 9).unwrap()
|
/// FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
@ -579,11 +570,11 @@ impl DateTime<FixedOffset> {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use chrono::{DateTime, FixedOffset, TimeZone};
|
/// use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate};
|
||||||
///
|
///
|
||||||
/// let dt = DateTime::<FixedOffset>::parse_from_str(
|
/// let dt = DateTime::<FixedOffset>::parse_from_str(
|
||||||
/// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z");
|
/// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z");
|
||||||
/// assert_eq!(dt, Ok(FixedOffset::east_opt(0).unwrap().ymd_opt(1983, 4, 13).unwrap().and_hms_milli_opt(12, 9, 14, 274).unwrap()));
|
/// assert_eq!(dt, Ok(FixedOffset::east_opt(0).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(1983, 4, 13).unwrap().and_hms_milli_opt(12, 9, 14, 274).unwrap()).unwrap()));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<DateTime<FixedOffset>> {
|
pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
@ -656,16 +647,20 @@ where
|
|||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
|
||||||
pub fn to_rfc2822(&self) -> String {
|
pub fn to_rfc2822(&self) -> String {
|
||||||
const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
|
let mut result = String::with_capacity(32);
|
||||||
self.format_with_items(ITEMS.iter()).to_string()
|
crate::format::write_rfc2822(&mut result, self.naive_local(), self.offset.fix())
|
||||||
|
.expect("writing rfc2822 datetime to string should never fail");
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
|
/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
|
||||||
pub fn to_rfc3339(&self) -> String {
|
pub fn to_rfc3339(&self) -> String {
|
||||||
const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
|
let mut result = String::with_capacity(32);
|
||||||
self.format_with_items(ITEMS.iter()).to_string()
|
crate::format::write_rfc3339(&mut result, self.naive_local(), self.offset.fix())
|
||||||
|
.expect("writing rfc3339 datetime to string should never fail");
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an RFC 3339 and ISO 8601 date and time string with subseconds
|
/// Return an RFC 3339 and ISO 8601 date and time string with subseconds
|
||||||
@ -678,8 +673,8 @@ where
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc};
|
/// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate};
|
||||||
/// let dt = Utc.ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(18, 30, 9, 453_829).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(18, 30, 9, 453_829).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false),
|
/// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false),
|
||||||
/// "2018-01-26T18:30:09.453+00:00");
|
/// "2018-01-26T18:30:09.453+00:00");
|
||||||
/// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true),
|
/// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true),
|
||||||
@ -688,7 +683,7 @@ where
|
|||||||
/// "2018-01-26T18:30:09Z");
|
/// "2018-01-26T18:30:09Z");
|
||||||
///
|
///
|
||||||
/// let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
/// let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
||||||
/// let dt = pst.ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(10, 30, 9, 453_829).unwrap();
|
/// let dt = pst.from_local_datetime(&NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(10, 30, 9, 453_829).unwrap()).unwrap();
|
||||||
/// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
|
/// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
|
||||||
/// "2018-01-26T10:30:09+08:00");
|
/// "2018-01-26T10:30:09+08:00");
|
||||||
/// ```
|
/// ```
|
||||||
@ -757,7 +752,7 @@ where
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// use chrono::prelude::*;
|
/// use chrono::prelude::*;
|
||||||
///
|
///
|
||||||
/// let date_time: DateTime<Utc> = Utc.ymd_opt(2017, 04, 02).unwrap().and_hms_opt(12, 50, 32).unwrap();
|
/// let date_time: DateTime<Utc> = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap();
|
||||||
/// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
|
/// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
|
||||||
/// assert_eq!(formatted, "02/04/2017 12:50");
|
/// assert_eq!(formatted, "02/04/2017 12:50");
|
||||||
/// ```
|
/// ```
|
||||||
@ -941,8 +936,8 @@ impl<Tz: TimeZone, Tz2: TimeZone> PartialOrd<DateTime<Tz2>> for DateTime<Tz> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use chrono::prelude::*;
|
/// use chrono::prelude::*;
|
||||||
///
|
///
|
||||||
/// let earlier = Utc.ymd_opt(2015, 5, 15).unwrap().and_hms_opt(2, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(1 * 3600).unwrap());
|
/// let earlier = Utc.with_ymd_and_hms(2015, 5, 15, 2, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(1 * 3600).unwrap());
|
||||||
/// let later = Utc.ymd_opt(2015, 5, 15).unwrap().and_hms_opt(3, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(5 * 3600).unwrap());
|
/// let later = Utc.with_ymd_and_hms(2015, 5, 15, 3, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(5 * 3600).unwrap());
|
||||||
///
|
///
|
||||||
/// assert_eq!(earlier.to_string(), "2015-05-15 01:00:00 -01:00");
|
/// assert_eq!(earlier.to_string(), "2015-05-15 01:00:00 -01:00");
|
||||||
/// assert_eq!(later.to_string(), "2015-05-14 22:00:00 -05:00");
|
/// assert_eq!(later.to_string(), "2015-05-14 22:00:00 -05:00");
|
||||||
@ -1047,7 +1042,8 @@ impl<Tz: TimeZone> Sub<Days> for DateTime<Tz> {
|
|||||||
|
|
||||||
impl<Tz: TimeZone> fmt::Debug for DateTime<Tz> {
|
impl<Tz: TimeZone> fmt::Debug for DateTime<Tz> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{:?}{:?}", self.naive_local(), self.offset)
|
self.naive_local().fmt(f)?;
|
||||||
|
self.offset.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1056,7 +1052,9 @@ where
|
|||||||
Tz::Offset: fmt::Display,
|
Tz::Offset: fmt::Display,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} {}", self.naive_local(), self.offset)
|
self.naive_local().fmt(f)?;
|
||||||
|
f.write_char(' ')?;
|
||||||
|
self.offset.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1207,49 +1205,44 @@ impl From<DateTime<Utc>> for js_sys::Date {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note that implementation of Arbitrary cannot be simply derived for DateTime<Tz>, due to
|
||||||
|
// the nontrivial bound <Tz as TimeZone>::Offset: Arbitrary.
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
impl<'a, Tz> arbitrary::Arbitrary<'a> for DateTime<Tz>
|
||||||
|
where
|
||||||
|
Tz: TimeZone,
|
||||||
|
<Tz as TimeZone>::Offset: arbitrary::Arbitrary<'a>,
|
||||||
|
{
|
||||||
|
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<DateTime<Tz>> {
|
||||||
|
let datetime = NaiveDateTime::arbitrary(u)?;
|
||||||
|
let offset = <Tz as TimeZone>::Offset::arbitrary(u)?;
|
||||||
|
Ok(DateTime::from_utc(datetime, offset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_sub_months() {
|
fn test_add_sub_months() {
|
||||||
let utc_dt = Utc.ymd_opt(2018, 9, 5).unwrap().and_hms_opt(23, 58, 0).unwrap();
|
let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(utc_dt + Months::new(15), Utc.with_ymd_and_hms(2019, 12, 5, 23, 58, 0).unwrap());
|
||||||
utc_dt + Months::new(15),
|
|
||||||
Utc.ymd_opt(2019, 12, 5).unwrap().and_hms_opt(23, 58, 0).unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let utc_dt = Utc.ymd_opt(2020, 1, 31).unwrap().and_hms_opt(23, 58, 0).unwrap();
|
let utc_dt = Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(utc_dt + Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap());
|
||||||
utc_dt + Months::new(1),
|
assert_eq!(utc_dt + Months::new(2), Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap());
|
||||||
Utc.ymd_opt(2020, 2, 29).unwrap().and_hms_opt(23, 58, 0).unwrap()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
utc_dt + Months::new(2),
|
|
||||||
Utc.ymd_opt(2020, 3, 31).unwrap().and_hms_opt(23, 58, 0).unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let utc_dt = Utc.ymd_opt(2018, 9, 5).unwrap().and_hms_opt(23, 58, 0).unwrap();
|
let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(utc_dt - Months::new(15), Utc.with_ymd_and_hms(2017, 6, 5, 23, 58, 0).unwrap());
|
||||||
utc_dt - Months::new(15),
|
|
||||||
Utc.ymd_opt(2017, 6, 5).unwrap().and_hms_opt(23, 58, 0).unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let utc_dt = Utc.ymd_opt(2020, 3, 31).unwrap().and_hms_opt(23, 58, 0).unwrap();
|
let utc_dt = Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(utc_dt - Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap());
|
||||||
utc_dt - Months::new(1),
|
assert_eq!(utc_dt - Months::new(2), Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap());
|
||||||
Utc.ymd_opt(2020, 2, 29).unwrap().and_hms_opt(23, 58, 0).unwrap()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
utc_dt - Months::new(2),
|
|
||||||
Utc.ymd_opt(2020, 1, 31).unwrap().and_hms_opt(23, 58, 0).unwrap()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_auto_conversion() {
|
fn test_auto_conversion() {
|
||||||
let utc_dt = Utc.ymd_opt(2018, 9, 5).unwrap().and_hms_opt(23, 58, 0).unwrap();
|
let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap();
|
||||||
let cdt_dt = FixedOffset::west_opt(5 * 60 * 60)
|
let cdt_dt = FixedOffset::west_opt(5 * 60 * 60)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2018, 9, 5)
|
.with_ymd_and_hms(2018, 9, 5, 18, 58, 0)
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(18, 58, 0)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let utc_dt2: DateTime<Utc> = cdt_dt.into();
|
let utc_dt2: DateTime<Utc> = cdt_dt.into();
|
||||||
assert_eq!(utc_dt, utc_dt2);
|
assert_eq!(utc_dt, utc_dt2);
|
||||||
@ -1263,30 +1256,20 @@ where
|
|||||||
E: ::core::fmt::Debug,
|
E: ::core::fmt::Debug,
|
||||||
{
|
{
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_string_utc(&Utc.ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()).ok(),
|
to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(),
|
||||||
Some(r#""2014-07-24T12:34:06Z""#.into())
|
Some(r#""2014-07-24T12:34:06Z""#.into())
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_string_fixed(
|
to_string_fixed(
|
||||||
&FixedOffset::east_opt(3660)
|
&FixedOffset::east_opt(3660).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
|
||||||
.unwrap()
|
|
||||||
.ymd_opt(2014, 7, 24)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(12, 34, 6)
|
|
||||||
.unwrap()
|
|
||||||
)
|
)
|
||||||
.ok(),
|
.ok(),
|
||||||
Some(r#""2014-07-24T12:34:06+01:01""#.into())
|
Some(r#""2014-07-24T12:34:06+01:01""#.into())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_string_fixed(
|
to_string_fixed(
|
||||||
&FixedOffset::east_opt(3650)
|
&FixedOffset::east_opt(3650).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
|
||||||
.unwrap()
|
|
||||||
.ymd_opt(2014, 7, 24)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(12, 34, 6)
|
|
||||||
.unwrap()
|
|
||||||
)
|
)
|
||||||
.ok(),
|
.ok(),
|
||||||
Some(r#""2014-07-24T12:34:06+01:00:50""#.into())
|
Some(r#""2014-07-24T12:34:06+01:00:50""#.into())
|
||||||
@ -1311,22 +1294,17 @@ fn test_decodable_json<FUtc, FFixed, FLocal, E>(
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
|
norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
|
||||||
norm(&Some(Utc.ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()))
|
norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
|
norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
|
||||||
norm(&Some(Utc.ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()))
|
norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
|
norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
|
||||||
norm(&Some(
|
norm(&Some(
|
||||||
FixedOffset::east_opt(0)
|
FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
|
||||||
.unwrap()
|
|
||||||
.ymd_opt(2014, 7, 24)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(12, 34, 6)
|
|
||||||
.unwrap()
|
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1334,9 +1312,7 @@ fn test_decodable_json<FUtc, FFixed, FLocal, E>(
|
|||||||
norm(&Some(
|
norm(&Some(
|
||||||
FixedOffset::east_opt(60 * 60 + 23 * 60)
|
FixedOffset::east_opt(60 * 60 + 23 * 60)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2014, 7, 24)
|
.with_ymd_and_hms(2014, 7, 24, 13, 57, 6)
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(13, 57, 6)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
@ -1345,11 +1321,11 @@ fn test_decodable_json<FUtc, FFixed, FLocal, E>(
|
|||||||
// the conversion didn't change the instant itself
|
// the conversion didn't change the instant itself
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local shouuld parse"),
|
local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local shouuld parse"),
|
||||||
Utc.ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()
|
Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
local_from_str(r#""2014-07-24T13:57:06+01:23""#).expect("local should parse with offset"),
|
local_from_str(r#""2014-07-24T13:57:06+01:23""#).expect("local should parse with offset"),
|
||||||
Utc.ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()
|
Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
|
assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
|
||||||
|
@ -106,7 +106,7 @@ impl<'de> de::Deserialize<'de> for DateTime<Local> {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::{Deserialize, Serialize};
|
/// # use serde_derive::{Deserialize, Serialize};
|
||||||
/// use chrono::serde::ts_nanoseconds;
|
/// use chrono::serde::ts_nanoseconds;
|
||||||
/// #[derive(Deserialize, Serialize)]
|
/// #[derive(Deserialize, Serialize)]
|
||||||
@ -115,7 +115,7 @@ impl<'de> de::Deserialize<'de> for DateTime<Local> {
|
|||||||
/// time: DateTime<Utc>
|
/// time: DateTime<Utc>
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let time = Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap();
|
/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: time.clone(),
|
/// time: time.clone(),
|
||||||
/// };
|
/// };
|
||||||
@ -142,7 +142,7 @@ pub mod ts_nanoseconds {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::Serialize;
|
/// # use serde_derive::Serialize;
|
||||||
/// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts;
|
/// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts;
|
||||||
/// #[derive(Serialize)]
|
/// #[derive(Serialize)]
|
||||||
@ -152,7 +152,7 @@ pub mod ts_nanoseconds {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap(),
|
/// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap(),
|
||||||
/// };
|
/// };
|
||||||
/// let as_string = serde_json::to_string(&my_s)?;
|
/// let as_string = serde_json::to_string(&my_s)?;
|
||||||
/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
|
/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
|
||||||
@ -231,7 +231,7 @@ pub mod ts_nanoseconds {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::{Deserialize, Serialize};
|
/// # use serde_derive::{Deserialize, Serialize};
|
||||||
/// use chrono::serde::ts_nanoseconds_option;
|
/// use chrono::serde::ts_nanoseconds_option;
|
||||||
/// #[derive(Deserialize, Serialize)]
|
/// #[derive(Deserialize, Serialize)]
|
||||||
@ -240,7 +240,7 @@ pub mod ts_nanoseconds {
|
|||||||
/// time: Option<DateTime<Utc>>
|
/// time: Option<DateTime<Utc>>
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let time = Some(Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap());
|
/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap());
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: time.clone(),
|
/// time: time.clone(),
|
||||||
/// };
|
/// };
|
||||||
@ -266,7 +266,7 @@ pub mod ts_nanoseconds_option {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::Serialize;
|
/// # use serde_derive::Serialize;
|
||||||
/// use chrono::serde::ts_nanoseconds_option::serialize as to_nano_tsopt;
|
/// use chrono::serde::ts_nanoseconds_option::serialize as to_nano_tsopt;
|
||||||
/// #[derive(Serialize)]
|
/// #[derive(Serialize)]
|
||||||
@ -276,7 +276,7 @@ pub mod ts_nanoseconds_option {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: Some(Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap()),
|
/// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_nano_opt(02, 04, 59, 918355733).unwrap().and_local_timezone(Utc).unwrap()),
|
||||||
/// };
|
/// };
|
||||||
/// let as_string = serde_json::to_string(&my_s)?;
|
/// let as_string = serde_json::to_string(&my_s)?;
|
||||||
/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
|
/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
|
||||||
@ -360,7 +360,7 @@ pub mod ts_nanoseconds_option {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::{Deserialize, Serialize};
|
/// # use serde_derive::{Deserialize, Serialize};
|
||||||
/// use chrono::serde::ts_microseconds;
|
/// use chrono::serde::ts_microseconds;
|
||||||
/// #[derive(Deserialize, Serialize)]
|
/// #[derive(Deserialize, Serialize)]
|
||||||
@ -369,7 +369,7 @@ pub mod ts_nanoseconds_option {
|
|||||||
/// time: DateTime<Utc>
|
/// time: DateTime<Utc>
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let time = Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap();
|
/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: time.clone(),
|
/// time: time.clone(),
|
||||||
/// };
|
/// };
|
||||||
@ -395,7 +395,7 @@ pub mod ts_microseconds {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::Serialize;
|
/// # use serde_derive::Serialize;
|
||||||
/// use chrono::serde::ts_microseconds::serialize as to_micro_ts;
|
/// use chrono::serde::ts_microseconds::serialize as to_micro_ts;
|
||||||
/// #[derive(Serialize)]
|
/// #[derive(Serialize)]
|
||||||
@ -405,7 +405,7 @@ pub mod ts_microseconds {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap(),
|
/// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap(),
|
||||||
/// };
|
/// };
|
||||||
/// let as_string = serde_json::to_string(&my_s)?;
|
/// let as_string = serde_json::to_string(&my_s)?;
|
||||||
/// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
|
/// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
|
||||||
@ -484,7 +484,7 @@ pub mod ts_microseconds {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::{Deserialize, Serialize};
|
/// # use serde_derive::{Deserialize, Serialize};
|
||||||
/// use chrono::serde::ts_microseconds_option;
|
/// use chrono::serde::ts_microseconds_option;
|
||||||
/// #[derive(Deserialize, Serialize)]
|
/// #[derive(Deserialize, Serialize)]
|
||||||
@ -493,7 +493,7 @@ pub mod ts_microseconds {
|
|||||||
/// time: Option<DateTime<Utc>>
|
/// time: Option<DateTime<Utc>>
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let time = Some(Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap());
|
/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap());
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: time.clone(),
|
/// time: time.clone(),
|
||||||
/// };
|
/// };
|
||||||
@ -518,7 +518,7 @@ pub mod ts_microseconds_option {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::Serialize;
|
/// # use serde_derive::Serialize;
|
||||||
/// use chrono::serde::ts_microseconds_option::serialize as to_micro_tsopt;
|
/// use chrono::serde::ts_microseconds_option::serialize as to_micro_tsopt;
|
||||||
/// #[derive(Serialize)]
|
/// #[derive(Serialize)]
|
||||||
@ -528,7 +528,7 @@ pub mod ts_microseconds_option {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: Some(Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap()),
|
/// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_micro_opt(02, 04, 59, 918355).unwrap().and_local_timezone(Utc).unwrap()),
|
||||||
/// };
|
/// };
|
||||||
/// let as_string = serde_json::to_string(&my_s)?;
|
/// let as_string = serde_json::to_string(&my_s)?;
|
||||||
/// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
|
/// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
|
||||||
@ -612,7 +612,7 @@ pub mod ts_microseconds_option {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::{Deserialize, Serialize};
|
/// # use serde_derive::{Deserialize, Serialize};
|
||||||
/// use chrono::serde::ts_milliseconds;
|
/// use chrono::serde::ts_milliseconds;
|
||||||
/// #[derive(Deserialize, Serialize)]
|
/// #[derive(Deserialize, Serialize)]
|
||||||
@ -621,7 +621,7 @@ pub mod ts_microseconds_option {
|
|||||||
/// time: DateTime<Utc>
|
/// time: DateTime<Utc>
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let time = Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap();
|
/// let time = NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: time.clone(),
|
/// time: time.clone(),
|
||||||
/// };
|
/// };
|
||||||
@ -647,7 +647,7 @@ pub mod ts_milliseconds {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::Serialize;
|
/// # use serde_derive::Serialize;
|
||||||
/// use chrono::serde::ts_milliseconds::serialize as to_milli_ts;
|
/// use chrono::serde::ts_milliseconds::serialize as to_milli_ts;
|
||||||
/// #[derive(Serialize)]
|
/// #[derive(Serialize)]
|
||||||
@ -657,7 +657,7 @@ pub mod ts_milliseconds {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap(),
|
/// time: NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap(),
|
||||||
/// };
|
/// };
|
||||||
/// let as_string = serde_json::to_string(&my_s)?;
|
/// let as_string = serde_json::to_string(&my_s)?;
|
||||||
/// assert_eq!(as_string, r#"{"time":1526522699918}"#);
|
/// assert_eq!(as_string, r#"{"time":1526522699918}"#);
|
||||||
@ -733,7 +733,7 @@ pub mod ts_milliseconds {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::{Deserialize, Serialize};
|
/// # use serde_derive::{Deserialize, Serialize};
|
||||||
/// use chrono::serde::ts_milliseconds_option;
|
/// use chrono::serde::ts_milliseconds_option;
|
||||||
/// #[derive(Deserialize, Serialize)]
|
/// #[derive(Deserialize, Serialize)]
|
||||||
@ -742,7 +742,7 @@ pub mod ts_milliseconds {
|
|||||||
/// time: Option<DateTime<Utc>>
|
/// time: Option<DateTime<Utc>>
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let time = Some(Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap());
|
/// let time = Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap());
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: time.clone(),
|
/// time: time.clone(),
|
||||||
/// };
|
/// };
|
||||||
@ -767,7 +767,7 @@ pub mod ts_milliseconds_option {
|
|||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use chrono::{TimeZone, DateTime, Utc};
|
/// # use chrono::{TimeZone, DateTime, Utc, NaiveDate};
|
||||||
/// # use serde_derive::Serialize;
|
/// # use serde_derive::Serialize;
|
||||||
/// use chrono::serde::ts_milliseconds_option::serialize as to_milli_tsopt;
|
/// use chrono::serde::ts_milliseconds_option::serialize as to_milli_tsopt;
|
||||||
/// #[derive(Serialize)]
|
/// #[derive(Serialize)]
|
||||||
@ -777,7 +777,7 @@ pub mod ts_milliseconds_option {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: Some(Utc.ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap()),
|
/// time: Some(NaiveDate::from_ymd_opt(2018, 5, 17).unwrap().and_hms_milli_opt(02, 04, 59, 918).unwrap().and_local_timezone(Utc).unwrap()),
|
||||||
/// };
|
/// };
|
||||||
/// let as_string = serde_json::to_string(&my_s)?;
|
/// let as_string = serde_json::to_string(&my_s)?;
|
||||||
/// assert_eq!(as_string, r#"{"time":1526522699918}"#);
|
/// assert_eq!(as_string, r#"{"time":1526522699918}"#);
|
||||||
@ -883,7 +883,7 @@ pub mod ts_milliseconds_option {
|
|||||||
/// time: DateTime<Utc>
|
/// time: DateTime<Utc>
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let time = Utc.ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap();
|
/// let time = Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap();
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: time.clone(),
|
/// time: time.clone(),
|
||||||
/// };
|
/// };
|
||||||
@ -919,7 +919,7 @@ pub mod ts_seconds {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: Utc.ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap(),
|
/// time: Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(),
|
||||||
/// };
|
/// };
|
||||||
/// let as_string = serde_json::to_string(&my_s)?;
|
/// let as_string = serde_json::to_string(&my_s)?;
|
||||||
/// assert_eq!(as_string, r#"{"time":1431684000}"#);
|
/// assert_eq!(as_string, r#"{"time":1431684000}"#);
|
||||||
@ -1001,7 +1001,7 @@ pub mod ts_seconds {
|
|||||||
/// time: Option<DateTime<Utc>>
|
/// time: Option<DateTime<Utc>>
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let time = Some(Utc.ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap());
|
/// let time = Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap());
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: time.clone(),
|
/// time: time.clone(),
|
||||||
/// };
|
/// };
|
||||||
@ -1036,7 +1036,7 @@ pub mod ts_seconds_option {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let my_s = S {
|
/// let my_s = S {
|
||||||
/// time: Some(Utc.ymd_opt(2015, 5, 15).unwrap().and_hms_opt(10, 0, 0).unwrap()),
|
/// time: Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()),
|
||||||
/// };
|
/// };
|
||||||
/// let as_string = serde_json::to_string(&my_s)?;
|
/// let as_string = serde_json::to_string(&my_s)?;
|
||||||
/// assert_eq!(as_string, r#"{"time":1431684000}"#);
|
/// assert_eq!(as_string, r#"{"time":1431684000}"#);
|
||||||
@ -1134,7 +1134,7 @@ fn test_serde_bincode() {
|
|||||||
// it is not self-describing.
|
// it is not self-describing.
|
||||||
use bincode::{deserialize, serialize};
|
use bincode::{deserialize, serialize};
|
||||||
|
|
||||||
let dt = Utc.ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap();
|
let dt = Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap();
|
||||||
let encoded = serialize(&dt).unwrap();
|
let encoded = serialize(&dt).unwrap();
|
||||||
let decoded: DateTime<Utc> = deserialize(&encoded).unwrap();
|
let decoded: DateTime<Utc> = deserialize(&encoded).unwrap();
|
||||||
assert_eq!(dt, decoded);
|
assert_eq!(dt, decoded);
|
||||||
|
@ -16,96 +16,90 @@ fn test_datetime_offset() {
|
|||||||
let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap();
|
let kst = FixedOffset::east_opt(9 * 60 * 60).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", Utc.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap()),
|
format!("{}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
|
||||||
"2014-05-06 07:08:09 UTC"
|
"2014-05-06 07:08:09 UTC"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", edt.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap()),
|
format!("{}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
|
||||||
"2014-05-06 07:08:09 -04:00"
|
"2014-05-06 07:08:09 -04:00"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", kst.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap()),
|
format!("{}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
|
||||||
"2014-05-06 07:08:09 +09:00"
|
"2014-05-06 07:08:09 +09:00"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", Utc.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap()),
|
format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
|
||||||
"2014-05-06T07:08:09Z"
|
"2014-05-06T07:08:09Z"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", edt.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap()),
|
format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
|
||||||
"2014-05-06T07:08:09-04:00"
|
"2014-05-06T07:08:09-04:00"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", kst.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap()),
|
format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap()),
|
||||||
"2014-05-06T07:08:09+09:00"
|
"2014-05-06T07:08:09+09:00"
|
||||||
);
|
);
|
||||||
|
|
||||||
// edge cases
|
// edge cases
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", Utc.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(0, 0, 0).unwrap()),
|
format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()),
|
||||||
"2014-05-06T00:00:00Z"
|
"2014-05-06T00:00:00Z"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", edt.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(0, 0, 0).unwrap()),
|
format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()),
|
||||||
"2014-05-06T00:00:00-04:00"
|
"2014-05-06T00:00:00-04:00"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", kst.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(0, 0, 0).unwrap()),
|
format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 0, 0, 0).unwrap()),
|
||||||
"2014-05-06T00:00:00+09:00"
|
"2014-05-06T00:00:00+09:00"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", Utc.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(23, 59, 59).unwrap()),
|
format!("{:?}", Utc.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()),
|
||||||
"2014-05-06T23:59:59Z"
|
"2014-05-06T23:59:59Z"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", edt.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(23, 59, 59).unwrap()),
|
format!("{:?}", edt.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()),
|
||||||
"2014-05-06T23:59:59-04:00"
|
"2014-05-06T23:59:59-04:00"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", kst.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(23, 59, 59).unwrap()),
|
format!("{:?}", kst.with_ymd_and_hms(2014, 5, 6, 23, 59, 59).unwrap()),
|
||||||
"2014-05-06T23:59:59+09:00"
|
"2014-05-06T23:59:59+09:00"
|
||||||
);
|
);
|
||||||
|
|
||||||
let dt = Utc.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap();
|
let dt = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap();
|
||||||
assert_eq!(dt, edt.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(3, 8, 9).unwrap());
|
assert_eq!(dt, edt.with_ymd_and_hms(2014, 5, 6, 3, 8, 9).unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt + TimeDelta::seconds(3600 + 60 + 1),
|
dt + TimeDelta::seconds(3600 + 60 + 1),
|
||||||
Utc.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(8, 9, 10).unwrap()
|
Utc.with_ymd_and_hms(2014, 5, 6, 8, 9, 10).unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.signed_duration_since(edt.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(10, 11, 12).unwrap()),
|
dt.signed_duration_since(edt.with_ymd_and_hms(2014, 5, 6, 10, 11, 12).unwrap()),
|
||||||
TimeDelta::seconds(-7 * 3600 - 3 * 60 - 3)
|
TimeDelta::seconds(-7 * 3600 - 3 * 60 - 3)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(*Utc.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap().offset(), Utc);
|
assert_eq!(*Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset(), Utc);
|
||||||
assert_eq!(*edt.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap().offset(), edt);
|
assert_eq!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset(), edt);
|
||||||
assert!(*edt.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap().offset() != est);
|
assert!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset() != est);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_date_and_time() {
|
fn test_datetime_date_and_time() {
|
||||||
let tz = FixedOffset::east_opt(5 * 60 * 60).unwrap();
|
let tz = FixedOffset::east_opt(5 * 60 * 60).unwrap();
|
||||||
let d = tz.ymd_opt(2014, 5, 6).unwrap().and_hms_opt(7, 8, 9).unwrap();
|
let d = tz.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap();
|
||||||
assert_eq!(d.time(), NaiveTime::from_hms_opt(7, 8, 9).unwrap());
|
assert_eq!(d.time(), NaiveTime::from_hms_opt(7, 8, 9).unwrap());
|
||||||
assert_eq!(d.date(), tz.ymd_opt(2014, 5, 6).unwrap());
|
assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2014, 5, 6).unwrap());
|
||||||
assert_eq!(d.date().naive_local(), NaiveDate::from_ymd_opt(2014, 5, 6).unwrap());
|
|
||||||
assert_eq!(d.date().and_time(d.time()), Some(d));
|
|
||||||
|
|
||||||
let tz = FixedOffset::east_opt(4 * 60 * 60).unwrap();
|
let tz = FixedOffset::east_opt(4 * 60 * 60).unwrap();
|
||||||
let d = tz.ymd_opt(2016, 5, 4).unwrap().and_hms_opt(3, 2, 1).unwrap();
|
let d = tz.with_ymd_and_hms(2016, 5, 4, 3, 2, 1).unwrap();
|
||||||
assert_eq!(d.time(), NaiveTime::from_hms_opt(3, 2, 1).unwrap());
|
assert_eq!(d.time(), NaiveTime::from_hms_opt(3, 2, 1).unwrap());
|
||||||
assert_eq!(d.date(), tz.ymd_opt(2016, 5, 4).unwrap());
|
assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2016, 5, 4).unwrap());
|
||||||
assert_eq!(d.date().naive_local(), NaiveDate::from_ymd_opt(2016, 5, 4).unwrap());
|
|
||||||
assert_eq!(d.date().and_time(d.time()), Some(d));
|
|
||||||
|
|
||||||
let tz = FixedOffset::west_opt(13 * 60 * 60).unwrap();
|
let tz = FixedOffset::west_opt(13 * 60 * 60).unwrap();
|
||||||
let d = tz.ymd_opt(2017, 8, 9).unwrap().and_hms_opt(12, 34, 56).unwrap();
|
let d = tz.with_ymd_and_hms(2017, 8, 9, 12, 34, 56).unwrap();
|
||||||
assert_eq!(d.time(), NaiveTime::from_hms_opt(12, 34, 56).unwrap());
|
assert_eq!(d.time(), NaiveTime::from_hms_opt(12, 34, 56).unwrap());
|
||||||
assert_eq!(d.date(), tz.ymd_opt(2017, 8, 9).unwrap());
|
assert_eq!(d.date_naive(), NaiveDate::from_ymd_opt(2017, 8, 9).unwrap());
|
||||||
assert_eq!(d.date().naive_local(), NaiveDate::from_ymd_opt(2017, 8, 9).unwrap());
|
|
||||||
assert_eq!(d.date().and_time(d.time()), Some(d));
|
|
||||||
|
|
||||||
let utc_d = Utc.ymd_opt(2017, 8, 9).unwrap().and_hms_opt(12, 34, 56).unwrap();
|
let utc_d = Utc.with_ymd_and_hms(2017, 8, 9, 12, 34, 56).unwrap();
|
||||||
assert!(utc_d < d);
|
assert!(utc_d < d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,73 +116,92 @@ fn test_datetime_with_timezone() {
|
|||||||
fn test_datetime_rfc2822_and_rfc3339() {
|
fn test_datetime_rfc2822_and_rfc3339() {
|
||||||
let edt = FixedOffset::east_opt(5 * 60 * 60).unwrap();
|
let edt = FixedOffset::east_opt(5 * 60 * 60).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_opt(23, 16, 9).unwrap().to_rfc2822(),
|
Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc2822(),
|
||||||
"Wed, 18 Feb 2015 23:16:09 +0000"
|
"Wed, 18 Feb 2015 23:16:09 +0000"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_opt(23, 16, 9).unwrap().to_rfc3339(),
|
Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc3339(),
|
||||||
"2015-02-18T23:16:09+00:00"
|
"2015-02-18T23:16:09+00:00"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
edt.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap().to_rfc2822(),
|
edt.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.to_rfc2822(),
|
||||||
"Wed, 18 Feb 2015 23:16:09 +0500"
|
"Wed, 18 Feb 2015 23:16:09 +0500"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
edt.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap().to_rfc3339(),
|
edt.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.to_rfc3339(),
|
||||||
"2015-02-18T23:16:09.150+05:00"
|
"2015-02-18T23:16:09.150+05:00"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
edt.ymd_opt(2015, 2, 18)
|
edt.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
.and_hms_micro_opt(23, 59, 59, 1_234_567)
|
.unwrap()
|
||||||
.unwrap()
|
.and_hms_micro_opt(23, 59, 59, 1_234_567)
|
||||||
.to_rfc2822(),
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.to_rfc2822(),
|
||||||
"Wed, 18 Feb 2015 23:59:60 +0500"
|
"Wed, 18 Feb 2015 23:59:60 +0500"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
edt.ymd_opt(2015, 2, 18)
|
edt.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
.and_hms_micro_opt(23, 59, 59, 1_234_567)
|
.unwrap()
|
||||||
.unwrap()
|
.and_hms_micro_opt(23, 59, 59, 1_234_567)
|
||||||
.to_rfc3339(),
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.to_rfc3339(),
|
||||||
"2015-02-18T23:59:60.234567+05:00"
|
"2015-02-18T23:59:60.234567+05:00"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"),
|
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"),
|
||||||
Ok(FixedOffset::east_opt(0)
|
Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
|
||||||
.unwrap()
|
|
||||||
.ymd_opt(2015, 2, 18)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(23, 16, 9)
|
|
||||||
.unwrap())
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"),
|
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"),
|
||||||
Ok(FixedOffset::east_opt(0)
|
Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
|
||||||
.unwrap()
|
|
||||||
.ymd_opt(2015, 2, 18)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(23, 16, 9)
|
|
||||||
.unwrap())
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:16:09Z"),
|
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:16:09Z"),
|
||||||
Ok(FixedOffset::east_opt(0)
|
Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
|
||||||
.unwrap()
|
|
||||||
.ymd_opt(2015, 2, 18)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(23, 16, 9)
|
|
||||||
.unwrap())
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
|
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
|
||||||
Ok(edt.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap())
|
Ok(edt
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 59, 59, 1_000)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert!(DateTime::<FixedOffset>::parse_from_rfc2822("31 DEC 262143 23:59 -2359").is_err());
|
assert!(DateTime::<FixedOffset>::parse_from_rfc2822("31 DEC 262143 23:59 -2359").is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"),
|
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"),
|
||||||
Ok(edt.ymd_opt(2015, 2, 18).unwrap().and_hms_micro_opt(23, 59, 59, 1_234_567).unwrap())
|
Ok(edt
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_micro_opt(23, 59, 59, 1_234_567)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +209,14 @@ fn test_datetime_rfc2822_and_rfc3339() {
|
|||||||
fn test_rfc3339_opts() {
|
fn test_rfc3339_opts() {
|
||||||
use crate::SecondsFormat::*;
|
use crate::SecondsFormat::*;
|
||||||
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
||||||
let dt = pst.ymd_opt(2018, 1, 11).unwrap().and_hms_nano_opt(10, 5, 13, 84_660_000).unwrap();
|
let dt = pst
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2018, 1, 11)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(10, 5, 13, 84_660_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(dt.to_rfc3339_opts(Secs, false), "2018-01-11T10:05:13+08:00");
|
assert_eq!(dt.to_rfc3339_opts(Secs, false), "2018-01-11T10:05:13+08:00");
|
||||||
assert_eq!(dt.to_rfc3339_opts(Secs, true), "2018-01-11T10:05:13+08:00");
|
assert_eq!(dt.to_rfc3339_opts(Secs, true), "2018-01-11T10:05:13+08:00");
|
||||||
assert_eq!(dt.to_rfc3339_opts(Millis, false), "2018-01-11T10:05:13.084+08:00");
|
assert_eq!(dt.to_rfc3339_opts(Millis, false), "2018-01-11T10:05:13.084+08:00");
|
||||||
@ -218,7 +238,7 @@ fn test_rfc3339_opts() {
|
|||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_rfc3339_opts_nonexhaustive() {
|
fn test_rfc3339_opts_nonexhaustive() {
|
||||||
use crate::SecondsFormat;
|
use crate::SecondsFormat;
|
||||||
let dt = Utc.ymd_opt(1999, 10, 9).unwrap().and_hms_opt(1, 2, 3).unwrap();
|
let dt = Utc.with_ymd_and_hms(1999, 10, 9, 1, 2, 3).unwrap();
|
||||||
dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true);
|
dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,51 +248,95 @@ fn test_datetime_from_str() {
|
|||||||
"2015-02-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
|
"2015-02-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
|
||||||
Ok(FixedOffset::east_opt(0)
|
Ok(FixedOffset::east_opt(0)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2015, 2, 18)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
.and_hms_milli_opt(23, 16, 9, 150)
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
.unwrap())
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2015-02-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
|
"2015-02-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
|
||||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
Ok(Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2015-02-18T23:16:9.15 UTC".parse::<DateTime<Utc>>(),
|
"2015-02-18T23:16:9.15 UTC".parse::<DateTime<Utc>>(),
|
||||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
Ok(Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2015-02-18T23:16:9.15UTC".parse::<DateTime<Utc>>(),
|
"2015-02-18T23:16:9.15UTC".parse::<DateTime<Utc>>(),
|
||||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
Ok(Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
|
"2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
|
||||||
Ok(FixedOffset::east_opt(0)
|
Ok(FixedOffset::east_opt(0)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2015, 2, 18)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
.and_hms_milli_opt(23, 16, 9, 150)
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
.unwrap())
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2015-2-18T13:16:9.15-10:00".parse::<DateTime<FixedOffset>>(),
|
"2015-2-18T13:16:9.15-10:00".parse::<DateTime<FixedOffset>>(),
|
||||||
Ok(FixedOffset::west_opt(10 * 3600)
|
Ok(FixedOffset::west_opt(10 * 3600)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2015, 2, 18)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
.and_hms_milli_opt(13, 16, 9, 150)
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(13, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
.unwrap())
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert!("2015-2-18T23:16:9.15".parse::<DateTime<FixedOffset>>().is_err());
|
assert!("2015-2-18T23:16:9.15".parse::<DateTime<FixedOffset>>().is_err());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2015-2-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
|
"2015-2-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
|
||||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
Ok(Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"2015-2-18T13:16:9.15-10:00".parse::<DateTime<Utc>>(),
|
"2015-2-18T13:16:9.15-10:00".parse::<DateTime<Utc>>(),
|
||||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
Ok(Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(23, 16, 9, 150)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert!("2015-2-18T23:16:9.15".parse::<DateTime<Utc>>().is_err());
|
assert!("2015-2-18T23:16:9.15".parse::<DateTime<Utc>>().is_err());
|
||||||
|
|
||||||
@ -282,7 +346,7 @@ fn test_datetime_from_str() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_parse_from_str() {
|
fn test_datetime_parse_from_str() {
|
||||||
let ymdhms = |y, m, d, h, n, s, off| {
|
let ymdhms = |y, m, d, h, n, s, off| {
|
||||||
FixedOffset::east_opt(off).unwrap().ymd_opt(y, m, d).unwrap().and_hms_opt(h, n, s).unwrap()
|
FixedOffset::east_opt(off).unwrap().with_ymd_and_hms(y, m, d, h, n, s).unwrap()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<FixedOffset>::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
|
DateTime::<FixedOffset>::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
|
||||||
@ -296,13 +360,13 @@ fn test_datetime_parse_from_str() {
|
|||||||
.is_err());
|
.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"),
|
Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"),
|
||||||
Ok(Utc.ymd_opt(2013, 8, 9).unwrap().and_hms_opt(23, 54, 35).unwrap())
|
Ok(Utc.with_ymd_and_hms(2013, 8, 9, 23, 54, 35).unwrap())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_to_string_round_trip() {
|
fn test_to_string_round_trip() {
|
||||||
let dt = Utc.ymd_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
|
let dt = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
|
||||||
let _dt: DateTime<Utc> = dt.to_string().parse().unwrap();
|
let _dt: DateTime<Utc> = dt.to_string().parse().unwrap();
|
||||||
|
|
||||||
let ndt_fixed = dt.with_timezone(&FixedOffset::east_opt(3600).unwrap());
|
let ndt_fixed = dt.with_timezone(&FixedOffset::east_opt(3600).unwrap());
|
||||||
@ -352,7 +416,14 @@ fn test_datetime_is_send() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_subsecond_part() {
|
fn test_subsecond_part() {
|
||||||
let datetime = Utc.ymd_opt(2014, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 1234567).unwrap();
|
let datetime = Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2014, 7, 8)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(9, 10, 11, 1234567)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(1, datetime.timestamp_subsec_millis());
|
assert_eq!(1, datetime.timestamp_subsec_millis());
|
||||||
assert_eq!(1234, datetime.timestamp_subsec_micros());
|
assert_eq!(1234, datetime.timestamp_subsec_micros());
|
||||||
@ -364,31 +435,52 @@ fn test_subsecond_part() {
|
|||||||
fn test_from_system_time() {
|
fn test_from_system_time() {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
let epoch = Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
|
let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap();
|
||||||
let nanos = 999_999_999;
|
let nanos = 999_999_999;
|
||||||
|
|
||||||
// SystemTime -> DateTime<Utc>
|
// SystemTime -> DateTime<Utc>
|
||||||
assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
|
assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)),
|
DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)),
|
||||||
Utc.ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 39, nanos).unwrap()
|
Utc.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2001, 9, 9)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(1, 46, 39, nanos)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)),
|
DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)),
|
||||||
Utc.ymd_opt(1938, 4, 24).unwrap().and_hms_nano_opt(22, 13, 20, 1).unwrap()
|
Utc.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(1938, 4, 24).unwrap().and_hms_nano_opt(22, 13, 20, 1).unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
// DateTime<Utc> -> SystemTime
|
// DateTime<Utc> -> SystemTime
|
||||||
assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
|
assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SystemTime::from(
|
SystemTime::from(
|
||||||
Utc.ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 39, nanos).unwrap()
|
Utc.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2001, 9, 9)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(1, 46, 39, nanos)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
),
|
),
|
||||||
UNIX_EPOCH + Duration::new(999_999_999, nanos)
|
UNIX_EPOCH + Duration::new(999_999_999, nanos)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SystemTime::from(
|
SystemTime::from(
|
||||||
Utc.ymd_opt(1938, 4, 24).unwrap().and_hms_nano_opt(22, 13, 20, 1).unwrap()
|
Utc.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(1938, 4, 24)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(22, 13, 20, 1)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
),
|
),
|
||||||
UNIX_EPOCH - Duration::new(999_999_999, 999_999_999)
|
UNIX_EPOCH - Duration::new(999_999_999, 999_999_999)
|
||||||
);
|
);
|
||||||
@ -415,30 +507,54 @@ fn test_from_system_time() {
|
|||||||
|
|
||||||
let nanos = 999_999_000;
|
let nanos = 999_999_000;
|
||||||
|
|
||||||
let epoch = Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap();
|
let epoch = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap();
|
||||||
|
|
||||||
// SystemTime -> DateTime<Utc>
|
// SystemTime -> DateTime<Utc>
|
||||||
assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
|
assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)),
|
DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, nanos)),
|
||||||
Utc.ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 39, nanos).unwrap()
|
Utc.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2001, 9, 9)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(1, 46, 39, nanos)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)),
|
DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, nanos)),
|
||||||
Utc.ymd_opt(1938, 4, 24).unwrap().and_hms_nano_opt(22, 13, 20, 1_000).unwrap()
|
Utc.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(1938, 4, 24)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(22, 13, 20, 1_000)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
// DateTime<Utc> -> SystemTime
|
// DateTime<Utc> -> SystemTime
|
||||||
assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
|
assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SystemTime::from(
|
SystemTime::from(
|
||||||
Utc.ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 39, nanos).unwrap()
|
Utc.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2001, 9, 9)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(1, 46, 39, nanos)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
),
|
),
|
||||||
UNIX_EPOCH + Duration::new(999_999_999, nanos)
|
UNIX_EPOCH + Duration::new(999_999_999, nanos)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SystemTime::from(
|
SystemTime::from(
|
||||||
Utc.ymd_opt(1938, 4, 24).unwrap().and_hms_nano_opt(22, 13, 20, 1_000).unwrap()
|
Utc.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(1938, 4, 24)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(22, 13, 20, 1_000)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
),
|
),
|
||||||
UNIX_EPOCH - Duration::new(999_999_999, nanos)
|
UNIX_EPOCH - Duration::new(999_999_999, nanos)
|
||||||
);
|
);
|
||||||
@ -460,7 +576,7 @@ fn test_from_system_time() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_format_alignment() {
|
fn test_datetime_format_alignment() {
|
||||||
let datetime = Utc.ymd_opt(2007, 1, 2).unwrap();
|
let datetime = Utc.with_ymd_and_hms(2007, 1, 2, 0, 0, 0).unwrap();
|
||||||
|
|
||||||
// Item::Literal
|
// Item::Literal
|
||||||
let percent = datetime.format("%%");
|
let percent = datetime.format("%%");
|
||||||
@ -517,16 +633,18 @@ fn test_years_elapsed() {
|
|||||||
const WEEKS_PER_YEAR: f32 = 52.1775;
|
const WEEKS_PER_YEAR: f32 = 52.1775;
|
||||||
|
|
||||||
// This is always at least one year because 1 year = 52.1775 weeks.
|
// This is always at least one year because 1 year = 52.1775 weeks.
|
||||||
let one_year_ago = Utc::today() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64);
|
let one_year_ago =
|
||||||
|
Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64);
|
||||||
// A bit more than 2 years.
|
// A bit more than 2 years.
|
||||||
let two_year_ago = Utc::today() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64);
|
let two_year_ago =
|
||||||
|
Utc::now().date_naive() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64);
|
||||||
|
|
||||||
assert_eq!(Utc::today().years_since(one_year_ago), Some(1));
|
assert_eq!(Utc::now().date_naive().years_since(one_year_ago), Some(1));
|
||||||
assert_eq!(Utc::today().years_since(two_year_ago), Some(2));
|
assert_eq!(Utc::now().date_naive().years_since(two_year_ago), Some(2));
|
||||||
|
|
||||||
// If the given DateTime is later than now, the function will always return 0.
|
// If the given DateTime is later than now, the function will always return 0.
|
||||||
let future = Utc::today() + TimeDelta::weeks(12);
|
let future = Utc::now().date_naive() + TimeDelta::weeks(12);
|
||||||
assert_eq!(Utc::today().years_since(future), None);
|
assert_eq!(Utc::now().date_naive().years_since(future), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
//! # use std::error::Error;
|
//! # use std::error::Error;
|
||||||
//! use chrono::prelude::*;
|
//! use chrono::prelude::*;
|
||||||
//!
|
//!
|
||||||
//! let date_time = Utc.ymd_opt(2020, 11, 10).unwrap().and_hms_opt(0, 1, 32).unwrap();
|
//! let date_time = Utc.with_ymd_and_hms(2020, 11, 10, 0, 1, 32).unwrap();
|
||||||
//!
|
//!
|
||||||
//! let formatted = format!("{}", date_time.format("%Y-%m-%d %H:%M:%S"));
|
//! let formatted = format!("{}", date_time.format("%Y-%m-%d %H:%M:%S"));
|
||||||
//! assert_eq!(formatted, "2020-11-10 00:01:32");
|
//! assert_eq!(formatted, "2020-11-10 00:01:32");
|
||||||
@ -40,6 +40,7 @@ use alloc::string::{String, ToString};
|
|||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use core::fmt::Write;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
@ -426,6 +427,63 @@ const TOO_SHORT: ParseError = ParseError(ParseErrorKind::TooShort);
|
|||||||
const TOO_LONG: ParseError = ParseError(ParseErrorKind::TooLong);
|
const TOO_LONG: ParseError = ParseError(ParseErrorKind::TooLong);
|
||||||
const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat);
|
const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
struct Locales {
|
||||||
|
short_months: &'static [&'static str],
|
||||||
|
long_months: &'static [&'static str],
|
||||||
|
short_weekdays: &'static [&'static str],
|
||||||
|
long_weekdays: &'static [&'static str],
|
||||||
|
am_pm: &'static [&'static str],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
impl Locales {
|
||||||
|
fn new(_locale: Option<Locale>) -> Self {
|
||||||
|
#[cfg(feature = "unstable-locales")]
|
||||||
|
{
|
||||||
|
let locale = _locale.unwrap_or(Locale::POSIX);
|
||||||
|
Self {
|
||||||
|
short_months: locales::short_months(locale),
|
||||||
|
long_months: locales::long_months(locale),
|
||||||
|
short_weekdays: locales::short_weekdays(locale),
|
||||||
|
long_weekdays: locales::long_weekdays(locale),
|
||||||
|
am_pm: locales::am_pm(locale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "unstable-locales"))]
|
||||||
|
Self {
|
||||||
|
short_months: &[
|
||||||
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||||
|
],
|
||||||
|
long_months: &[
|
||||||
|
"January",
|
||||||
|
"February",
|
||||||
|
"March",
|
||||||
|
"April",
|
||||||
|
"May",
|
||||||
|
"June",
|
||||||
|
"July",
|
||||||
|
"August",
|
||||||
|
"September",
|
||||||
|
"October",
|
||||||
|
"November",
|
||||||
|
"December",
|
||||||
|
],
|
||||||
|
short_weekdays: &["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||||
|
long_weekdays: &[
|
||||||
|
"Sunday",
|
||||||
|
"Monday",
|
||||||
|
"Tuesday",
|
||||||
|
"Wednesday",
|
||||||
|
"Thursday",
|
||||||
|
"Friday",
|
||||||
|
"Saturday",
|
||||||
|
],
|
||||||
|
am_pm: &["AM", "PM"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Formats single formatting item
|
/// Formats single formatting item
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
|
||||||
@ -448,47 +506,10 @@ fn format_inner<'a>(
|
|||||||
time: Option<&NaiveTime>,
|
time: Option<&NaiveTime>,
|
||||||
off: Option<&(String, FixedOffset)>,
|
off: Option<&(String, FixedOffset)>,
|
||||||
item: &Item<'a>,
|
item: &Item<'a>,
|
||||||
_locale: Option<Locale>,
|
locale: Option<Locale>,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
#[cfg(feature = "unstable-locales")]
|
let locale = Locales::new(locale);
|
||||||
let (short_months, long_months, short_weekdays, long_weekdays, am_pm, am_pm_lowercase) = {
|
|
||||||
let locale = _locale.unwrap_or(Locale::POSIX);
|
|
||||||
let am_pm = locales::am_pm(locale);
|
|
||||||
(
|
|
||||||
locales::short_months(locale),
|
|
||||||
locales::long_months(locale),
|
|
||||||
locales::short_weekdays(locale),
|
|
||||||
locales::long_weekdays(locale),
|
|
||||||
am_pm,
|
|
||||||
&[am_pm[0].to_lowercase(), am_pm[1].to_lowercase()],
|
|
||||||
)
|
|
||||||
};
|
|
||||||
#[cfg(not(feature = "unstable-locales"))]
|
|
||||||
let (short_months, long_months, short_weekdays, long_weekdays, am_pm, am_pm_lowercase) = {
|
|
||||||
(
|
|
||||||
&["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
|
||||||
&[
|
|
||||||
"January",
|
|
||||||
"February",
|
|
||||||
"March",
|
|
||||||
"April",
|
|
||||||
"May",
|
|
||||||
"June",
|
|
||||||
"July",
|
|
||||||
"August",
|
|
||||||
"September",
|
|
||||||
"October",
|
|
||||||
"November",
|
|
||||||
"December",
|
|
||||||
],
|
|
||||||
&["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
||||||
&["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
|
||||||
&["AM", "PM"],
|
|
||||||
&["am", "pm"],
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
use core::fmt::Write;
|
|
||||||
use num_integer::{div_floor, mod_floor};
|
use num_integer::{div_floor, mod_floor};
|
||||||
|
|
||||||
match *item {
|
match *item {
|
||||||
@ -564,77 +585,41 @@ fn format_inner<'a>(
|
|||||||
Item::Fixed(ref spec) => {
|
Item::Fixed(ref spec) => {
|
||||||
use self::Fixed::*;
|
use self::Fixed::*;
|
||||||
|
|
||||||
/// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`.
|
|
||||||
/// `Z` instead of `+00[:]00` is allowed when `allow_zulu` is true.
|
|
||||||
fn write_local_minus_utc(
|
|
||||||
result: &mut String,
|
|
||||||
off: FixedOffset,
|
|
||||||
allow_zulu: bool,
|
|
||||||
colon_type: Colons,
|
|
||||||
) -> fmt::Result {
|
|
||||||
let off = off.local_minus_utc();
|
|
||||||
if !allow_zulu || off != 0 {
|
|
||||||
let (sign, off) = if off < 0 { ('-', -off) } else { ('+', off) };
|
|
||||||
|
|
||||||
match colon_type {
|
|
||||||
Colons::None => {
|
|
||||||
write!(result, "{}{:02}{:02}", sign, off / 3600, off / 60 % 60)
|
|
||||||
}
|
|
||||||
Colons::Single => {
|
|
||||||
write!(result, "{}{:02}:{:02}", sign, off / 3600, off / 60 % 60)
|
|
||||||
}
|
|
||||||
Colons::Double => {
|
|
||||||
write!(
|
|
||||||
result,
|
|
||||||
"{}{:02}:{:02}:{:02}",
|
|
||||||
sign,
|
|
||||||
off / 3600,
|
|
||||||
off / 60 % 60,
|
|
||||||
off % 60
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Colons::Triple => {
|
|
||||||
write!(result, "{}{:02}", sign, off / 3600)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.push('Z');
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret =
|
let ret =
|
||||||
match *spec {
|
match *spec {
|
||||||
ShortMonthName => date.map(|d| {
|
ShortMonthName => date.map(|d| {
|
||||||
result.push_str(short_months[d.month0() as usize]);
|
result.push_str(locale.short_months[d.month0() as usize]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
LongMonthName => date.map(|d| {
|
LongMonthName => date.map(|d| {
|
||||||
result.push_str(long_months[d.month0() as usize]);
|
result.push_str(locale.long_months[d.month0() as usize]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
ShortWeekdayName => date.map(|d| {
|
ShortWeekdayName => date.map(|d| {
|
||||||
result
|
result.push_str(
|
||||||
.push_str(short_weekdays[d.weekday().num_days_from_sunday() as usize]);
|
locale.short_weekdays[d.weekday().num_days_from_sunday() as usize],
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
LongWeekdayName => date.map(|d| {
|
LongWeekdayName => date.map(|d| {
|
||||||
result.push_str(long_weekdays[d.weekday().num_days_from_sunday() as usize]);
|
result.push_str(
|
||||||
|
locale.long_weekdays[d.weekday().num_days_from_sunday() as usize],
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
LowerAmPm => time.map(|t| {
|
LowerAmPm => time.map(|t| {
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(clippy::useless_asref))]
|
let ampm = if t.hour12().0 { locale.am_pm[1] } else { locale.am_pm[0] };
|
||||||
{
|
for char in ampm.chars() {
|
||||||
result.push_str(if t.hour12().0 {
|
result.extend(char.to_lowercase())
|
||||||
am_pm_lowercase[1].as_ref()
|
|
||||||
} else {
|
|
||||||
am_pm_lowercase[0].as_ref()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
UpperAmPm => time.map(|t| {
|
UpperAmPm => time.map(|t| {
|
||||||
result.push_str(if t.hour12().0 { am_pm[1] } else { am_pm[0] });
|
result.push_str(if t.hour12().0 {
|
||||||
|
locale.am_pm[1]
|
||||||
|
} else {
|
||||||
|
locale.am_pm[0]
|
||||||
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
Nanosecond => time.map(|t| {
|
Nanosecond => time.map(|t| {
|
||||||
@ -701,19 +686,7 @@ fn format_inner<'a>(
|
|||||||
// same as `%a, %d %b %Y %H:%M:%S %z`
|
// same as `%a, %d %b %Y %H:%M:%S %z`
|
||||||
{
|
{
|
||||||
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
|
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
|
||||||
let sec = t.second() + t.nanosecond() / 1_000_000_000;
|
Some(write_rfc2822_inner(result, d, t, off, locale))
|
||||||
write!(
|
|
||||||
result,
|
|
||||||
"{}, {:02} {} {:04} {:02}:{:02}:{:02} ",
|
|
||||||
short_weekdays[d.weekday().num_days_from_sunday() as usize],
|
|
||||||
d.day(),
|
|
||||||
short_months[d.month0() as usize],
|
|
||||||
d.year(),
|
|
||||||
t.hour(),
|
|
||||||
t.minute(),
|
|
||||||
sec
|
|
||||||
)?;
|
|
||||||
Some(write_local_minus_utc(result, off, false, Colons::None))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -722,10 +695,7 @@ fn format_inner<'a>(
|
|||||||
// same as `%Y-%m-%dT%H:%M:%S%.f%:z`
|
// same as `%Y-%m-%dT%H:%M:%S%.f%:z`
|
||||||
{
|
{
|
||||||
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
|
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
|
||||||
// reuse `Debug` impls which already print ISO 8601 format.
|
Some(write_rfc3339(result, crate::NaiveDateTime::new(*d, *t), off))
|
||||||
// this is faster in this way.
|
|
||||||
write!(result, "{:?}T{:?}", d, t)?;
|
|
||||||
Some(write_local_minus_utc(result, off, false, Colons::Single))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -743,6 +713,110 @@ fn format_inner<'a>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`.
|
||||||
|
/// `Z` instead of `+00[:]00` is allowed when `allow_zulu` is true.
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
fn write_local_minus_utc(
|
||||||
|
result: &mut String,
|
||||||
|
off: FixedOffset,
|
||||||
|
allow_zulu: bool,
|
||||||
|
colon_type: Colons,
|
||||||
|
) -> fmt::Result {
|
||||||
|
let off = off.local_minus_utc();
|
||||||
|
if allow_zulu && off == 0 {
|
||||||
|
result.push('Z');
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let (sign, off) = if off < 0 { ('-', -off) } else { ('+', off) };
|
||||||
|
result.push(sign);
|
||||||
|
|
||||||
|
write_hundreds(result, (off / 3600) as u8)?;
|
||||||
|
|
||||||
|
match colon_type {
|
||||||
|
Colons::None => write_hundreds(result, (off / 60 % 60) as u8),
|
||||||
|
Colons::Single => {
|
||||||
|
result.push(':');
|
||||||
|
write_hundreds(result, (off / 60 % 60) as u8)
|
||||||
|
}
|
||||||
|
Colons::Double => {
|
||||||
|
result.push(':');
|
||||||
|
write_hundreds(result, (off / 60 % 60) as u8)?;
|
||||||
|
result.push(':');
|
||||||
|
write_hundreds(result, (off % 60) as u8)
|
||||||
|
}
|
||||||
|
Colons::Triple => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the date, time and offset to the string. same as `%Y-%m-%dT%H:%M:%S%.f%:z`
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
pub(crate) fn write_rfc3339(
|
||||||
|
result: &mut String,
|
||||||
|
dt: crate::NaiveDateTime,
|
||||||
|
off: FixedOffset,
|
||||||
|
) -> fmt::Result {
|
||||||
|
// reuse `Debug` impls which already print ISO 8601 format.
|
||||||
|
// this is faster in this way.
|
||||||
|
write!(result, "{:?}", dt)?;
|
||||||
|
write_local_minus_utc(result, off, false, Colons::Single)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
/// write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
|
||||||
|
pub(crate) fn write_rfc2822(
|
||||||
|
result: &mut String,
|
||||||
|
dt: crate::NaiveDateTime,
|
||||||
|
off: FixedOffset,
|
||||||
|
) -> fmt::Result {
|
||||||
|
write_rfc2822_inner(result, &dt.date(), &dt.time(), off, Locales::new(None))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
/// write datetimes like `Tue, 1 Jul 2003 10:52:37 +0200`, same as `%a, %d %b %Y %H:%M:%S %z`
|
||||||
|
fn write_rfc2822_inner(
|
||||||
|
result: &mut String,
|
||||||
|
d: &NaiveDate,
|
||||||
|
t: &NaiveTime,
|
||||||
|
off: FixedOffset,
|
||||||
|
locale: Locales,
|
||||||
|
) -> fmt::Result {
|
||||||
|
let year = d.year();
|
||||||
|
// RFC2822 is only defined on years 0 through 9999
|
||||||
|
if !(0..=9999).contains(&year) {
|
||||||
|
return Err(fmt::Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_str(locale.short_weekdays[d.weekday().num_days_from_sunday() as usize]);
|
||||||
|
result.push_str(", ");
|
||||||
|
write_hundreds(result, d.day() as u8)?;
|
||||||
|
result.push(' ');
|
||||||
|
result.push_str(locale.short_months[d.month0() as usize]);
|
||||||
|
result.push(' ');
|
||||||
|
write_hundreds(result, (year / 100) as u8)?;
|
||||||
|
write_hundreds(result, (year % 100) as u8)?;
|
||||||
|
result.push(' ');
|
||||||
|
write_hundreds(result, t.hour() as u8)?;
|
||||||
|
result.push(':');
|
||||||
|
write_hundreds(result, t.minute() as u8)?;
|
||||||
|
result.push(':');
|
||||||
|
let sec = t.second() + t.nanosecond() / 1_000_000_000;
|
||||||
|
write_hundreds(result, sec as u8)?;
|
||||||
|
result.push(' ');
|
||||||
|
write_local_minus_utc(result, off, false, Colons::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equivalent to `{:02}` formatting for n < 100.
|
||||||
|
pub(crate) fn write_hundreds(w: &mut impl Write, n: u8) -> fmt::Result {
|
||||||
|
if n >= 100 {
|
||||||
|
return Err(fmt::Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tens = b'0' + n / 10;
|
||||||
|
let ones = b'0' + n % 10;
|
||||||
|
w.write_char(tens as char)?;
|
||||||
|
w.write_char(ones as char)
|
||||||
|
}
|
||||||
|
|
||||||
/// Tries to format given arguments with given formatting items.
|
/// Tries to format given arguments with given formatting items.
|
||||||
/// Internally used by `DelayedFormat`.
|
/// Internally used by `DelayedFormat`.
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
@ -892,7 +892,7 @@ fn parse_rfc850() {
|
|||||||
static RFC850_FMT: &str = "%A, %d-%b-%y %T GMT";
|
static RFC850_FMT: &str = "%A, %d-%b-%y %T GMT";
|
||||||
|
|
||||||
let dt_str = "Sunday, 06-Nov-94 08:49:37 GMT";
|
let dt_str = "Sunday, 06-Nov-94 08:49:37 GMT";
|
||||||
let dt = Utc.ymd_opt(1994, 11, 6).unwrap().and_hms_opt(8, 49, 37).unwrap();
|
let dt = Utc.with_ymd_and_hms(1994, 11, 6, 8, 49, 37).unwrap();
|
||||||
|
|
||||||
// Check that the format is what we expect
|
// Check that the format is what we expect
|
||||||
assert_eq!(dt.format(RFC850_FMT).to_string(), dt_str);
|
assert_eq!(dt.format(RFC850_FMT).to_string(), dt_str);
|
||||||
@ -903,28 +903,19 @@ fn parse_rfc850() {
|
|||||||
// Check that the rest of the weekdays parse correctly (this test originally failed because
|
// Check that the rest of the weekdays parse correctly (this test originally failed because
|
||||||
// Sunday parsed incorrectly).
|
// Sunday parsed incorrectly).
|
||||||
let testdates = [
|
let testdates = [
|
||||||
|
(Utc.with_ymd_and_hms(1994, 11, 7, 8, 49, 37).unwrap(), "Monday, 07-Nov-94 08:49:37 GMT"),
|
||||||
|
(Utc.with_ymd_and_hms(1994, 11, 8, 8, 49, 37).unwrap(), "Tuesday, 08-Nov-94 08:49:37 GMT"),
|
||||||
(
|
(
|
||||||
Utc.ymd_opt(1994, 11, 7).unwrap().and_hms_opt(8, 49, 37).unwrap(),
|
Utc.with_ymd_and_hms(1994, 11, 9, 8, 49, 37).unwrap(),
|
||||||
"Monday, 07-Nov-94 08:49:37 GMT",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Utc.ymd_opt(1994, 11, 8).unwrap().and_hms_opt(8, 49, 37).unwrap(),
|
|
||||||
"Tuesday, 08-Nov-94 08:49:37 GMT",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Utc.ymd_opt(1994, 11, 9).unwrap().and_hms_opt(8, 49, 37).unwrap(),
|
|
||||||
"Wednesday, 09-Nov-94 08:49:37 GMT",
|
"Wednesday, 09-Nov-94 08:49:37 GMT",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Utc.ymd_opt(1994, 11, 10).unwrap().and_hms_opt(8, 49, 37).unwrap(),
|
Utc.with_ymd_and_hms(1994, 11, 10, 8, 49, 37).unwrap(),
|
||||||
"Thursday, 10-Nov-94 08:49:37 GMT",
|
"Thursday, 10-Nov-94 08:49:37 GMT",
|
||||||
),
|
),
|
||||||
|
(Utc.with_ymd_and_hms(1994, 11, 11, 8, 49, 37).unwrap(), "Friday, 11-Nov-94 08:49:37 GMT"),
|
||||||
(
|
(
|
||||||
Utc.ymd_opt(1994, 11, 11).unwrap().and_hms_opt(8, 49, 37).unwrap(),
|
Utc.with_ymd_and_hms(1994, 11, 12, 8, 49, 37).unwrap(),
|
||||||
"Friday, 11-Nov-94 08:49:37 GMT",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Utc.ymd_opt(1994, 11, 12).unwrap().and_hms_opt(8, 49, 37).unwrap(),
|
|
||||||
"Saturday, 12-Nov-94 08:49:37 GMT",
|
"Saturday, 12-Nov-94 08:49:37 GMT",
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
@ -229,7 +229,7 @@ impl Parsed {
|
|||||||
/// (`false` for AM, `true` for PM)
|
/// (`false` for AM, `true` for PM)
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> {
|
pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.hour_div_12, if value { 1 } else { 0 })
|
set_if_consistent(&mut self.hour_div_12, u32::from(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from
|
/// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from
|
||||||
@ -1185,9 +1185,12 @@ mod tests {
|
|||||||
let ymdhmsn = |y, m, d, h, n, s, nano, off| {
|
let ymdhmsn = |y, m, d, h, n, s, nano, off| {
|
||||||
Ok(FixedOffset::east_opt(off)
|
Ok(FixedOffset::east_opt(off)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(y, m, d)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(y, m, d)
|
||||||
.and_hms_nano_opt(h, n, s, nano)
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(h, n, s, nano)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.unwrap())
|
.unwrap())
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1232,7 +1235,14 @@ mod tests {
|
|||||||
parse!(Utc;
|
parse!(Utc;
|
||||||
year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
|
year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4,
|
||||||
minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
|
minute: 26, second: 40, nanosecond: 12_345_678, offset: 0),
|
||||||
Ok(Utc.ymd_opt(2014, 12, 31).unwrap().and_hms_nano_opt(4, 26, 40, 12_345_678).unwrap())
|
Ok(Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2014, 12, 31)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(4, 26, 40, 12_345_678)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse!(Utc;
|
parse!(Utc;
|
||||||
@ -1252,16 +1262,19 @@ mod tests {
|
|||||||
minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
|
minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400),
|
||||||
Ok(FixedOffset::east_opt(32400)
|
Ok(FixedOffset::east_opt(32400)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2014, 12, 31)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2014, 12, 31)
|
||||||
.and_hms_nano_opt(13, 26, 40, 12_345_678)
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(13, 26, 40, 12_345_678)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
.unwrap())
|
.unwrap())
|
||||||
);
|
);
|
||||||
|
|
||||||
// single result from timestamp
|
// single result from timestamp
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse!(Utc; timestamp: 1_420_000_000, offset: 0),
|
parse!(Utc; timestamp: 1_420_000_000, offset: 0),
|
||||||
Ok(Utc.ymd_opt(2014, 12, 31).unwrap().and_hms_opt(4, 26, 40).unwrap())
|
Ok(Utc.with_ymd_and_hms(2014, 12, 31, 4, 26, 40).unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 32400), Err(IMPOSSIBLE));
|
assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 32400), Err(IMPOSSIBLE));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1272,9 +1285,7 @@ mod tests {
|
|||||||
parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400),
|
parse!(FixedOffset::east_opt(32400).unwrap(); timestamp: 1_420_000_000, offset: 32400),
|
||||||
Ok(FixedOffset::east_opt(32400)
|
Ok(FixedOffset::east_opt(32400)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2014, 12, 31)
|
.with_ymd_and_hms(2014, 12, 31, 13, 26, 40)
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(13, 26, 40)
|
|
||||||
.unwrap())
|
.unwrap())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -556,13 +556,17 @@ fn test_strftime_items() {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_strftime_docs() {
|
fn test_strftime_docs() {
|
||||||
|
use crate::NaiveDate;
|
||||||
use crate::{DateTime, FixedOffset, TimeZone, Timelike, Utc};
|
use crate::{DateTime, FixedOffset, TimeZone, Timelike, Utc};
|
||||||
|
|
||||||
let dt = FixedOffset::east_opt(34200)
|
let dt = FixedOffset::east_opt(34200)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2001, 7, 8)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2001, 7, 8)
|
||||||
.and_hms_nano_opt(0, 34, 59, 1_026_490_708)
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(0, 34, 59, 1_026_490_708)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// date specifiers
|
// date specifiers
|
||||||
@ -659,13 +663,12 @@ fn test_strftime_docs() {
|
|||||||
#[cfg(feature = "unstable-locales")]
|
#[cfg(feature = "unstable-locales")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_strftime_docs_localized() {
|
fn test_strftime_docs_localized() {
|
||||||
use crate::{FixedOffset, TimeZone};
|
use crate::{FixedOffset, NaiveDate};
|
||||||
|
|
||||||
let dt = FixedOffset::east_opt(34200)
|
let dt = NaiveDate::from_ymd_opt(2001, 7, 8)
|
||||||
|
.and_then(|d| d.and_hms_nano_opt(0, 34, 59, 1_026_490_708))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2001, 7, 8)
|
.and_local_timezone(FixedOffset::east_opt(34200).unwrap())
|
||||||
.unwrap()
|
|
||||||
.and_hms_nano_opt(0, 34, 59, 1_026_490_708)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// date specifiers
|
// date specifiers
|
||||||
|
39
src/lib.rs
39
src/lib.rs
@ -112,26 +112,26 @@
|
|||||||
//! use chrono::prelude::*;
|
//! use chrono::prelude::*;
|
||||||
//! use chrono::offset::LocalResult;
|
//! use chrono::offset::LocalResult;
|
||||||
//!
|
//!
|
||||||
//! let dt = Utc.ymd_opt(2014, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap(); // `2014-07-08T09:10:11Z`
|
//! let dt = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(); // `2014-07-08T09:10:11Z`
|
||||||
//! // July 8 is 188th day of the year 2014 (`o` for "ordinal")
|
//! // July 8 is 188th day of the year 2014 (`o` for "ordinal")
|
||||||
//! assert_eq!(dt, Utc.yo(2014, 189).and_hms_opt(9, 10, 11).unwrap());
|
//! assert_eq!(dt, Utc.yo(2014, 189).and_hms_opt(9, 10, 11).unwrap());
|
||||||
//! // July 8 is Tuesday in ISO week 28 of the year 2014.
|
//! // July 8 is Tuesday in ISO week 28 of the year 2014.
|
||||||
//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms_opt(9, 10, 11).unwrap());
|
//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms_opt(9, 10, 11).unwrap());
|
||||||
//!
|
//!
|
||||||
//! let dt = Utc.ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap(); // `2014-07-08T09:10:11.012Z`
|
//! let dt = NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap().and_local_timezone(Utc).unwrap(); // `2014-07-08T09:10:11.012Z`
|
||||||
//! assert_eq!(dt, Utc.ymd_opt(2014, 7, 8).unwrap().and_hms_micro_opt(9, 10, 11, 12_000).unwrap());
|
//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_micro_opt(9, 10, 11, 12_000).unwrap().and_local_timezone(Utc).unwrap());
|
||||||
//! assert_eq!(dt, Utc.ymd_opt(2014, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 12_000_000).unwrap());
|
//! assert_eq!(dt, NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_nano_opt(9, 10, 11, 12_000_000).unwrap().and_local_timezone(Utc).unwrap());
|
||||||
//!
|
//!
|
||||||
//! // dynamic verification
|
//! // dynamic verification
|
||||||
//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33),
|
//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33),
|
||||||
//! LocalResult::Single(Utc.ymd_opt(2014, 7, 8).unwrap().and_hms_opt(21, 15, 33).unwrap()));
|
//! LocalResult::Single(Utc.with_ymd_and_hms(2014, 7, 8, 21, 15, 33).unwrap()));
|
||||||
//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None);
|
//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None);
|
||||||
//! assert_eq!(Utc.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None);
|
//! assert_eq!(Utc.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None);
|
||||||
//!
|
//!
|
||||||
//! // other time zone objects can be used to construct a local datetime.
|
//! // other time zone objects can be used to construct a local datetime.
|
||||||
//! // obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical.
|
//! // obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical.
|
||||||
//! let local_dt = Local.ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap();
|
//! let local_dt = Local.from_local_datetime(&NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(9, 10, 11, 12).unwrap()).unwrap();
|
||||||
//! let fixed_dt = FixedOffset::east_opt(9 * 3600).unwrap().ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(18, 10, 11, 12).unwrap();
|
//! let fixed_dt = FixedOffset::east_opt(9 * 3600).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(2014, 7, 8).unwrap().and_hms_milli_opt(18, 10, 11, 12).unwrap()).unwrap();
|
||||||
//! assert_eq!(dt, fixed_dt);
|
//! assert_eq!(dt, fixed_dt);
|
||||||
//! # let _ = local_dt;
|
//! # let _ = local_dt;
|
||||||
//! ```
|
//! ```
|
||||||
@ -147,7 +147,7 @@
|
|||||||
//! use chrono::TimeDelta;
|
//! use chrono::TimeDelta;
|
||||||
//!
|
//!
|
||||||
//! // assume this returned `2014-11-28T21:45:59.324310806+09:00`:
|
//! // assume this returned `2014-11-28T21:45:59.324310806+09:00`:
|
||||||
//! let dt = FixedOffset::east_opt(9*3600).unwrap().ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(21, 45, 59, 324310806).unwrap();
|
//! let dt = FixedOffset::east_opt(9*3600).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(21, 45, 59, 324310806).unwrap()).unwrap();
|
||||||
//!
|
//!
|
||||||
//! // property accessors
|
//! // property accessors
|
||||||
//! assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28));
|
//! assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28));
|
||||||
@ -161,7 +161,7 @@
|
|||||||
//! // time zone accessor and manipulation
|
//! // time zone accessor and manipulation
|
||||||
//! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600);
|
//! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600);
|
||||||
//! assert_eq!(dt.timezone(), FixedOffset::east_opt(9 * 3600).unwrap());
|
//! assert_eq!(dt.timezone(), FixedOffset::east_opt(9 * 3600).unwrap());
|
||||||
//! assert_eq!(dt.with_timezone(&Utc), Utc.ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 45, 59, 324310806).unwrap());
|
//! assert_eq!(dt.with_timezone(&Utc), NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 45, 59, 324310806).unwrap().and_local_timezone(Utc).unwrap());
|
||||||
//!
|
//!
|
||||||
//! // a sample of property manipulations (validates dynamically)
|
//! // a sample of property manipulations (validates dynamically)
|
||||||
//! assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday
|
//! assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday
|
||||||
@ -169,14 +169,14 @@
|
|||||||
//! assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE
|
//! assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE
|
||||||
//!
|
//!
|
||||||
//! // arithmetic operations
|
//! // arithmetic operations
|
||||||
//! let dt1 = Utc.ymd_opt(2014, 11, 14).unwrap().and_hms_opt(8, 9, 10).unwrap();
|
//! let dt1 = Utc.with_ymd_and_hms(2014, 11, 14, 8, 9, 10).unwrap();
|
||||||
//! let dt2 = Utc.ymd_opt(2014, 11, 14).unwrap().and_hms_opt(10, 9, 8).unwrap();
|
//! let dt2 = Utc.with_ymd_and_hms(2014, 11, 14, 10, 9, 8).unwrap();
|
||||||
//! assert_eq!(dt1.signed_duration_since(dt2), TimeDelta::seconds(-2 * 3600 + 2));
|
//! assert_eq!(dt1.signed_duration_since(dt2), TimeDelta::seconds(-2 * 3600 + 2));
|
||||||
//! assert_eq!(dt2.signed_duration_since(dt1), TimeDelta::seconds(2 * 3600 - 2));
|
//! assert_eq!(dt2.signed_duration_since(dt1), TimeDelta::seconds(2 * 3600 - 2));
|
||||||
//! assert_eq!(Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap() + TimeDelta::seconds(1_000_000_000),
|
//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() + TimeDelta::seconds(1_000_000_000),
|
||||||
//! Utc.ymd_opt(2001, 9, 9).unwrap().and_hms_opt(1, 46, 40).unwrap());
|
//! Utc.with_ymd_and_hms(2001, 9, 9, 1, 46, 40).unwrap());
|
||||||
//! assert_eq!(Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap() - TimeDelta::seconds(1_000_000_000),
|
//! assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap() - TimeDelta::seconds(1_000_000_000),
|
||||||
//! Utc.ymd_opt(1938, 4, 24).unwrap().and_hms_opt(22, 13, 20).unwrap());
|
//! Utc.with_ymd_and_hms(1938, 4, 24, 22, 13, 20).unwrap());
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ### Formatting and Parsing
|
//! ### Formatting and Parsing
|
||||||
@ -207,7 +207,7 @@
|
|||||||
//!
|
//!
|
||||||
//! # #[cfg(feature = "unstable-locales")]
|
//! # #[cfg(feature = "unstable-locales")]
|
||||||
//! # fn test() {
|
//! # fn test() {
|
||||||
//! let dt = Utc.ymd_opt(2014, 11, 28).unwrap().and_hms_opt(12, 0, 9).unwrap();
|
//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9).unwrap();
|
||||||
//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09");
|
//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09");
|
||||||
//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014");
|
//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014");
|
||||||
//! assert_eq!(dt.format_localized("%A %e %B %Y, %T", Locale::fr_BE).to_string(), "vendredi 28 novembre 2014, 12:00:09");
|
//! assert_eq!(dt.format_localized("%A %e %B %Y, %T", Locale::fr_BE).to_string(), "vendredi 28 novembre 2014, 12:00:09");
|
||||||
@ -219,7 +219,7 @@
|
|||||||
//! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
|
//! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
|
||||||
//!
|
//!
|
||||||
//! // Note that milli/nanoseconds are only printed if they are non-zero
|
//! // Note that milli/nanoseconds are only printed if they are non-zero
|
||||||
//! let dt_nano = Utc.ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 0, 9, 1).unwrap();
|
//! let dt_nano = NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_nano_opt(12, 0, 9, 1).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
//! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
|
//! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z");
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "unstable-locales"))]
|
//! # #[cfg(not(feature = "unstable-locales"))]
|
||||||
@ -259,7 +259,7 @@
|
|||||||
//! ```rust
|
//! ```rust
|
||||||
//! use chrono::prelude::*;
|
//! use chrono::prelude::*;
|
||||||
//!
|
//!
|
||||||
//! let dt = Utc.ymd_opt(2014, 11, 28).unwrap().and_hms_opt(12, 0, 9).unwrap();
|
//! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9).unwrap();
|
||||||
//! let fixed_dt = dt.with_timezone(&FixedOffset::east_opt(9*3600).unwrap());
|
//! let fixed_dt = dt.with_timezone(&FixedOffset::east_opt(9*3600).unwrap());
|
||||||
//!
|
//!
|
||||||
//! // method 1
|
//! // method 1
|
||||||
@ -329,7 +329,7 @@
|
|||||||
//!
|
//!
|
||||||
//! assert_eq!(Utc.ymd_opt(2014, 11, 28).unwrap().weekday(), Weekday::Fri);
|
//! assert_eq!(Utc.ymd_opt(2014, 11, 28).unwrap().weekday(), Weekday::Fri);
|
||||||
//! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None);
|
//! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None);
|
||||||
//! assert_eq!(Utc.ymd_opt(2014, 11, 28).unwrap().and_hms_milli_opt(7, 8, 9, 10).unwrap().format("%H%M%S").to_string(),
|
//! assert_eq!(NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_milli_opt(7, 8, 9, 10).unwrap().and_local_timezone(Utc).unwrap().format("%H%M%S").to_string(),
|
||||||
//! "070809");
|
//! "070809");
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
@ -409,6 +409,7 @@ doctest!("../README.md");
|
|||||||
/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`).
|
/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`).
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub use crate::Date;
|
pub use crate::Date;
|
||||||
#[cfg(feature = "clock")]
|
#[cfg(feature = "clock")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
|
||||||
|
16
src/month.rs
16
src/month.rs
@ -14,7 +14,7 @@ use crate::OutOfRange;
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use std::convert::TryFrom;
|
/// # use std::convert::TryFrom;
|
||||||
/// use chrono::prelude::*;
|
/// use chrono::prelude::*;
|
||||||
/// let date = Utc.ymd_opt(2019, 10, 28).unwrap().and_hms_opt(9, 10, 11).unwrap();
|
/// let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap();
|
||||||
/// // `2019-10-28T09:10:11Z`
|
/// // `2019-10-28T09:10:11Z`
|
||||||
/// let month = Month::try_from(u8::try_from(date.month()).unwrap()).ok();
|
/// let month = Month::try_from(u8::try_from(date.month()).unwrap()).ok();
|
||||||
/// assert_eq!(month, Some(Month::October))
|
/// assert_eq!(month, Some(Month::October))
|
||||||
@ -23,7 +23,7 @@ use crate::OutOfRange;
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use chrono::prelude::*;
|
/// # use chrono::prelude::*;
|
||||||
/// let month = Month::January;
|
/// let month = Month::January;
|
||||||
/// let dt = Utc.ymd_opt(2019, month.number_from_month(), 28).unwrap().and_hms_opt(9, 10, 11).unwrap();
|
/// let dt = Utc.with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11).unwrap();
|
||||||
/// assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28));
|
/// assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28));
|
||||||
/// ```
|
/// ```
|
||||||
/// Allows mapping from and to month, from 1-January to 12-December.
|
/// Allows mapping from and to month, from 1-January to 12-December.
|
||||||
@ -31,6 +31,7 @@ use crate::OutOfRange;
|
|||||||
// Actual implementation is zero-indexed, API intended as 1-indexed for more intuitive behavior.
|
// Actual implementation is zero-indexed, API intended as 1-indexed for more intuitive behavior.
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
|
||||||
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
||||||
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||||
pub enum Month {
|
pub enum Month {
|
||||||
/// January
|
/// January
|
||||||
January = 0,
|
January = 0,
|
||||||
@ -177,6 +178,7 @@ impl TryFrom<u8> for Month {
|
|||||||
|
|
||||||
/// A duration in calendar months
|
/// A duration in calendar months
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
|
||||||
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||||
pub struct Months(pub(crate) u32);
|
pub struct Months(pub(crate) u32);
|
||||||
|
|
||||||
impl Months {
|
impl Months {
|
||||||
@ -317,15 +319,11 @@ mod tests {
|
|||||||
assert_eq!(Month::try_from(12), Ok(Month::December));
|
assert_eq!(Month::try_from(12), Ok(Month::December));
|
||||||
assert_eq!(Month::try_from(13), Err(OutOfRange::new()));
|
assert_eq!(Month::try_from(13), Err(OutOfRange::new()));
|
||||||
|
|
||||||
let date = Utc.ymd_opt(2019, 10, 28).unwrap().and_hms_opt(9, 10, 11).unwrap();
|
let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap();
|
||||||
assert_eq!(Month::try_from(date.month() as u8), Ok(Month::October));
|
assert_eq!(Month::try_from(date.month() as u8).ok(), Some(Month::October));
|
||||||
|
|
||||||
let month = Month::January;
|
let month = Month::January;
|
||||||
let dt = Utc
|
let dt = Utc.with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11).unwrap();
|
||||||
.ymd_opt(2019, month.number_from_month(), 28)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(9, 10, 11)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28));
|
assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use rkyv::{Archive, Deserialize, Serialize};
|
|||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
use crate::format::DelayedFormat;
|
use crate::format::DelayedFormat;
|
||||||
use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems};
|
use crate::format::{parse, write_hundreds, ParseError, ParseResult, Parsed, StrftimeItems};
|
||||||
use crate::format::{Item, Numeric, Pad};
|
use crate::format::{Item, Numeric, Pad};
|
||||||
use crate::month::Months;
|
use crate::month::Months;
|
||||||
use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime};
|
use crate::naive::{IsoWeek, NaiveDateTime, NaiveTime};
|
||||||
@ -191,6 +191,16 @@ pub const MIN_DATE: NaiveDate = NaiveDate::MIN;
|
|||||||
#[deprecated(since = "0.4.20", note = "Use NaiveDate::MAX instead")]
|
#[deprecated(since = "0.4.20", note = "Use NaiveDate::MAX instead")]
|
||||||
pub const MAX_DATE: NaiveDate = NaiveDate::MAX;
|
pub const MAX_DATE: NaiveDate = NaiveDate::MAX;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
impl arbitrary::Arbitrary<'_> for NaiveDate {
|
||||||
|
fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<NaiveDate> {
|
||||||
|
let year = u.int_in_range(MIN_YEAR..=MAX_YEAR)?;
|
||||||
|
let max_days = YearFlags::from_year(year).ndays();
|
||||||
|
let ord = u.int_in_range(1..=max_days)?;
|
||||||
|
NaiveDate::from_yo_opt(year, ord).ok_or(arbitrary::Error::IncorrectFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`,
|
// as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`,
|
||||||
// we use a separate run-time test.
|
// we use a separate run-time test.
|
||||||
#[test]
|
#[test]
|
||||||
@ -265,7 +275,7 @@ impl NaiveDate {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> {
|
pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> {
|
||||||
let flags = YearFlags::from_year(year);
|
let flags = YearFlags::from_year(year);
|
||||||
NaiveDate::from_mdf(year, Mdf::new(month, day, flags))
|
NaiveDate::from_mdf(year, Mdf::new(month, day, flags)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date)
|
/// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date)
|
||||||
@ -299,7 +309,7 @@ impl NaiveDate {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> {
|
pub fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> {
|
||||||
let flags = YearFlags::from_year(year);
|
let flags = YearFlags::from_year(year);
|
||||||
NaiveDate::from_of(year, Of::new(ordinal, flags))
|
NaiveDate::from_of(year, Of::new(ordinal, flags)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` from the [ISO week date](#week-date)
|
/// Makes a new `NaiveDate` from the [ISO week date](#week-date)
|
||||||
@ -368,18 +378,18 @@ impl NaiveDate {
|
|||||||
let prevflags = YearFlags::from_year(year - 1);
|
let prevflags = YearFlags::from_year(year - 1);
|
||||||
NaiveDate::from_of(
|
NaiveDate::from_of(
|
||||||
year - 1,
|
year - 1,
|
||||||
Of::new(weekord + prevflags.ndays() - delta, prevflags),
|
Of::new(weekord + prevflags.ndays() - delta, prevflags)?,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let ordinal = weekord - delta;
|
let ordinal = weekord - delta;
|
||||||
let ndays = flags.ndays();
|
let ndays = flags.ndays();
|
||||||
if ordinal <= ndays {
|
if ordinal <= ndays {
|
||||||
// this year
|
// this year
|
||||||
NaiveDate::from_of(year, Of::new(ordinal, flags))
|
NaiveDate::from_of(year, Of::new(ordinal, flags)?)
|
||||||
} else {
|
} else {
|
||||||
// ordinal > ndays, next year
|
// ordinal > ndays, next year
|
||||||
let nextflags = YearFlags::from_year(year + 1);
|
let nextflags = YearFlags::from_year(year + 1);
|
||||||
NaiveDate::from_of(year + 1, Of::new(ordinal - ndays, nextflags))
|
NaiveDate::from_of(year + 1, Of::new(ordinal - ndays, nextflags)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -422,7 +432,7 @@ impl NaiveDate {
|
|||||||
let (year_div_400, cycle) = div_mod_floor(days, 146_097);
|
let (year_div_400, cycle) = div_mod_floor(days, 146_097);
|
||||||
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
|
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
|
||||||
let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
|
let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
|
||||||
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags))
|
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week
|
/// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week
|
||||||
@ -613,7 +623,7 @@ impl NaiveDate {
|
|||||||
let days = [31, feb_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
let days = [31, feb_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||||
let day = Ord::min(self.day(), days[(month - 1) as usize]);
|
let day = Ord::min(self.day(), days[(month - 1) as usize]);
|
||||||
|
|
||||||
NaiveDate::from_mdf(year, Mdf::new(month as u32, day, flags))
|
NaiveDate::from_mdf(year, Mdf::new(month as u32, day, flags)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a duration in [`Days`] to the date
|
/// Add a duration in [`Days`] to the date
|
||||||
@ -974,7 +984,7 @@ impl NaiveDate {
|
|||||||
|
|
||||||
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
|
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
|
||||||
let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
|
let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
|
||||||
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags))
|
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subtracts the `days` part of given `TimeDelta` from the current date.
|
/// Subtracts the `days` part of given `TimeDelta` from the current date.
|
||||||
@ -1005,7 +1015,7 @@ impl NaiveDate {
|
|||||||
|
|
||||||
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
|
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
|
||||||
let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
|
let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
|
||||||
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags))
|
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subtracts another `NaiveDate` from the current date.
|
/// Subtracts another `NaiveDate` from the current date.
|
||||||
@ -1042,6 +1052,19 @@ impl NaiveDate {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of whole years from the given `base` until `self`.
|
||||||
|
pub fn years_since(&self, base: Self) -> Option<u32> {
|
||||||
|
let mut years = self.year() - base.year();
|
||||||
|
if (self.month(), self.day()) < (base.month(), base.day()) {
|
||||||
|
years -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
match years >= 0 {
|
||||||
|
true => Some(years as u32),
|
||||||
|
false => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Formats the date with the specified formatting items.
|
/// Formats the date with the specified formatting items.
|
||||||
/// Otherwise it is the same as the ordinary `format` method.
|
/// Otherwise it is the same as the ordinary `format` method.
|
||||||
///
|
///
|
||||||
@ -1427,7 +1450,7 @@ impl Datelike for NaiveDate {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_month(&self, month: u32) -> Option<NaiveDate> {
|
fn with_month(&self, month: u32) -> Option<NaiveDate> {
|
||||||
self.with_mdf(self.mdf().with_month(month))
|
self.with_mdf(self.mdf().with_month(month)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` with the month number (starting from 0) changed.
|
/// Makes a new `NaiveDate` with the month number (starting from 0) changed.
|
||||||
@ -1446,7 +1469,7 @@ impl Datelike for NaiveDate {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_month0(&self, month0: u32) -> Option<NaiveDate> {
|
fn with_month0(&self, month0: u32) -> Option<NaiveDate> {
|
||||||
self.with_mdf(self.mdf().with_month(month0 + 1))
|
self.with_mdf(self.mdf().with_month(month0 + 1)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
|
/// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
|
||||||
@ -1465,7 +1488,7 @@ impl Datelike for NaiveDate {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_day(&self, day: u32) -> Option<NaiveDate> {
|
fn with_day(&self, day: u32) -> Option<NaiveDate> {
|
||||||
self.with_mdf(self.mdf().with_day(day))
|
self.with_mdf(self.mdf().with_day(day)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` with the day of month (starting from 0) changed.
|
/// Makes a new `NaiveDate` with the day of month (starting from 0) changed.
|
||||||
@ -1484,7 +1507,7 @@ impl Datelike for NaiveDate {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_day0(&self, day0: u32) -> Option<NaiveDate> {
|
fn with_day0(&self, day0: u32) -> Option<NaiveDate> {
|
||||||
self.with_mdf(self.mdf().with_day(day0 + 1))
|
self.with_mdf(self.mdf().with_day(day0 + 1)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` with the day of year (starting from 1) changed.
|
/// Makes a new `NaiveDate` with the day of year (starting from 1) changed.
|
||||||
@ -1508,7 +1531,7 @@ impl Datelike for NaiveDate {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDate> {
|
fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDate> {
|
||||||
self.with_of(self.of().with_ordinal(ordinal))
|
self.with_of(self.of().with_ordinal(ordinal)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` with the day of year (starting from 0) changed.
|
/// Makes a new `NaiveDate` with the day of year (starting from 0) changed.
|
||||||
@ -1532,7 +1555,7 @@ impl Datelike for NaiveDate {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDate> {
|
fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDate> {
|
||||||
self.with_of(self.of().with_ordinal(ordinal0 + 1))
|
self.with_of(self.of().with_ordinal(ordinal0 + 1)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1818,14 +1841,22 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator {
|
|||||||
/// ```
|
/// ```
|
||||||
impl fmt::Debug for NaiveDate {
|
impl fmt::Debug for NaiveDate {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
let year = self.year();
|
let year = self.year();
|
||||||
let mdf = self.mdf();
|
let mdf = self.mdf();
|
||||||
if (0..=9999).contains(&year) {
|
if (0..=9999).contains(&year) {
|
||||||
write!(f, "{:04}-{:02}-{:02}", year, mdf.month(), mdf.day())
|
write_hundreds(f, (year / 100) as u8)?;
|
||||||
|
write_hundreds(f, (year % 100) as u8)?;
|
||||||
} else {
|
} else {
|
||||||
// ISO 8601 requires the explicit sign for out-of-range years
|
// ISO 8601 requires the explicit sign for out-of-range years
|
||||||
write!(f, "{:+05}-{:02}-{:02}", year, mdf.month(), mdf.day())
|
write!(f, "{:+05}", year)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.write_char('-')?;
|
||||||
|
write_hundreds(f, mdf.month() as u8)?;
|
||||||
|
f.write_char('-')?;
|
||||||
|
write_hundreds(f, mdf.day() as u8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
use core::fmt::Write;
|
||||||
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||||
use core::{fmt, str};
|
use core::{fmt, str};
|
||||||
|
|
||||||
@ -74,6 +75,7 @@ pub const MAX_DATETIME: NaiveDateTime = NaiveDateTime::MAX;
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
|
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
|
||||||
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
||||||
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||||
pub struct NaiveDateTime {
|
pub struct NaiveDateTime {
|
||||||
date: NaiveDate,
|
date: NaiveDate,
|
||||||
time: NaiveTime,
|
time: NaiveTime,
|
||||||
@ -1623,7 +1625,9 @@ impl Sub<Days> for NaiveDateTime {
|
|||||||
/// ```
|
/// ```
|
||||||
impl fmt::Debug for NaiveDateTime {
|
impl fmt::Debug for NaiveDateTime {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{:?}T{:?}", self.date, self.time)
|
self.date.fmt(f)?;
|
||||||
|
f.write_char('T')?;
|
||||||
|
self.time.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1654,7 +1658,9 @@ impl fmt::Debug for NaiveDateTime {
|
|||||||
/// ```
|
/// ```
|
||||||
impl fmt::Display for NaiveDateTime {
|
impl fmt::Display for NaiveDateTime {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} {}", self.date, self.time)
|
self.date.fmt(f)?;
|
||||||
|
f.write_char(' ')?;
|
||||||
|
self.time.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,7 +1053,7 @@ fn test_serde_deserialize() {
|
|||||||
// it is not self-describing.
|
// it is not self-describing.
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serde_bincode() {
|
fn test_serde_bincode() {
|
||||||
use crate::naive::NaiveDate;
|
use crate::NaiveDate;
|
||||||
use bincode::{deserialize, serialize};
|
use bincode::{deserialize, serialize};
|
||||||
|
|
||||||
let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap();
|
let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap();
|
||||||
@ -1076,10 +1076,8 @@ fn test_serde_bincode_optional() {
|
|||||||
two: Option<DateTime<Utc>>,
|
two: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let expected = Test {
|
let expected =
|
||||||
one: Some(1),
|
Test { one: Some(1), two: Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap()) };
|
||||||
two: Some(Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 1, 1).unwrap()),
|
|
||||||
};
|
|
||||||
let bytes: Vec<u8> = serialize(&expected).unwrap();
|
let bytes: Vec<u8> = serialize(&expected).unwrap();
|
||||||
let actual = deserialize::<Test>(&(bytes)).unwrap();
|
let actual = deserialize::<Test>(&(bytes)).unwrap();
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::NaiveDateTime;
|
use super::NaiveDateTime;
|
||||||
use crate::naive::NaiveDate;
|
|
||||||
use crate::time_delta::TimeDelta;
|
use crate::time_delta::TimeDelta;
|
||||||
|
use crate::NaiveDate;
|
||||||
use crate::{Datelike, FixedOffset, Utc};
|
use crate::{Datelike, FixedOffset, Utc};
|
||||||
use std::i64;
|
use std::i64;
|
||||||
|
|
||||||
|
@ -272,20 +272,13 @@ pub(super) struct Of(pub(crate) u32);
|
|||||||
|
|
||||||
impl Of {
|
impl Of {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clamp_ordinal(ordinal: u32) -> u32 {
|
pub(super) fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Option<Of> {
|
||||||
if ordinal > 366 {
|
match ordinal <= 366 {
|
||||||
0
|
true => Some(Of((ordinal << 4) | u32::from(flags))),
|
||||||
} else {
|
false => None,
|
||||||
ordinal
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(super) fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Of {
|
|
||||||
let ordinal = Of::clamp_ordinal(ordinal);
|
|
||||||
Of((ordinal << 4) | u32::from(flags))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn from_mdf(Mdf(mdf): Mdf) -> Of {
|
pub(super) fn from_mdf(Mdf(mdf): Mdf) -> Of {
|
||||||
let mdl = mdf >> 3;
|
let mdl = mdf >> 3;
|
||||||
@ -309,10 +302,13 @@ impl Of {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn with_ordinal(&self, ordinal: u32) -> Of {
|
pub(super) fn with_ordinal(&self, ordinal: u32) -> Option<Of> {
|
||||||
let ordinal = Of::clamp_ordinal(ordinal);
|
if ordinal > 366 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let Of(of) = *self;
|
let Of(of) = *self;
|
||||||
Of((of & 0b1111) | (ordinal << 4))
|
Some(Of((of & 0b1111) | (ordinal << 4)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -377,30 +373,13 @@ pub(super) struct Mdf(pub(super) u32);
|
|||||||
|
|
||||||
impl Mdf {
|
impl Mdf {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clamp_month(month: u32) -> u32 {
|
pub(super) fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> {
|
||||||
if month > 12 {
|
match month <= 12 && day <= 31 {
|
||||||
0
|
true => Some(Mdf((month << 9) | (day << 4) | u32::from(flags))),
|
||||||
} else {
|
false => None,
|
||||||
month
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn clamp_day(day: u32) -> u32 {
|
|
||||||
if day > 31 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
day
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(super) fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf {
|
|
||||||
let month = Mdf::clamp_month(month);
|
|
||||||
let day = Mdf::clamp_day(day);
|
|
||||||
Mdf((month << 9) | (day << 4) | u32::from(flags))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn from_of(Of(of): Of) -> Mdf {
|
pub(super) fn from_of(Of(of): Of) -> Mdf {
|
||||||
let ol = of >> 3;
|
let ol = of >> 3;
|
||||||
@ -427,10 +406,13 @@ impl Mdf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn with_month(&self, month: u32) -> Mdf {
|
pub(super) fn with_month(&self, month: u32) -> Option<Mdf> {
|
||||||
let month = Mdf::clamp_month(month);
|
if month > 12 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let Mdf(mdf) = *self;
|
let Mdf(mdf) = *self;
|
||||||
Mdf((mdf & 0b1_1111_1111) | (month << 9))
|
Some(Mdf((mdf & 0b1_1111_1111) | (month << 9)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -440,10 +422,13 @@ impl Mdf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn with_day(&self, day: u32) -> Mdf {
|
pub(super) fn with_day(&self, day: u32) -> Option<Mdf> {
|
||||||
let day = Mdf::clamp_day(day);
|
if day > 31 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let Mdf(mdf) = *self;
|
let Mdf(mdf) = *self;
|
||||||
Mdf((mdf & !0b1_1111_0000) | (day << 4))
|
Some(Mdf((mdf & !0b1_1111_0000) | (day << 4)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -525,7 +510,12 @@ mod tests {
|
|||||||
fn test_of() {
|
fn test_of() {
|
||||||
fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) {
|
fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) {
|
||||||
for ordinal in range_inclusive(ordinal1, ordinal2) {
|
for ordinal in range_inclusive(ordinal1, ordinal2) {
|
||||||
let of = Of::new(ordinal, flags);
|
let of = match Of::new(ordinal, flags) {
|
||||||
|
Some(of) => of,
|
||||||
|
None if !expected => continue,
|
||||||
|
None => panic!("Of::new({}, {:?}) returned None", ordinal, flags),
|
||||||
|
};
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
of.valid() == expected,
|
of.valid() == expected,
|
||||||
"ordinal {} = {:?} should be {} for dominical year {:?}",
|
"ordinal {} = {:?} should be {} for dominical year {:?}",
|
||||||
@ -557,7 +547,12 @@ mod tests {
|
|||||||
fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) {
|
fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) {
|
||||||
for month in range_inclusive(month1, month2) {
|
for month in range_inclusive(month1, month2) {
|
||||||
for day in range_inclusive(day1, day2) {
|
for day in range_inclusive(day1, day2) {
|
||||||
let mdf = Mdf::new(month, day, flags);
|
let mdf = match Mdf::new(month, day, flags) {
|
||||||
|
Some(mdf) => mdf,
|
||||||
|
None if !expected => continue,
|
||||||
|
None => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags),
|
||||||
|
};
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
mdf.valid() == expected,
|
mdf.valid() == expected,
|
||||||
"month {} day {} = {:?} should be {} for dominical year {:?}",
|
"month {} day {} = {:?} should be {} for dominical year {:?}",
|
||||||
@ -642,7 +637,7 @@ mod tests {
|
|||||||
fn test_of_fields() {
|
fn test_of_fields() {
|
||||||
for &flags in FLAGS.iter() {
|
for &flags in FLAGS.iter() {
|
||||||
for ordinal in range_inclusive(1u32, 366) {
|
for ordinal in range_inclusive(1u32, 366) {
|
||||||
let of = Of::new(ordinal, flags);
|
let of = Of::new(ordinal, flags).unwrap();
|
||||||
if of.valid() {
|
if of.valid() {
|
||||||
assert_eq!(of.ordinal(), ordinal);
|
assert_eq!(of.ordinal(), ordinal);
|
||||||
}
|
}
|
||||||
@ -653,11 +648,16 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_of_with_fields() {
|
fn test_of_with_fields() {
|
||||||
fn check(flags: YearFlags, ordinal: u32) {
|
fn check(flags: YearFlags, ordinal: u32) {
|
||||||
let of = Of::new(ordinal, flags);
|
let of = Of::new(ordinal, flags).unwrap();
|
||||||
|
|
||||||
for ordinal in range_inclusive(0u32, 1024) {
|
for ordinal in range_inclusive(0u32, 1024) {
|
||||||
let of = of.with_ordinal(ordinal);
|
let of = match of.with_ordinal(ordinal) {
|
||||||
assert_eq!(of.valid(), Of::new(ordinal, flags).valid());
|
Some(of) => of,
|
||||||
|
None if ordinal > 366 => continue,
|
||||||
|
None => panic!("failed to create Of with ordinal {}", ordinal),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(of.valid(), Of::new(ordinal, flags).unwrap().valid());
|
||||||
if of.valid() {
|
if of.valid() {
|
||||||
assert_eq!(of.ordinal(), ordinal);
|
assert_eq!(of.ordinal(), ordinal);
|
||||||
}
|
}
|
||||||
@ -676,25 +676,25 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_of_weekday() {
|
fn test_of_weekday() {
|
||||||
assert_eq!(Of::new(1, A).weekday(), Weekday::Sun);
|
assert_eq!(Of::new(1, A).unwrap().weekday(), Weekday::Sun);
|
||||||
assert_eq!(Of::new(1, B).weekday(), Weekday::Sat);
|
assert_eq!(Of::new(1, B).unwrap().weekday(), Weekday::Sat);
|
||||||
assert_eq!(Of::new(1, C).weekday(), Weekday::Fri);
|
assert_eq!(Of::new(1, C).unwrap().weekday(), Weekday::Fri);
|
||||||
assert_eq!(Of::new(1, D).weekday(), Weekday::Thu);
|
assert_eq!(Of::new(1, D).unwrap().weekday(), Weekday::Thu);
|
||||||
assert_eq!(Of::new(1, E).weekday(), Weekday::Wed);
|
assert_eq!(Of::new(1, E).unwrap().weekday(), Weekday::Wed);
|
||||||
assert_eq!(Of::new(1, F).weekday(), Weekday::Tue);
|
assert_eq!(Of::new(1, F).unwrap().weekday(), Weekday::Tue);
|
||||||
assert_eq!(Of::new(1, G).weekday(), Weekday::Mon);
|
assert_eq!(Of::new(1, G).unwrap().weekday(), Weekday::Mon);
|
||||||
assert_eq!(Of::new(1, AG).weekday(), Weekday::Sun);
|
assert_eq!(Of::new(1, AG).unwrap().weekday(), Weekday::Sun);
|
||||||
assert_eq!(Of::new(1, BA).weekday(), Weekday::Sat);
|
assert_eq!(Of::new(1, BA).unwrap().weekday(), Weekday::Sat);
|
||||||
assert_eq!(Of::new(1, CB).weekday(), Weekday::Fri);
|
assert_eq!(Of::new(1, CB).unwrap().weekday(), Weekday::Fri);
|
||||||
assert_eq!(Of::new(1, DC).weekday(), Weekday::Thu);
|
assert_eq!(Of::new(1, DC).unwrap().weekday(), Weekday::Thu);
|
||||||
assert_eq!(Of::new(1, ED).weekday(), Weekday::Wed);
|
assert_eq!(Of::new(1, ED).unwrap().weekday(), Weekday::Wed);
|
||||||
assert_eq!(Of::new(1, FE).weekday(), Weekday::Tue);
|
assert_eq!(Of::new(1, FE).unwrap().weekday(), Weekday::Tue);
|
||||||
assert_eq!(Of::new(1, GF).weekday(), Weekday::Mon);
|
assert_eq!(Of::new(1, GF).unwrap().weekday(), Weekday::Mon);
|
||||||
|
|
||||||
for &flags in FLAGS.iter() {
|
for &flags in FLAGS.iter() {
|
||||||
let mut prev = Of::new(1, flags).weekday();
|
let mut prev = Of::new(1, flags).unwrap().weekday();
|
||||||
for ordinal in range_inclusive(2u32, flags.ndays()) {
|
for ordinal in range_inclusive(2u32, flags.ndays()) {
|
||||||
let of = Of::new(ordinal, flags);
|
let of = Of::new(ordinal, flags).unwrap();
|
||||||
let expected = prev.succ();
|
let expected = prev.succ();
|
||||||
assert_eq!(of.weekday(), expected);
|
assert_eq!(of.weekday(), expected);
|
||||||
prev = expected;
|
prev = expected;
|
||||||
@ -707,7 +707,11 @@ mod tests {
|
|||||||
for &flags in FLAGS.iter() {
|
for &flags in FLAGS.iter() {
|
||||||
for month in range_inclusive(1u32, 12) {
|
for month in range_inclusive(1u32, 12) {
|
||||||
for day in range_inclusive(1u32, 31) {
|
for day in range_inclusive(1u32, 31) {
|
||||||
let mdf = Mdf::new(month, day, flags);
|
let mdf = match Mdf::new(month, day, flags) {
|
||||||
|
Some(mdf) => mdf,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
if mdf.valid() {
|
if mdf.valid() {
|
||||||
assert_eq!(mdf.month(), month);
|
assert_eq!(mdf.month(), month);
|
||||||
assert_eq!(mdf.day(), day);
|
assert_eq!(mdf.day(), day);
|
||||||
@ -720,11 +724,15 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_mdf_with_fields() {
|
fn test_mdf_with_fields() {
|
||||||
fn check(flags: YearFlags, month: u32, day: u32) {
|
fn check(flags: YearFlags, month: u32, day: u32) {
|
||||||
let mdf = Mdf::new(month, day, flags);
|
let mdf = Mdf::new(month, day, flags).unwrap();
|
||||||
|
|
||||||
for month in range_inclusive(0u32, 16) {
|
for month in range_inclusive(0u32, 16) {
|
||||||
let mdf = mdf.with_month(month);
|
let mdf = match mdf.with_month(month) {
|
||||||
assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
|
Some(mdf) => mdf,
|
||||||
|
None if month > 12 => continue,
|
||||||
|
None => panic!("failed to create Mdf with month {}", month),
|
||||||
|
};
|
||||||
|
|
||||||
if mdf.valid() {
|
if mdf.valid() {
|
||||||
assert_eq!(mdf.month(), month);
|
assert_eq!(mdf.month(), month);
|
||||||
assert_eq!(mdf.day(), day);
|
assert_eq!(mdf.day(), day);
|
||||||
@ -732,8 +740,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for day in range_inclusive(0u32, 1024) {
|
for day in range_inclusive(0u32, 1024) {
|
||||||
let mdf = mdf.with_day(day);
|
let mdf = match mdf.with_day(day) {
|
||||||
assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
|
Some(mdf) => mdf,
|
||||||
|
None if day > 31 => continue,
|
||||||
|
None => panic!("failed to create Mdf with month {}", month),
|
||||||
|
};
|
||||||
|
|
||||||
if mdf.valid() {
|
if mdf.valid() {
|
||||||
assert_eq!(mdf.month(), month);
|
assert_eq!(mdf.month(), month);
|
||||||
assert_eq!(mdf.day(), day);
|
assert_eq!(mdf.day(), day);
|
||||||
@ -763,7 +775,7 @@ mod tests {
|
|||||||
fn test_of_isoweekdate_raw() {
|
fn test_of_isoweekdate_raw() {
|
||||||
for &flags in FLAGS.iter() {
|
for &flags in FLAGS.iter() {
|
||||||
// January 4 should be in the first week
|
// January 4 should be in the first week
|
||||||
let (week, _) = Of::new(4 /* January 4 */, flags).isoweekdate_raw();
|
let (week, _) = Of::new(4 /* January 4 */, flags).unwrap().isoweekdate_raw();
|
||||||
assert_eq!(week, 1);
|
assert_eq!(week, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ use rkyv::{Archive, Deserialize, Serialize};
|
|||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
use crate::format::DelayedFormat;
|
use crate::format::DelayedFormat;
|
||||||
use crate::format::{parse, ParseError, ParseResult, Parsed, StrftimeItems};
|
use crate::format::{parse, write_hundreds, ParseError, ParseResult, Parsed, StrftimeItems};
|
||||||
use crate::format::{Fixed, Item, Numeric, Pad};
|
use crate::format::{Fixed, Item, Numeric, Pad};
|
||||||
use crate::{TimeDelta, Timelike};
|
use crate::{TimeDelta, Timelike};
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ mod tests;
|
|||||||
///
|
///
|
||||||
/// let dt1 = NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_micro_opt(8, 59, 59, 1_000_000).unwrap();
|
/// let dt1 = NaiveDate::from_ymd_opt(2015, 7, 1).unwrap().and_hms_micro_opt(8, 59, 59, 1_000_000).unwrap();
|
||||||
///
|
///
|
||||||
/// let dt2 = Utc.ymd_opt(2015, 6, 30).unwrap().and_hms_nano_opt(23, 59, 59, 1_000_000_000).unwrap();
|
/// let dt2 = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_nano_opt(23, 59, 59, 1_000_000_000).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// # let _ = (t, dt1, dt2);
|
/// # let _ = (t, dt1, dt2);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@ -157,9 +157,9 @@ mod tests;
|
|||||||
/// will be represented as the second part being 60, as required by ISO 8601.
|
/// will be represented as the second part being 60, as required by ISO 8601.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use chrono::{Utc, TimeZone};
|
/// use chrono::{Utc, TimeZone, NaiveDate};
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z");
|
/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@ -171,12 +171,12 @@ mod tests;
|
|||||||
/// and would be read back to the next non-leap second.
|
/// and would be read back to the next non-leap second.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use chrono::{DateTime, Utc, TimeZone};
|
/// use chrono::{DateTime, Utc, TimeZone, NaiveDate};
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 56, 4, 1_000).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2015, 6, 30).unwrap().and_hms_milli_opt(23, 56, 4, 1_000).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z");
|
/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z");
|
||||||
///
|
///
|
||||||
/// let dt = Utc.ymd_opt(2015, 6, 30).unwrap().and_hms_opt(23, 56, 5).unwrap();
|
/// let dt = Utc.with_ymd_and_hms(2015, 6, 30, 23, 56, 5).unwrap();
|
||||||
/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z");
|
/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z");
|
||||||
/// assert_eq!(DateTime::<Utc>::parse_from_rfc3339("2015-06-30T23:56:05Z").unwrap(), dt);
|
/// assert_eq!(DateTime::<Utc>::parse_from_rfc3339("2015-06-30T23:56:05Z").unwrap(), dt);
|
||||||
/// ```
|
/// ```
|
||||||
@ -190,6 +190,17 @@ pub struct NaiveTime {
|
|||||||
frac: u32,
|
frac: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
impl arbitrary::Arbitrary<'_> for NaiveTime {
|
||||||
|
fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<NaiveTime> {
|
||||||
|
let secs = u.int_in_range(0..=86_399)?;
|
||||||
|
let nano = u.int_in_range(0..=1_999_999_999)?;
|
||||||
|
let time = NaiveTime::from_num_seconds_from_midnight_opt(secs, nano)
|
||||||
|
.expect("Could not generate a valid chrono::NaiveTime. It looks like implementation of Arbitrary for NaiveTime is erroneous.");
|
||||||
|
Ok(time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NaiveTime {
|
impl NaiveTime {
|
||||||
/// Makes a new `NaiveTime` from hour, minute and second.
|
/// Makes a new `NaiveTime` from hour, minute and second.
|
||||||
///
|
///
|
||||||
@ -637,13 +648,7 @@ impl NaiveTime {
|
|||||||
|
|
||||||
// `secs` may contain a leap second yet to be counted
|
// `secs` may contain a leap second yet to be counted
|
||||||
let adjust = match self.secs.cmp(&rhs.secs) {
|
let adjust = match self.secs.cmp(&rhs.secs) {
|
||||||
Ordering::Greater => {
|
Ordering::Greater => i64::from(rhs.frac >= 1_000_000_000),
|
||||||
if rhs.frac >= 1_000_000_000 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ordering::Equal => 0,
|
Ordering::Equal => 0,
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
if self.frac >= 1_000_000_000 {
|
if self.frac >= 1_000_000_000 {
|
||||||
@ -1173,7 +1178,13 @@ impl fmt::Debug for NaiveTime {
|
|||||||
(sec, self.frac)
|
(sec, self.frac)
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "{:02}:{:02}:{:02}", hour, min, sec)?;
|
use core::fmt::Write;
|
||||||
|
write_hundreds(f, hour as u8)?;
|
||||||
|
f.write_char(':')?;
|
||||||
|
write_hundreds(f, min as u8)?;
|
||||||
|
f.write_char(':')?;
|
||||||
|
write_hundreds(f, sec as u8)?;
|
||||||
|
|
||||||
if nano == 0 {
|
if nano == 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if nano % 1_000_000 == 0 {
|
} else if nano % 1_000_000 == 0 {
|
||||||
|
@ -152,6 +152,16 @@ impl fmt::Display for FixedOffset {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
impl arbitrary::Arbitrary<'_> for FixedOffset {
|
||||||
|
fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<FixedOffset> {
|
||||||
|
let secs = u.int_in_range(-86_399..=86_399)?;
|
||||||
|
let fixed_offset = FixedOffset::east_opt(secs)
|
||||||
|
.expect("Could not generate a valid chrono::FixedOffset. It looks like implementation of Arbitrary for FixedOffset is erroneous.");
|
||||||
|
Ok(fixed_offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// addition or subtraction of FixedOffset to/from Timelike values is the same as
|
// addition or subtraction of FixedOffset to/from Timelike values is the same as
|
||||||
// adding or subtracting the offset's local_minus_utc value
|
// adding or subtracting the offset's local_minus_utc value
|
||||||
// but keep keeps the leap second information.
|
// but keep keeps the leap second information.
|
||||||
@ -231,33 +241,41 @@ mod tests {
|
|||||||
// starting from 0.3 we don't have an offset exceeding one day.
|
// starting from 0.3 we don't have an offset exceeding one day.
|
||||||
// this makes everything easier!
|
// this makes everything easier!
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", FixedOffset::east_opt(86399).unwrap().ymd_opt(2012, 2, 29).unwrap()),
|
format!(
|
||||||
"2012-02-29+23:59:59".to_string()
|
"{:?}",
|
||||||
|
FixedOffset::east_opt(86399)
|
||||||
|
.unwrap()
|
||||||
|
.with_ymd_and_hms(2012, 2, 29, 5, 6, 7)
|
||||||
|
.unwrap()
|
||||||
|
),
|
||||||
|
"2012-02-29T05:06:07+23:59:59".to_string()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!(
|
format!(
|
||||||
"{:?}",
|
"{:?}",
|
||||||
FixedOffset::east_opt(86399)
|
FixedOffset::east_opt(86399)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2012, 2, 29)
|
.with_ymd_and_hms(2012, 2, 29, 5, 6, 7)
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(5, 6, 7)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
),
|
),
|
||||||
"2012-02-29T05:06:07+23:59:59".to_string()
|
"2012-02-29T05:06:07+23:59:59".to_string()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
format!("{:?}", FixedOffset::west_opt(86399).unwrap().ymd_opt(2012, 3, 4).unwrap()),
|
|
||||||
"2012-03-04-23:59:59".to_string()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!(
|
format!(
|
||||||
"{:?}",
|
"{:?}",
|
||||||
FixedOffset::west_opt(86399)
|
FixedOffset::west_opt(86399)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ymd_opt(2012, 3, 4)
|
.with_ymd_and_hms(2012, 3, 4, 5, 6, 7)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_hms_opt(5, 6, 7)
|
),
|
||||||
|
"2012-03-04T05:06:07-23:59:59".to_string()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
format!(
|
||||||
|
"{:?}",
|
||||||
|
FixedOffset::west_opt(86399)
|
||||||
|
.unwrap()
|
||||||
|
.with_ymd_and_hms(2012, 3, 4, 5, 6, 7)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
),
|
),
|
||||||
"2012-03-04T05:06:07-23:59:59".to_string()
|
"2012-03-04T05:06:07-23:59:59".to_string()
|
||||||
|
@ -9,6 +9,7 @@ use rkyv::{Archive, Deserialize, Serialize};
|
|||||||
use super::fixed::FixedOffset;
|
use super::fixed::FixedOffset;
|
||||||
use super::{LocalResult, TimeZone};
|
use super::{LocalResult, TimeZone};
|
||||||
use crate::naive::{NaiveDate, NaiveDateTime};
|
use crate::naive::{NaiveDate, NaiveDateTime};
|
||||||
|
#[allow(deprecated)]
|
||||||
use crate::{Date, DateTime};
|
use crate::{Date, DateTime};
|
||||||
|
|
||||||
// we don't want `stub.rs` when the target_os is not wasi or emscripten
|
// we don't want `stub.rs` when the target_os is not wasi or emscripten
|
||||||
@ -52,10 +53,13 @@ mod tz_info;
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
||||||
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||||
pub struct Local;
|
pub struct Local;
|
||||||
|
|
||||||
impl Local {
|
impl Local {
|
||||||
/// Returns a `Date` which corresponds to the current date.
|
/// Returns a `Date` which corresponds to the current date.
|
||||||
|
#[deprecated(since = "0.4.23", note = "use `Local::now()` instead")]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub fn today() -> Date<Local> {
|
pub fn today() -> Date<Local> {
|
||||||
Local::now().date()
|
Local::now().date()
|
||||||
}
|
}
|
||||||
@ -96,6 +100,7 @@ impl TimeZone for Local {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// they are easier to define in terms of the finished date and time unlike other offsets
|
// they are easier to define in terms of the finished date and time unlike other offsets
|
||||||
|
#[allow(deprecated)]
|
||||||
fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
|
fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<FixedOffset> {
|
||||||
self.from_local_date(local).map(|date| *date.offset())
|
self.from_local_date(local).map(|date| *date.offset())
|
||||||
}
|
}
|
||||||
@ -104,6 +109,7 @@ impl TimeZone for Local {
|
|||||||
self.from_local_datetime(local).map(|datetime| *datetime.offset())
|
self.from_local_datetime(local).map(|datetime| *datetime.offset())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
|
fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset {
|
||||||
*self.from_utc_date(utc).offset()
|
*self.from_utc_date(utc).offset()
|
||||||
}
|
}
|
||||||
@ -113,6 +119,7 @@ impl TimeZone for Local {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// override them for avoiding redundant works
|
// override them for avoiding redundant works
|
||||||
|
#[allow(deprecated)]
|
||||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> {
|
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> {
|
||||||
// this sounds very strange, but required for keeping `TimeZone::ymd` sane.
|
// this sounds very strange, but required for keeping `TimeZone::ymd` sane.
|
||||||
// in the other words, we use the offset at the local midnight
|
// in the other words, we use the offset at the local midnight
|
||||||
@ -145,6 +152,7 @@ impl TimeZone for Local {
|
|||||||
inner::naive_to_local(local, true)
|
inner::naive_to_local(local, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> {
|
fn from_utc_date(&self, utc: &NaiveDate) -> Date<Local> {
|
||||||
let midnight = self.from_utc_datetime(&utc.and_hms_opt(0, 0, 0).unwrap());
|
let midnight = self.from_utc_datetime(&utc.and_hms_opt(0, 0, 0).unwrap());
|
||||||
Date::from_utc(*utc, *midnight.offset())
|
Date::from_utc(*utc, *midnight.offset())
|
||||||
@ -179,7 +187,7 @@ impl TimeZone for Local {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::Local;
|
use super::Local;
|
||||||
use crate::offset::TimeZone;
|
use crate::offset::TimeZone;
|
||||||
use crate::{Datelike, TimeDelta};
|
use crate::{Datelike, TimeDelta, Utc};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verify_correct_offsets() {
|
fn verify_correct_offsets() {
|
||||||
@ -227,13 +235,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_local_date_sanity_check() {
|
fn test_local_date_sanity_check() {
|
||||||
// issue #27
|
// issue #27
|
||||||
assert_eq!(Local.ymd_opt(2999, 12, 28).unwrap().day(), 28);
|
assert_eq!(Local.with_ymd_and_hms(2999, 12, 28, 0, 0, 0).unwrap().day(), 28);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_leap_second() {
|
fn test_leap_second() {
|
||||||
// issue #123
|
// issue #123
|
||||||
let today = Local::today();
|
let today = Utc::now().date_naive();
|
||||||
|
|
||||||
let dt = today.and_hms_milli_opt(1, 2, 59, 1000).unwrap();
|
let dt = today.and_hms_milli_opt(1, 2, 59, 1000).unwrap();
|
||||||
let timestr = dt.time().to_string();
|
let timestr = dt.time().to_string();
|
||||||
|
@ -26,11 +26,10 @@ impl TimeZone {
|
|||||||
///
|
///
|
||||||
/// This method in not supported on non-UNIX platforms, and returns the UTC time zone instead.
|
/// This method in not supported on non-UNIX platforms, and returns the UTC time zone instead.
|
||||||
///
|
///
|
||||||
pub(crate) fn local() -> Result<Self, Error> {
|
pub(crate) fn local(env_tz: Option<&str>) -> Result<Self, Error> {
|
||||||
if let Ok(tz) = std::env::var("TZ") {
|
match env_tz {
|
||||||
Self::from_posix_tz(&tz)
|
Some(tz) => Self::from_posix_tz(tz),
|
||||||
} else {
|
None => Self::from_posix_tz("localtime"),
|
||||||
Self::from_posix_tz("localtime")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,7 +812,7 @@ mod tests {
|
|||||||
// so just ensure that ::local() acts as expected
|
// so just ensure that ::local() acts as expected
|
||||||
// in this case
|
// in this case
|
||||||
if let Ok(tz) = std::env::var("TZ") {
|
if let Ok(tz) = std::env::var("TZ") {
|
||||||
let time_zone_local = TimeZone::local()?;
|
let time_zone_local = TimeZone::local(Some(tz.as_str()))?;
|
||||||
let time_zone_local_1 = TimeZone::from_posix_tz(&tz)?;
|
let time_zone_local_1 = TimeZone::from_posix_tz(&tz)?;
|
||||||
assert_eq!(time_zone_local, time_zone_local_1);
|
assert_eq!(time_zone_local, time_zone_local_1);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::{cell::RefCell, env, fs, time::SystemTime};
|
use std::{cell::RefCell, collections::hash_map, env, fs, hash::Hasher, time::SystemTime};
|
||||||
|
|
||||||
use super::tz_info::TimeZone;
|
use super::tz_info::TimeZone;
|
||||||
use super::{DateTime, FixedOffset, Local, NaiveDateTime};
|
use super::{DateTime, FixedOffset, Local, NaiveDateTime};
|
||||||
@ -32,68 +32,40 @@ thread_local! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum Source {
|
enum Source {
|
||||||
LocalTime { mtime: SystemTime, last_checked: SystemTime },
|
LocalTime { mtime: SystemTime },
|
||||||
// we don't bother storing the contents of the environment variable in this case.
|
Environment { hash: u64 },
|
||||||
// changing the environment while the process is running is generally not reccomended
|
|
||||||
Environment,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Source {
|
impl Source {
|
||||||
fn default() -> Source {
|
fn new(env_tz: Option<&str>) -> Source {
|
||||||
// use of var_os avoids allocating, which is nice
|
match env_tz {
|
||||||
// as we are only going to discard the string anyway
|
Some(tz) => {
|
||||||
// but we must ensure the contents are valid unicode
|
let mut hasher = hash_map::DefaultHasher::new();
|
||||||
// otherwise the behaivour here would be different
|
hasher.write(tz.as_bytes());
|
||||||
// to that in `naive_to_local`
|
let hash = hasher.finish();
|
||||||
match env::var_os("TZ") {
|
Source::Environment { hash }
|
||||||
Some(ref s) if s.to_str().is_some() => Source::Environment,
|
}
|
||||||
Some(_) | None => match fs::symlink_metadata("/etc/localtime") {
|
None => match fs::symlink_metadata("/etc/localtime") {
|
||||||
Ok(data) => Source::LocalTime {
|
Ok(data) => Source::LocalTime {
|
||||||
// we have to pick a sensible default when the mtime fails
|
// we have to pick a sensible default when the mtime fails
|
||||||
// by picking SystemTime::now() we raise the probability of
|
// by picking SystemTime::now() we raise the probability of
|
||||||
// the cache being invalidated if/when the mtime starts working
|
// the cache being invalidated if/when the mtime starts working
|
||||||
mtime: data.modified().unwrap_or_else(|_| SystemTime::now()),
|
mtime: data.modified().unwrap_or_else(|_| SystemTime::now()),
|
||||||
last_checked: SystemTime::now(),
|
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// as above, now() should be a better default than some constant
|
// as above, now() should be a better default than some constant
|
||||||
// TODO: see if we can improve caching in the case where the fallback is a valid timezone
|
// TODO: see if we can improve caching in the case where the fallback is a valid timezone
|
||||||
Source::LocalTime { mtime: SystemTime::now(), last_checked: SystemTime::now() }
|
Source::LocalTime { mtime: SystemTime::now() }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Source {
|
|
||||||
fn out_of_date(&mut self) -> bool {
|
|
||||||
let now = SystemTime::now();
|
|
||||||
let prev = match self {
|
|
||||||
Source::LocalTime { mtime, last_checked } => match now.duration_since(*last_checked) {
|
|
||||||
Ok(d) if d.as_secs() < 1 => return false,
|
|
||||||
Ok(_) | Err(_) => *mtime,
|
|
||||||
},
|
|
||||||
Source::Environment => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
match Source::default() {
|
|
||||||
Source::LocalTime { mtime, .. } => {
|
|
||||||
*self = Source::LocalTime { mtime, last_checked: now };
|
|
||||||
prev != mtime
|
|
||||||
}
|
|
||||||
// will only reach here if TZ has been set while
|
|
||||||
// the process is running
|
|
||||||
Source::Environment => {
|
|
||||||
*self = Source::Environment;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Cache {
|
struct Cache {
|
||||||
zone: TimeZone,
|
zone: TimeZone,
|
||||||
source: Source,
|
source: Source,
|
||||||
|
last_checked: SystemTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
@ -115,17 +87,63 @@ fn fallback_timezone() -> Option<TimeZone> {
|
|||||||
impl Default for Cache {
|
impl Default for Cache {
|
||||||
fn default() -> Cache {
|
fn default() -> Cache {
|
||||||
// default to UTC if no local timezone can be found
|
// default to UTC if no local timezone can be found
|
||||||
|
let env_tz = env::var("TZ").ok();
|
||||||
|
let env_ref = env_tz.as_ref().map(|s| s.as_str());
|
||||||
Cache {
|
Cache {
|
||||||
zone: TimeZone::local().ok().or_else(fallback_timezone).unwrap_or_else(TimeZone::utc),
|
last_checked: SystemTime::now(),
|
||||||
source: Source::default(),
|
source: Source::new(env_ref),
|
||||||
|
zone: current_zone(env_ref),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn current_zone(var: Option<&str>) -> TimeZone {
|
||||||
|
TimeZone::local(var).ok().or_else(fallback_timezone).unwrap_or_else(TimeZone::utc)
|
||||||
|
}
|
||||||
|
|
||||||
impl Cache {
|
impl Cache {
|
||||||
fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
|
fn offset(&mut self, d: NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
|
||||||
if self.source.out_of_date() {
|
let now = SystemTime::now();
|
||||||
*self = Cache::default();
|
|
||||||
|
match now.duration_since(self.last_checked) {
|
||||||
|
// If the cache has been around for less than a second then we reuse it
|
||||||
|
// unconditionally. This is a reasonable tradeoff because the timezone
|
||||||
|
// generally won't be changing _that_ often, but if the time zone does
|
||||||
|
// change, it will reflect sufficiently quickly from an application
|
||||||
|
// user's perspective.
|
||||||
|
Ok(d) if d.as_secs() < 1 => (),
|
||||||
|
Ok(_) | Err(_) => {
|
||||||
|
let env_tz = env::var("TZ").ok();
|
||||||
|
let env_ref = env_tz.as_ref().map(|s| s.as_str());
|
||||||
|
let new_source = Source::new(env_ref);
|
||||||
|
|
||||||
|
let out_of_date = match (&self.source, &new_source) {
|
||||||
|
// change from env to file or file to env, must recreate the zone
|
||||||
|
(Source::Environment { .. }, Source::LocalTime { .. })
|
||||||
|
| (Source::LocalTime { .. }, Source::Environment { .. }) => true,
|
||||||
|
// stay as file, but mtime has changed
|
||||||
|
(Source::LocalTime { mtime: old_mtime }, Source::LocalTime { mtime })
|
||||||
|
if old_mtime != mtime =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
// stay as env, but hash of variable has changed
|
||||||
|
(Source::Environment { hash: old_hash }, Source::Environment { hash })
|
||||||
|
if old_hash != hash =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
// cache can be reused
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if out_of_date {
|
||||||
|
self.zone = current_zone(env_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_checked = now;
|
||||||
|
self.source = new_source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !local {
|
if !local {
|
||||||
|
@ -23,6 +23,7 @@ use core::fmt;
|
|||||||
use crate::format::{parse, ParseResult, Parsed, StrftimeItems};
|
use crate::format::{parse, ParseResult, Parsed, StrftimeItems};
|
||||||
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
|
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
|
||||||
use crate::Weekday;
|
use crate::Weekday;
|
||||||
|
#[allow(deprecated)]
|
||||||
use crate::{Date, DateTime};
|
use crate::{Date, DateTime};
|
||||||
|
|
||||||
mod fixed;
|
mod fixed;
|
||||||
@ -84,6 +85,7 @@ impl<T> LocalResult<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<Tz: TimeZone> LocalResult<Date<Tz>> {
|
impl<Tz: TimeZone> LocalResult<Date<Tz>> {
|
||||||
/// Makes a new `DateTime` from the current date and given `NaiveTime`.
|
/// Makes a new `DateTime` from the current date and given `NaiveTime`.
|
||||||
/// The offset in the current date is preserved.
|
/// The offset in the current date is preserved.
|
||||||
@ -206,6 +208,27 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
/// The original `TimeZone` value can be recovered via `TimeZone::from_offset`.
|
/// The original `TimeZone` value can be recovered via `TimeZone::from_offset`.
|
||||||
type Offset: Offset;
|
type Offset: Offset;
|
||||||
|
|
||||||
|
/// Make a new `DateTime` from year, month, day, time components and current time zone.
|
||||||
|
///
|
||||||
|
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
||||||
|
///
|
||||||
|
/// Returns `LocalResult::None` on invalid input data.
|
||||||
|
fn with_ymd_and_hms(
|
||||||
|
&self,
|
||||||
|
year: i32,
|
||||||
|
month: u32,
|
||||||
|
day: u32,
|
||||||
|
hour: u32,
|
||||||
|
min: u32,
|
||||||
|
sec: u32,
|
||||||
|
) -> LocalResult<DateTime<Self>> {
|
||||||
|
match NaiveDate::from_ymd_opt(year, month, day).and_then(|d| d.and_hms_opt(hour, min, sec))
|
||||||
|
{
|
||||||
|
Some(dt) => self.from_local_datetime(&dt),
|
||||||
|
None => LocalResult::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes a new `Date` from year, month, day and the current time zone.
|
/// Makes a new `Date` from year, month, day and the current time zone.
|
||||||
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
||||||
///
|
///
|
||||||
@ -213,7 +236,8 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||||
///
|
///
|
||||||
/// Panics on the out-of-range date, invalid month and/or day.
|
/// Panics on the out-of-range date, invalid month and/or day.
|
||||||
#[deprecated(since = "0.4.23", note = "use `ymd_opt()` instead")]
|
#[deprecated(since = "0.4.23", note = "use `with_ymd_and_hms()` instead")]
|
||||||
|
#[allow(deprecated)]
|
||||||
fn ymd(&self, year: i32, month: u32, day: u32) -> Date<Self> {
|
fn ymd(&self, year: i32, month: u32, day: u32) -> Date<Self> {
|
||||||
self.ymd_opt(year, month, day).unwrap()
|
self.ymd_opt(year, month, day).unwrap()
|
||||||
}
|
}
|
||||||
@ -225,15 +249,8 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||||
///
|
///
|
||||||
/// Returns `None` on the out-of-range date, invalid month and/or day.
|
/// Returns `None` on the out-of-range date, invalid month and/or day.
|
||||||
///
|
#[deprecated(since = "0.4.23", note = "use `with_ymd_and_hms()` instead")]
|
||||||
/// # Example
|
#[allow(deprecated)]
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use chrono::{Utc, LocalResult, TimeZone};
|
|
||||||
///
|
|
||||||
/// assert_eq!(Utc.ymd_opt(2015, 5, 15).unwrap().to_string(), "2015-05-15UTC");
|
|
||||||
/// assert_eq!(Utc.ymd_opt(2000, 0, 0), LocalResult::None);
|
|
||||||
/// ```
|
|
||||||
fn ymd_opt(&self, year: i32, month: u32, day: u32) -> LocalResult<Date<Self>> {
|
fn ymd_opt(&self, year: i32, month: u32, day: u32) -> LocalResult<Date<Self>> {
|
||||||
match NaiveDate::from_ymd_opt(year, month, day) {
|
match NaiveDate::from_ymd_opt(year, month, day) {
|
||||||
Some(d) => self.from_local_date(&d),
|
Some(d) => self.from_local_date(&d),
|
||||||
@ -248,7 +265,11 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||||
///
|
///
|
||||||
/// Panics on the out-of-range date and/or invalid DOY.
|
/// Panics on the out-of-range date and/or invalid DOY.
|
||||||
#[deprecated(since = "0.4.23", note = "use `ymd_opt()` instead")]
|
#[deprecated(
|
||||||
|
since = "0.4.23",
|
||||||
|
note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
|
||||||
|
)]
|
||||||
|
#[allow(deprecated)]
|
||||||
fn yo(&self, year: i32, ordinal: u32) -> Date<Self> {
|
fn yo(&self, year: i32, ordinal: u32) -> Date<Self> {
|
||||||
self.yo_opt(year, ordinal).unwrap()
|
self.yo_opt(year, ordinal).unwrap()
|
||||||
}
|
}
|
||||||
@ -260,14 +281,11 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||||
///
|
///
|
||||||
/// Returns `None` on the out-of-range date and/or invalid DOY.
|
/// Returns `None` on the out-of-range date and/or invalid DOY.
|
||||||
///
|
#[deprecated(
|
||||||
/// # Example
|
since = "0.4.23",
|
||||||
///
|
note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
|
||||||
/// ```
|
)]
|
||||||
/// use chrono::{Utc, TimeZone};
|
#[allow(deprecated)]
|
||||||
///
|
|
||||||
/// assert_eq!(Utc.yo_opt(2015, 135).unwrap().to_string(), "2015-05-15UTC");
|
|
||||||
/// ```
|
|
||||||
fn yo_opt(&self, year: i32, ordinal: u32) -> LocalResult<Date<Self>> {
|
fn yo_opt(&self, year: i32, ordinal: u32) -> LocalResult<Date<Self>> {
|
||||||
match NaiveDate::from_yo_opt(year, ordinal) {
|
match NaiveDate::from_yo_opt(year, ordinal) {
|
||||||
Some(d) => self.from_local_date(&d),
|
Some(d) => self.from_local_date(&d),
|
||||||
@ -284,7 +302,11 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||||
///
|
///
|
||||||
/// Panics on the out-of-range date and/or invalid week number.
|
/// Panics on the out-of-range date and/or invalid week number.
|
||||||
#[deprecated(since = "0.4.23", note = "use `isoywd_opt()` instead")]
|
#[deprecated(
|
||||||
|
since = "0.4.23",
|
||||||
|
note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
|
||||||
|
)]
|
||||||
|
#[allow(deprecated)]
|
||||||
fn isoywd(&self, year: i32, week: u32, weekday: Weekday) -> Date<Self> {
|
fn isoywd(&self, year: i32, week: u32, weekday: Weekday) -> Date<Self> {
|
||||||
self.isoywd_opt(year, week, weekday).unwrap()
|
self.isoywd_opt(year, week, weekday).unwrap()
|
||||||
}
|
}
|
||||||
@ -298,14 +320,11 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
/// but it will propagate to the `DateTime` values constructed via this date.
|
/// but it will propagate to the `DateTime` values constructed via this date.
|
||||||
///
|
///
|
||||||
/// Returns `None` on the out-of-range date and/or invalid week number.
|
/// Returns `None` on the out-of-range date and/or invalid week number.
|
||||||
///
|
#[deprecated(
|
||||||
/// # Example
|
since = "0.4.23",
|
||||||
///
|
note = "use `from_local_datetime()` with a `NaiveDateTime` instead"
|
||||||
/// ```
|
)]
|
||||||
/// use chrono::{Utc, Weekday, TimeZone};
|
#[allow(deprecated)]
|
||||||
///
|
|
||||||
/// assert_eq!(Utc.isoywd_opt(2015, 20, Weekday::Fri).unwrap().to_string(), "2015-05-15UTC");
|
|
||||||
/// ```
|
|
||||||
fn isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> LocalResult<Date<Self>> {
|
fn isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> LocalResult<Date<Self>> {
|
||||||
match NaiveDate::from_isoywd_opt(year, week, weekday) {
|
match NaiveDate::from_isoywd_opt(year, week, weekday) {
|
||||||
Some(d) => self.from_local_date(&d),
|
Some(d) => self.from_local_date(&d),
|
||||||
@ -431,6 +450,8 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
|
|
||||||
/// Converts the local `NaiveDate` to the timezone-aware `Date` if possible.
|
/// Converts the local `NaiveDate` to the timezone-aware `Date` if possible.
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
|
#[deprecated(since = "0.4.23", note = "use `from_local_datetime()` instead")]
|
||||||
|
#[allow(deprecated)]
|
||||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Self>> {
|
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Self>> {
|
||||||
self.offset_from_local_date(local).map(|offset| {
|
self.offset_from_local_date(local).map(|offset| {
|
||||||
// since FixedOffset is within +/- 1 day, the date is never affected
|
// since FixedOffset is within +/- 1 day, the date is never affected
|
||||||
@ -454,6 +475,8 @@ pub trait TimeZone: Sized + Clone {
|
|||||||
/// Converts the UTC `NaiveDate` to the local time.
|
/// Converts the UTC `NaiveDate` to the local time.
|
||||||
/// The UTC is continuous and thus this cannot fail (but can give the duplicate local time).
|
/// The UTC is continuous and thus this cannot fail (but can give the duplicate local time).
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
|
#[deprecated(since = "0.4.23", note = "use `from_utc_datetime()` instead")]
|
||||||
|
#[allow(deprecated)]
|
||||||
fn from_utc_date(&self, utc: &NaiveDate) -> Date<Self> {
|
fn from_utc_date(&self, utc: &NaiveDate) -> Date<Self> {
|
||||||
Date::from_utc(*utc, self.offset_from_utc_date(utc))
|
Date::from_utc(*utc, self.offset_from_utc_date(utc))
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ use rkyv::{Archive, Deserialize, Serialize};
|
|||||||
use super::{FixedOffset, LocalResult, Offset, TimeZone};
|
use super::{FixedOffset, LocalResult, Offset, TimeZone};
|
||||||
use crate::naive::{NaiveDate, NaiveDateTime};
|
use crate::naive::{NaiveDate, NaiveDateTime};
|
||||||
#[cfg(feature = "clock")]
|
#[cfg(feature = "clock")]
|
||||||
|
#[allow(deprecated)]
|
||||||
use crate::{Date, DateTime};
|
use crate::{Date, DateTime};
|
||||||
|
|
||||||
/// The UTC time zone. This is the most efficient time zone when you don't need the local time.
|
/// The UTC time zone. This is the most efficient time zone when you don't need the local time.
|
||||||
@ -37,16 +38,22 @@ use crate::{Date, DateTime};
|
|||||||
/// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
|
/// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
|
||||||
///
|
///
|
||||||
/// assert_eq!(Utc.timestamp(61, 0), dt);
|
/// assert_eq!(Utc.timestamp(61, 0), dt);
|
||||||
/// assert_eq!(Utc.ymd_opt(1970, 1, 1).unwrap().and_hms_opt(0, 1, 1).unwrap(), dt);
|
/// assert_eq!(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap(), dt);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
||||||
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||||
pub struct Utc;
|
pub struct Utc;
|
||||||
|
|
||||||
#[cfg(feature = "clock")]
|
#[cfg(feature = "clock")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
|
||||||
impl Utc {
|
impl Utc {
|
||||||
/// Returns a `Date` which corresponds to the current date.
|
/// Returns a `Date` which corresponds to the current date.
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.4.23",
|
||||||
|
note = "use `Utc::now()` instead, potentially with `.date_naive()`"
|
||||||
|
)]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub fn today() -> Date<Utc> {
|
pub fn today() -> Date<Utc> {
|
||||||
Utc::now().date()
|
Utc::now().date()
|
||||||
}
|
}
|
||||||
|
229
src/round.rs
229
src/round.rs
@ -24,8 +24,8 @@ pub trait SubsecRound {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ``` rust
|
/// ``` rust
|
||||||
/// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc};
|
/// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate};
|
||||||
/// let dt = Utc.ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000);
|
/// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000);
|
||||||
/// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000);
|
/// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000);
|
||||||
/// ```
|
/// ```
|
||||||
@ -36,8 +36,8 @@ pub trait SubsecRound {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ``` rust
|
/// ``` rust
|
||||||
/// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc};
|
/// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc, NaiveDate};
|
||||||
/// let dt = Utc.ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000);
|
/// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000);
|
||||||
/// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000);
|
/// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000);
|
||||||
/// ```
|
/// ```
|
||||||
@ -111,8 +111,8 @@ pub trait DurationRound: Sized {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ``` rust
|
/// ``` rust
|
||||||
/// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc};
|
/// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc, NaiveDate};
|
||||||
/// let dt = Utc.ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(),
|
/// dt.duration_round(TimeDelta::milliseconds(10)).unwrap().to_string(),
|
||||||
/// "2018-01-11 12:00:00.150 UTC"
|
/// "2018-01-11 12:00:00.150 UTC"
|
||||||
@ -128,8 +128,8 @@ pub trait DurationRound: Sized {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ``` rust
|
/// ``` rust
|
||||||
/// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc};
|
/// # use chrono::{DateTime, DurationRound, TimeDelta, TimeZone, Utc, NaiveDate};
|
||||||
/// let dt = Utc.ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2018, 1, 11).unwrap().and_hms_milli_opt(12, 0, 0, 154).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(),
|
/// dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(),
|
||||||
/// "2018-01-11 12:00:00.150 UTC"
|
/// "2018-01-11 12:00:00.150 UTC"
|
||||||
@ -244,7 +244,7 @@ pub enum RoundingError {
|
|||||||
///
|
///
|
||||||
/// ``` rust
|
/// ``` rust
|
||||||
/// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc};
|
/// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc};
|
||||||
/// let dt = Utc.ymd_opt(1970, 12, 12).unwrap().and_hms_opt(0, 0, 0).unwrap();
|
/// let dt = Utc.with_ymd_and_hms(1970, 12, 12, 0, 0, 0).unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// dt.duration_round(TimeDelta::days(365)),
|
/// dt.duration_round(TimeDelta::days(365)),
|
||||||
@ -256,8 +256,8 @@ pub enum RoundingError {
|
|||||||
/// Error when `TimeDelta.num_nanoseconds` exceeds the limit.
|
/// Error when `TimeDelta.num_nanoseconds` exceeds the limit.
|
||||||
///
|
///
|
||||||
/// ``` rust
|
/// ``` rust
|
||||||
/// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc};
|
/// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc, NaiveDate};
|
||||||
/// let dt = Utc.ymd_opt(2260, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 1_75_500_000).unwrap();
|
/// let dt = NaiveDate::from_ymd_opt(2260, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 1_75_500_000).unwrap().and_local_timezone(Utc).unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// dt.duration_round(TimeDelta::days(300 * 365)),
|
/// dt.duration_round(TimeDelta::days(300 * 365)),
|
||||||
@ -270,7 +270,7 @@ pub enum RoundingError {
|
|||||||
///
|
///
|
||||||
/// ``` rust
|
/// ``` rust
|
||||||
/// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc};
|
/// # use chrono::{DateTime, DurationRound, TimeDelta, RoundingError, TimeZone, Utc};
|
||||||
/// let dt = Utc.ymd_opt(2300, 12, 12).unwrap().and_hms_opt(0, 0, 0).unwrap();
|
/// let dt = Utc.with_ymd_and_hms(2300, 12, 12, 0, 0, 0).unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(dt.duration_round(TimeDelta::days(1)), Err(RoundingError::TimestampExceedsLimit),);
|
/// assert_eq!(dt.duration_round(TimeDelta::days(1)), Err(RoundingError::TimestampExceedsLimit),);
|
||||||
/// ```
|
/// ```
|
||||||
@ -306,12 +306,20 @@ impl std::error::Error for RoundingError {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::{DurationRound, SubsecRound, TimeDelta};
|
use super::{DurationRound, SubsecRound, TimeDelta};
|
||||||
use crate::offset::{FixedOffset, TimeZone, Utc};
|
use crate::offset::{FixedOffset, TimeZone, Utc};
|
||||||
|
use crate::NaiveDate;
|
||||||
use crate::Timelike;
|
use crate::Timelike;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_round_subsecs() {
|
fn test_round_subsecs() {
|
||||||
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
||||||
let dt = pst.ymd_opt(2018, 1, 11).unwrap().and_hms_nano_opt(10, 5, 13, 84_660_684).unwrap();
|
let dt = pst
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2018, 1, 11)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(10, 5, 13, 84_660_684)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(dt.round_subsecs(10), dt);
|
assert_eq!(dt.round_subsecs(10), dt);
|
||||||
assert_eq!(dt.round_subsecs(9), dt);
|
assert_eq!(dt.round_subsecs(9), dt);
|
||||||
@ -327,8 +335,14 @@ mod tests {
|
|||||||
assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
|
assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
|
||||||
assert_eq!(dt.round_subsecs(0).second(), 13);
|
assert_eq!(dt.round_subsecs(0).second(), 13);
|
||||||
|
|
||||||
let dt =
|
let dt = Utc
|
||||||
Utc.ymd_opt(2018, 1, 11).unwrap().and_hms_nano_opt(10, 5, 27, 750_500_000).unwrap();
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2018, 1, 11)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(10, 5, 27, 750_500_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(dt.round_subsecs(9), dt);
|
assert_eq!(dt.round_subsecs(9), dt);
|
||||||
assert_eq!(dt.round_subsecs(4), dt);
|
assert_eq!(dt.round_subsecs(4), dt);
|
||||||
assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000);
|
assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000);
|
||||||
@ -341,8 +355,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_round_leap_nanos() {
|
fn test_round_leap_nanos() {
|
||||||
let dt =
|
let dt = Utc
|
||||||
Utc.ymd_opt(2016, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 1_750_500_000).unwrap();
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2016, 12, 31)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(23, 59, 59, 1_750_500_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(dt.round_subsecs(9), dt);
|
assert_eq!(dt.round_subsecs(9), dt);
|
||||||
assert_eq!(dt.round_subsecs(4), dt);
|
assert_eq!(dt.round_subsecs(4), dt);
|
||||||
assert_eq!(dt.round_subsecs(2).nanosecond(), 1_750_000_000);
|
assert_eq!(dt.round_subsecs(2).nanosecond(), 1_750_000_000);
|
||||||
@ -356,7 +376,14 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_trunc_subsecs() {
|
fn test_trunc_subsecs() {
|
||||||
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
|
||||||
let dt = pst.ymd_opt(2018, 1, 11).unwrap().and_hms_nano_opt(10, 5, 13, 84_660_684).unwrap();
|
let dt = pst
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2018, 1, 11)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(10, 5, 13, 84_660_684)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(dt.trunc_subsecs(10), dt);
|
assert_eq!(dt.trunc_subsecs(10), dt);
|
||||||
assert_eq!(dt.trunc_subsecs(9), dt);
|
assert_eq!(dt.trunc_subsecs(9), dt);
|
||||||
@ -372,8 +399,14 @@ mod tests {
|
|||||||
assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0);
|
assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0);
|
||||||
assert_eq!(dt.trunc_subsecs(0).second(), 13);
|
assert_eq!(dt.trunc_subsecs(0).second(), 13);
|
||||||
|
|
||||||
let dt =
|
let dt = pst
|
||||||
pst.ymd_opt(2018, 1, 11).unwrap().and_hms_nano_opt(10, 5, 27, 750_500_000).unwrap();
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2018, 1, 11)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(10, 5, 27, 750_500_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(dt.trunc_subsecs(9), dt);
|
assert_eq!(dt.trunc_subsecs(9), dt);
|
||||||
assert_eq!(dt.trunc_subsecs(4), dt);
|
assert_eq!(dt.trunc_subsecs(4), dt);
|
||||||
assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000);
|
assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000);
|
||||||
@ -386,8 +419,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_trunc_leap_nanos() {
|
fn test_trunc_leap_nanos() {
|
||||||
let dt =
|
let dt = Utc
|
||||||
Utc.ymd_opt(2016, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 1_750_500_000).unwrap();
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2016, 12, 31)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(23, 59, 59, 1_750_500_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(dt.trunc_subsecs(9), dt);
|
assert_eq!(dt.trunc_subsecs(9), dt);
|
||||||
assert_eq!(dt.trunc_subsecs(4), dt);
|
assert_eq!(dt.trunc_subsecs(4), dt);
|
||||||
assert_eq!(dt.trunc_subsecs(2).nanosecond(), 1_750_000_000);
|
assert_eq!(dt.trunc_subsecs(2).nanosecond(), 1_750_000_000);
|
||||||
@ -400,8 +439,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_duration_round() {
|
fn test_duration_round() {
|
||||||
let dt =
|
let dt = Utc
|
||||||
Utc.ymd_opt(2016, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 175_500_000).unwrap();
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2016, 12, 31)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(23, 59, 59, 175_500_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_round(TimeDelta::zero()).unwrap().to_string(),
|
dt.duration_round(TimeDelta::zero()).unwrap().to_string(),
|
||||||
@ -414,13 +459,27 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// round up
|
// round up
|
||||||
let dt = Utc.ymd_opt(2012, 12, 12).unwrap().and_hms_milli_opt(18, 22, 30, 0).unwrap();
|
let dt = Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2012, 12, 12)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(18, 22, 30, 0)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(),
|
dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(),
|
||||||
"2012-12-12 18:25:00 UTC"
|
"2012-12-12 18:25:00 UTC"
|
||||||
);
|
);
|
||||||
// round down
|
// round down
|
||||||
let dt = Utc.ymd_opt(2012, 12, 12).unwrap().and_hms_milli_opt(18, 22, 29, 999).unwrap();
|
let dt = Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2012, 12, 12)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(18, 22, 29, 999)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(),
|
dt.duration_round(TimeDelta::minutes(5)).unwrap().to_string(),
|
||||||
"2012-12-12 18:20:00 UTC"
|
"2012-12-12 18:20:00 UTC"
|
||||||
@ -444,12 +503,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// timezone east
|
// timezone east
|
||||||
let dt = FixedOffset::east_opt(3600)
|
let dt =
|
||||||
.unwrap()
|
FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
|
||||||
.ymd_opt(2020, 10, 27)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(15, 0, 0)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
|
dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
|
||||||
"2020-10-28 00:00:00 +01:00"
|
"2020-10-28 00:00:00 +01:00"
|
||||||
@ -460,12 +515,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// timezone west
|
// timezone west
|
||||||
let dt = FixedOffset::west_opt(3600)
|
let dt =
|
||||||
.unwrap()
|
FixedOffset::west_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
|
||||||
.ymd_opt(2020, 10, 27)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(15, 0, 0)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
|
dt.duration_round(TimeDelta::days(1)).unwrap().to_string(),
|
||||||
"2020-10-28 00:00:00 -01:00"
|
"2020-10-28 00:00:00 -01:00"
|
||||||
@ -479,9 +530,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_duration_round_naive() {
|
fn test_duration_round_naive() {
|
||||||
let dt = Utc
|
let dt = Utc
|
||||||
.ymd_opt(2016, 12, 31)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2016, 12, 31)
|
||||||
.and_hms_nano_opt(23, 59, 59, 175_500_000)
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(23, 59, 59, 175_500_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.naive_utc();
|
.naive_utc();
|
||||||
|
|
||||||
@ -497,9 +551,12 @@ mod tests {
|
|||||||
|
|
||||||
// round up
|
// round up
|
||||||
let dt = Utc
|
let dt = Utc
|
||||||
.ymd_opt(2012, 12, 12)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2012, 12, 12)
|
||||||
.and_hms_milli_opt(18, 22, 30, 0)
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(18, 22, 30, 0)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.naive_utc();
|
.naive_utc();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -508,9 +565,12 @@ mod tests {
|
|||||||
);
|
);
|
||||||
// round down
|
// round down
|
||||||
let dt = Utc
|
let dt = Utc
|
||||||
.ymd_opt(2012, 12, 12)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2012, 12, 12)
|
||||||
.and_hms_milli_opt(18, 22, 29, 999)
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(18, 22, 29, 999)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.naive_utc();
|
.naive_utc();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -538,7 +598,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_duration_round_pre_epoch() {
|
fn test_duration_round_pre_epoch() {
|
||||||
let dt = Utc.ymd_opt(1969, 12, 12).unwrap().and_hms_opt(12, 12, 12).unwrap();
|
let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(),
|
dt.duration_round(TimeDelta::minutes(10)).unwrap().to_string(),
|
||||||
"1969-12-12 12:10:00 UTC"
|
"1969-12-12 12:10:00 UTC"
|
||||||
@ -547,8 +607,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_duration_trunc() {
|
fn test_duration_trunc() {
|
||||||
let dt =
|
let dt = Utc
|
||||||
Utc.ymd_opt(2016, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 175_500_000).unwrap();
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2016, 12, 31)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(23, 59, 59, 175_500_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(),
|
dt.duration_trunc(TimeDelta::milliseconds(10)).unwrap().to_string(),
|
||||||
@ -556,13 +622,27 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// would round up
|
// would round up
|
||||||
let dt = Utc.ymd_opt(2012, 12, 12).unwrap().and_hms_milli_opt(18, 22, 30, 0).unwrap();
|
let dt = Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2012, 12, 12)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(18, 22, 30, 0)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(),
|
dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(),
|
||||||
"2012-12-12 18:20:00 UTC"
|
"2012-12-12 18:20:00 UTC"
|
||||||
);
|
);
|
||||||
// would round down
|
// would round down
|
||||||
let dt = Utc.ymd_opt(2012, 12, 12).unwrap().and_hms_milli_opt(18, 22, 29, 999).unwrap();
|
let dt = Utc
|
||||||
|
.from_local_datetime(
|
||||||
|
&NaiveDate::from_ymd_opt(2012, 12, 12)
|
||||||
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(18, 22, 29, 999)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(),
|
dt.duration_trunc(TimeDelta::minutes(5)).unwrap().to_string(),
|
||||||
"2012-12-12 18:20:00 UTC"
|
"2012-12-12 18:20:00 UTC"
|
||||||
@ -585,12 +665,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// timezone east
|
// timezone east
|
||||||
let dt = FixedOffset::east_opt(3600)
|
let dt =
|
||||||
.unwrap()
|
FixedOffset::east_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
|
||||||
.ymd_opt(2020, 10, 27)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(15, 0, 0)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
|
dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
|
||||||
"2020-10-27 00:00:00 +01:00"
|
"2020-10-27 00:00:00 +01:00"
|
||||||
@ -601,12 +677,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// timezone west
|
// timezone west
|
||||||
let dt = FixedOffset::west_opt(3600)
|
let dt =
|
||||||
.unwrap()
|
FixedOffset::west_opt(3600).unwrap().with_ymd_and_hms(2020, 10, 27, 15, 0, 0).unwrap();
|
||||||
.ymd_opt(2020, 10, 27)
|
|
||||||
.unwrap()
|
|
||||||
.and_hms_opt(15, 0, 0)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
|
dt.duration_trunc(TimeDelta::days(1)).unwrap().to_string(),
|
||||||
"2020-10-27 00:00:00 -01:00"
|
"2020-10-27 00:00:00 -01:00"
|
||||||
@ -620,9 +692,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_duration_trunc_naive() {
|
fn test_duration_trunc_naive() {
|
||||||
let dt = Utc
|
let dt = Utc
|
||||||
.ymd_opt(2016, 12, 31)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2016, 12, 31)
|
||||||
.and_hms_nano_opt(23, 59, 59, 175_500_000)
|
.unwrap()
|
||||||
|
.and_hms_nano_opt(23, 59, 59, 175_500_000)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.naive_utc();
|
.naive_utc();
|
||||||
|
|
||||||
@ -633,9 +708,12 @@ mod tests {
|
|||||||
|
|
||||||
// would round up
|
// would round up
|
||||||
let dt = Utc
|
let dt = Utc
|
||||||
.ymd_opt(2012, 12, 12)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2012, 12, 12)
|
||||||
.and_hms_milli_opt(18, 22, 30, 0)
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(18, 22, 30, 0)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.naive_utc();
|
.naive_utc();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -644,9 +722,12 @@ mod tests {
|
|||||||
);
|
);
|
||||||
// would round down
|
// would round down
|
||||||
let dt = Utc
|
let dt = Utc
|
||||||
.ymd_opt(2012, 12, 12)
|
.from_local_datetime(
|
||||||
.unwrap()
|
&NaiveDate::from_ymd_opt(2012, 12, 12)
|
||||||
.and_hms_milli_opt(18, 22, 29, 999)
|
.unwrap()
|
||||||
|
.and_hms_milli_opt(18, 22, 29, 999)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.naive_utc();
|
.naive_utc();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -673,7 +754,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_duration_trunc_pre_epoch() {
|
fn test_duration_trunc_pre_epoch() {
|
||||||
let dt = Utc.ymd_opt(1969, 12, 12).unwrap().and_hms_opt(12, 12, 12).unwrap();
|
let dt = Utc.with_ymd_and_hms(1969, 12, 12, 12, 12, 12).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(),
|
dt.duration_trunc(TimeDelta::minutes(10)).unwrap().to_string(),
|
||||||
"1969-12-12 12:10:00 UTC"
|
"1969-12-12 12:10:00 UTC"
|
||||||
|
@ -483,6 +483,24 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
|
|||||||
(this / other, this % other)
|
(this / other, this % other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
impl arbitrary::Arbitrary<'_> for TimeDelta {
|
||||||
|
fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
|
||||||
|
const MIN_SECS: i64 = i64::MIN / MILLIS_PER_SEC - 1;
|
||||||
|
const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
|
||||||
|
|
||||||
|
let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
|
||||||
|
let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
|
||||||
|
let duration = TimeDelta { secs, nanos };
|
||||||
|
|
||||||
|
if duration < MIN || duration > MAX {
|
||||||
|
Err(arbitrary::Error::IncorrectFormat)
|
||||||
|
} else {
|
||||||
|
Ok(duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{OutOfRangeError, TimeDelta, MAX, MIN};
|
use super::{OutOfRangeError, TimeDelta, MAX, MIN};
|
||||||
|
@ -12,6 +12,7 @@ use crate::OutOfRange;
|
|||||||
/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result.
|
/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result.
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
|
||||||
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
|
||||||
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||||
pub enum Weekday {
|
pub enum Weekday {
|
||||||
/// Monday.
|
/// Monday.
|
||||||
Mon = 0,
|
Mon = 0,
|
||||||
|
@ -19,7 +19,7 @@ fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) {
|
|||||||
// seems to be consistent with the output of the `date` command, so we simply
|
// seems to be consistent with the output of the `date` command, so we simply
|
||||||
// compare both.
|
// compare both.
|
||||||
// let local = Local
|
// let local = Local
|
||||||
// .from_local_datetime(&NaiveDate::from_ymd_opt(year, month, day).unwrap().and_hms_opt(hour, 5, 1).unwrap())
|
// .with_ymd_and_hms(year, month, day, hour, 5, 1)
|
||||||
// // looks like the "date" command always returns a given time when it is ambiguous
|
// // looks like the "date" command always returns a given time when it is ambiguous
|
||||||
// .earliest();
|
// .earliest();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user