diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 498ebad32..277060db0 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -8,7 +8,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- rust: [1.40.0, stable]
+ rust: [1.34.0, 1.36.0, stable]
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
@@ -23,30 +23,33 @@ jobs:
toolchain: ${{ matrix.rust }}
override: true
- - name: Run `cargo check --no-default-features`
+ # deprecated
+ - name: Run `cargo check --features alloc`
uses: actions-rs/cargo@v1
with:
command: check
args: --no-default-features
+ if: matrix.rust != '1.34.0' # alloc is unstable in 1.34
- - name: Run `cargo check --no-default-features --features serde`
+ # std, serde, deprecated
+ - name: Run `cargo check --features serde`
uses: actions-rs/cargo@v1
with:
command: check
args: --no-default-features --features serde
- - name: Run `cargo check --all-features`
+ # std, deprecated
+ - name: Run `cargo check`
uses: actions-rs/cargo@v1
with:
command: check
- args: --all-features
test:
name: Test suite
runs-on: ${{ matrix.os }}
strategy:
matrix:
- rust: [1.40.0, stable]
+ rust: [1.34.0, 1.36.0, stable] # 1.36 is when alloc was stabilized
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
@@ -61,17 +64,17 @@ jobs:
toolchain: ${{ matrix.rust }}
override: true
- - name: Run `cargo test --no-default-features`
+ - name: Run `cargo test --features alloc`
uses: actions-rs/cargo@v1
with:
command: test
- args: --no-default-features
+ args: --features alloc
+ if: matrix.rust != '1.34.0' # alloc is unstable in 1.34
- - name: Run `cargo test --all-features`
+ - name: Run `cargo test`
uses: actions-rs/cargo@v1
with:
command: test
- args: --all-features
fmt:
name: Formatting
@@ -117,8 +120,8 @@ jobs:
- name: Install clippy
run: rustup component add clippy
- - name: Run `cargo clippy --all-features`
+ - name: Run `cargo clippy --features serde,deprecated`
uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- args: --all-features
+ args: --features serde,deprecated
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index 7f60df5c6..8ce0de618 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -21,11 +21,11 @@ jobs:
toolchain: nightly # rust-lang/rust#43466, rust-lang/rust#43781
override: true
- - name: Run `cargo doc --all-features`
+ - name: Run `cargo doc --features serde,deprecated`
uses: actions-rs/cargo@v1
with:
command: doc
- args: --all-features
+ args: --features serde,deprecated
- name: Build & publish documentation
uses: JamesIves/github-pages-deploy-action@releases/v2
diff --git a/Cargo.toml b/Cargo.toml
index 46c5030ed..29d3b73ec 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,18 +11,19 @@ license = "MIT OR Apache-2.0"
# TODO Add GitHub Actions badge once rust-lang/crates.io#1838 is merged.
description = "Date and time library. Fully interoperable with the standard library. Mostly compatible with #![no_std]."
+[package.metadata.docs.rs]
+all-features = true
+
[features]
-default = ["std", "deprecated"]
+default = ["deprecated"]
deprecated = []
-std = []
+alloc = ["serde/alloc"]
panicking-api = []
[dependencies]
-serde = { version = "1", optional = true, default-features = false, features = ["derive", "alloc"] }
+serde = { version = "1", optional = true, default-features = false, features = ["derive"] }
time-macros = { version = "0.1", path = "time-macros" }
-
-[package.metadata.docs.rs]
-all-features = true
+rustversion = "1"
[workspace]
members = [
diff --git a/README.md b/README.md
index 473a81a72..82832ace2 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
[![Matrix](https://img.shields.io/badge/chat-Matrix/Riot-blue)](https://riot.im/app/#/room/!AAFrFkLHvtsXtMYRho:matrix.org)
![license](https://img.shields.io/badge/license-MIT%20or%20Apache--2-brightgreen)
![version](https://img.shields.io/crates/v/time)
-![rustc 1.40.0](https://img.shields.io/badge/rustc-1.40.0-blue)
+![rustc 1.34.0](https://img.shields.io/badge/rustc-1.34.0-blue)
[Documentation (master)](https://time-rs.github.io/time/time/index.html)
diff --git a/src/date.rs b/src/date.rs
index a3ca0bcfa..3969c7fb1 100644
--- a/src/date.rs
+++ b/src/date.rs
@@ -1,8 +1,10 @@
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
use crate::{
format::parse::{parse, ParseError, ParseResult, ParsedItems},
- internals, ComponentRangeError, DeferredFormat, Duration, PrimitiveDateTime, Time,
+ internals,
+ shim::*,
+ ComponentRangeError, DeferredFormat, Duration, PrimitiveDateTime, Time,
Weekday::{self, Friday, Monday, Saturday, Sunday, Thursday, Tuesday, Wednesday},
};
use core::{
@@ -272,8 +274,8 @@ impl Date {
/// assert!(Date::today().year() >= 2019);
/// ```
#[inline(always)]
- #[cfg(feature = "std")]
- #[cfg_attr(doc, doc(cfg(feature = "std")))]
+ #[cfg(not(feature = "alloc"))]
+ #[cfg_attr(doc, doc(cfg(not(feature = "alloc"))))]
pub fn today() -> Self {
PrimitiveDateTime::now().date()
}
@@ -524,7 +526,7 @@ impl Date {
match (day as i32 + (13 * (month as i32 + 1)) / 5 + adjusted_year + adjusted_year / 4
- adjusted_year / 100
+ adjusted_year / 400)
- .rem_euclid(7)
+ .rem_euclid_shim(7)
{
0 => Saturday,
1 => Sunday,
@@ -635,15 +637,20 @@ impl Date {
let f = julian_day + J + (((4 * julian_day + B) / 146_097) * 3) / 4 + C;
let e = R * f + V;
- let g = e.rem_euclid(P) / R;
+ let g = e.rem_euclid_shim(P) / R;
let h = U * g + W;
- let day = h.rem_euclid(S) / U + 1;
- let month = (h / S + M).rem_euclid(N) + 1;
+ let day = h.rem_euclid_shim(S) / U + 1;
+ let month = (h / S + M).rem_euclid_shim(N) + 1;
let year = (e / P) - Y + (N + M - month) / N;
// TODO Seek out a formal proof that this always results in a valid value.
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
- internals::Date::from_ymd_unchecked(year as i32, month as u8, day as u8)
+ Date::try_from_ymd(year as i32, month as u8, day as u8).unwrap_or_else(|e| {
+ unreachable!(
+ "Internal error. Please file an issue on the time repository.\n\n{}",
+ e
+ );
+ })
}
}
@@ -946,20 +953,17 @@ impl Date {
}
}
- // Verification for all components is done at parse time.
match items {
- items!(year, month, day) => Ok(internals::Date::from_ymd_unchecked(
- year,
- month.get(),
- day.get(),
- )),
+ items!(year, month, day) => {
+ Date::try_from_ymd(year, month.get(), day.get()).map_err(Into::into)
+ }
items!(year, ordinal_day) => {
- Ok(internals::Date::from_yo_unchecked(year, ordinal_day.get()))
+ Date::try_from_yo(year, ordinal_day.get()).map_err(Into::into)
+ }
+ items!(week_based_year, iso_week, weekday) => {
+ Date::try_from_iso_ywd(week_based_year, iso_week.get(), weekday).map_err(Into::into)
}
- items!(week_based_year, iso_week, weekday) => Ok(
- internals::Date::from_iso_ywd_unchecked(week_based_year, iso_week.get(), weekday),
- ),
- items!(year, sunday_week, weekday) => Ok(internals::Date::from_yo_unchecked(
+ items!(year, sunday_week, weekday) => Date::try_from_yo(
year,
#[allow(clippy::cast_sign_loss)]
{
@@ -967,8 +971,9 @@ impl Date {
- adjustment(year)
+ 1) as u16
},
- )),
- items!(year, monday_week, weekday) => Ok(internals::Date::from_yo_unchecked(
+ )
+ .map_err(Into::into),
+ items!(year, monday_week, weekday) => Date::try_from_yo(
year,
#[allow(clippy::cast_sign_loss)]
{
@@ -976,7 +981,8 @@ impl Date {
- adjustment(year)
+ 1) as u16
},
- )),
+ )
+ .map_err(Into::into),
_ => Err(ParseError::InsufficientInformation),
}
}
@@ -1079,7 +1085,6 @@ impl Ord for Date {
mod test {
use super::*;
use crate::{date, prelude::*, time};
- use alloc::collections::btree_set::BTreeSet;
macro_rules! julian {
($julian:literal) => {
@@ -1089,17 +1094,12 @@ mod test {
#[test]
fn weeks_in_year_exhaustive() {
- let mut years_with_53 = BTreeSet::new();
- for year in [
+ let years_with_53 = &[
4, 9, 15, 20, 26, 32, 37, 43, 48, 54, 60, 65, 71, 76, 82, 88, 93, 99, 105, 111, 116,
122, 128, 133, 139, 144, 150, 156, 161, 167, 172, 178, 184, 189, 195, 201, 207, 212,
218, 224, 229, 235, 240, 246, 252, 257, 263, 268, 274, 280, 285, 291, 296, 303, 308,
314, 320, 325, 331, 336, 342, 348, 353, 359, 364, 370, 376, 381, 387, 392, 398,
- ]
- .iter()
- {
- years_with_53.insert(year);
- }
+ ];
for year in 0..400 {
assert_eq!(
@@ -1536,423 +1536,399 @@ mod test {
#[test]
#[allow(clippy::zero_prefixed_literal)]
fn test_parse_monday_based_week() {
- macro_rules! assert_dwy {
- ($weekday:ident $week:literal $year:literal => $ordinal:literal) => {
- assert_eq!(
- Date::parse(
- concat!(
- stringify!($weekday),
- " ",
- stringify!($week),
- " ",
- stringify!($year)
- ),
- "%a %W %Y"
- ),
- Ok(date!($year - $ordinal))
- );
+ macro_rules! parse {
+ ($s:literal) => {
+ Date::parse($s, "%a %W %Y").unwrap()
};
}
// A
- assert_dwy!(Sun 00 2023 => 001);
- assert_dwy!(Mon 01 2023 => 002);
- assert_dwy!(Tue 01 2023 => 003);
- assert_dwy!(Wed 01 2023 => 004);
- assert_dwy!(Thu 01 2023 => 005);
- assert_dwy!(Fri 01 2023 => 006);
- assert_dwy!(Sat 01 2023 => 007);
+ assert_eq!(parse!("Sun 00 2023"), date!(2023-001));
+ assert_eq!(parse!("Mon 01 2023"), date!(2023-002));
+ assert_eq!(parse!("Tue 01 2023"), date!(2023-003));
+ assert_eq!(parse!("Wed 01 2023"), date!(2023-004));
+ assert_eq!(parse!("Thu 01 2023"), date!(2023-005));
+ assert_eq!(parse!("Fri 01 2023"), date!(2023-006));
+ assert_eq!(parse!("Sat 01 2023"), date!(2023-007));
// B
- assert_dwy!(Sat 00 2022 => 001);
- assert_dwy!(Sun 00 2022 => 002);
- assert_dwy!(Mon 01 2022 => 003);
- assert_dwy!(Tue 01 2022 => 004);
- assert_dwy!(Wed 01 2022 => 005);
- assert_dwy!(Thu 01 2022 => 006);
- assert_dwy!(Fri 01 2022 => 007);
+ assert_eq!(parse!("Sat 00 2022"), date!(2022-001));
+ assert_eq!(parse!("Sun 00 2022"), date!(2022-002));
+ assert_eq!(parse!("Mon 01 2022"), date!(2022-003));
+ assert_eq!(parse!("Tue 01 2022"), date!(2022-004));
+ assert_eq!(parse!("Wed 01 2022"), date!(2022-005));
+ assert_eq!(parse!("Thu 01 2022"), date!(2022-006));
+ assert_eq!(parse!("Fri 01 2022"), date!(2022-007));
// C
- assert_dwy!(Fri 00 2021 => 001);
- assert_dwy!(Sat 00 2021 => 002);
- assert_dwy!(Sun 00 2021 => 003);
- assert_dwy!(Mon 01 2021 => 004);
- assert_dwy!(Tue 01 2021 => 005);
- assert_dwy!(Wed 01 2021 => 006);
- assert_dwy!(Thu 01 2021 => 007);
+ assert_eq!(parse!("Fri 00 2021"), date!(2021-001));
+ assert_eq!(parse!("Sat 00 2021"), date!(2021-002));
+ assert_eq!(parse!("Sun 00 2021"), date!(2021-003));
+ assert_eq!(parse!("Mon 01 2021"), date!(2021-004));
+ assert_eq!(parse!("Tue 01 2021"), date!(2021-005));
+ assert_eq!(parse!("Wed 01 2021"), date!(2021-006));
+ assert_eq!(parse!("Thu 01 2021"), date!(2021-007));
// D
- assert_dwy!(Thu 00 2026 => 001);
- assert_dwy!(Fri 00 2026 => 002);
- assert_dwy!(Sat 00 2026 => 003);
- assert_dwy!(Sun 00 2026 => 004);
- assert_dwy!(Mon 01 2026 => 005);
- assert_dwy!(Tue 01 2026 => 006);
- assert_dwy!(Wed 01 2026 => 007);
+ assert_eq!(parse!("Thu 00 2026"), date!(2026-001));
+ assert_eq!(parse!("Fri 00 2026"), date!(2026-002));
+ assert_eq!(parse!("Sat 00 2026"), date!(2026-003));
+ assert_eq!(parse!("Sun 00 2026"), date!(2026-004));
+ assert_eq!(parse!("Mon 01 2026"), date!(2026-005));
+ assert_eq!(parse!("Tue 01 2026"), date!(2026-006));
+ assert_eq!(parse!("Wed 01 2026"), date!(2026-007));
// E
- assert_dwy!(Wed 00 2025 => 001);
- assert_dwy!(Thu 00 2025 => 002);
- assert_dwy!(Fri 00 2025 => 003);
- assert_dwy!(Sat 00 2025 => 004);
- assert_dwy!(Sun 00 2025 => 005);
- assert_dwy!(Mon 01 2025 => 006);
- assert_dwy!(Tue 01 2025 => 007);
+ assert_eq!(parse!("Wed 00 2025"), date!(2025-001));
+ assert_eq!(parse!("Thu 00 2025"), date!(2025-002));
+ assert_eq!(parse!("Fri 00 2025"), date!(2025-003));
+ assert_eq!(parse!("Sat 00 2025"), date!(2025-004));
+ assert_eq!(parse!("Sun 00 2025"), date!(2025-005));
+ assert_eq!(parse!("Mon 01 2025"), date!(2025-006));
+ assert_eq!(parse!("Tue 01 2025"), date!(2025-007));
// F
- assert_dwy!(Tue 00 2019 => 001);
- assert_dwy!(Wed 00 2019 => 002);
- assert_dwy!(Thu 00 2019 => 003);
- assert_dwy!(Fri 00 2019 => 004);
- assert_dwy!(Sat 00 2019 => 005);
- assert_dwy!(Sun 00 2019 => 006);
- assert_dwy!(Mon 01 2019 => 007);
+ assert_eq!(parse!("Tue 00 2019"), date!(2019-001));
+ assert_eq!(parse!("Wed 00 2019"), date!(2019-002));
+ assert_eq!(parse!("Thu 00 2019"), date!(2019-003));
+ assert_eq!(parse!("Fri 00 2019"), date!(2019-004));
+ assert_eq!(parse!("Sat 00 2019"), date!(2019-005));
+ assert_eq!(parse!("Sun 00 2019"), date!(2019-006));
+ assert_eq!(parse!("Mon 01 2019"), date!(2019-007));
// G
- assert_dwy!(Mon 01 2018 => 001);
- assert_dwy!(Tue 01 2018 => 002);
- assert_dwy!(Wed 01 2018 => 003);
- assert_dwy!(Thu 01 2018 => 004);
- assert_dwy!(Fri 01 2018 => 005);
- assert_dwy!(Sat 01 2018 => 006);
- assert_dwy!(Sun 01 2018 => 007);
+ assert_eq!(parse!("Mon 01 2018"), date!(2018-001));
+ assert_eq!(parse!("Tue 01 2018"), date!(2018-002));
+ assert_eq!(parse!("Wed 01 2018"), date!(2018-003));
+ assert_eq!(parse!("Thu 01 2018"), date!(2018-004));
+ assert_eq!(parse!("Fri 01 2018"), date!(2018-005));
+ assert_eq!(parse!("Sat 01 2018"), date!(2018-006));
+ assert_eq!(parse!("Sun 01 2018"), date!(2018-007));
// AG
- assert_dwy!(Sun 00 2012 => 001);
- assert_dwy!(Mon 01 2012 => 002);
- assert_dwy!(Tue 01 2012 => 003);
- assert_dwy!(Wed 01 2012 => 004);
- assert_dwy!(Thu 01 2012 => 005);
- assert_dwy!(Fri 01 2012 => 006);
- assert_dwy!(Sat 01 2012 => 007);
- assert_dwy!(Tue 09 2012 => 059);
- assert_dwy!(Wed 09 2012 => 060);
- assert_dwy!(Thu 09 2012 => 061);
- assert_dwy!(Fri 09 2012 => 062);
- assert_dwy!(Sat 09 2012 => 063);
- assert_dwy!(Sun 09 2012 => 064);
- assert_dwy!(Mon 10 2012 => 065);
- assert_dwy!(Tue 10 2012 => 066);
- assert_dwy!(Wed 10 2012 => 067);
+ assert_eq!(parse!("Sun 00 2012"), date!(2012-001));
+ assert_eq!(parse!("Mon 01 2012"), date!(2012-002));
+ assert_eq!(parse!("Tue 01 2012"), date!(2012-003));
+ assert_eq!(parse!("Wed 01 2012"), date!(2012-004));
+ assert_eq!(parse!("Thu 01 2012"), date!(2012-005));
+ assert_eq!(parse!("Fri 01 2012"), date!(2012-006));
+ assert_eq!(parse!("Sat 01 2012"), date!(2012-007));
+ assert_eq!(parse!("Tue 09 2012"), date!(2012-059));
+ assert_eq!(parse!("Wed 09 2012"), date!(2012-060));
+ assert_eq!(parse!("Thu 09 2012"), date!(2012-061));
+ assert_eq!(parse!("Fri 09 2012"), date!(2012-062));
+ assert_eq!(parse!("Sat 09 2012"), date!(2012-063));
+ assert_eq!(parse!("Sun 09 2012"), date!(2012-064));
+ assert_eq!(parse!("Mon 10 2012"), date!(2012-065));
+ assert_eq!(parse!("Tue 10 2012"), date!(2012-066));
+ assert_eq!(parse!("Wed 10 2012"), date!(2012-067));
// BA
- assert_dwy!(Sat 00 2028 => 001);
- assert_dwy!(Sun 00 2028 => 002);
- assert_dwy!(Mon 01 2028 => 003);
- assert_dwy!(Tue 01 2028 => 004);
- assert_dwy!(Wed 01 2028 => 005);
- assert_dwy!(Thu 01 2028 => 006);
- assert_dwy!(Fri 01 2028 => 007);
- assert_dwy!(Mon 09 2028 => 059);
- assert_dwy!(Tue 09 2028 => 060);
- assert_dwy!(Wed 09 2028 => 061);
- assert_dwy!(Thu 09 2028 => 062);
- assert_dwy!(Fri 09 2028 => 063);
- assert_dwy!(Sat 09 2028 => 064);
- assert_dwy!(Sun 09 2028 => 065);
- assert_dwy!(Mon 10 2028 => 066);
- assert_dwy!(Tue 10 2028 => 067);
+ assert_eq!(parse!("Sat 00 2028"), date!(2028-001));
+ assert_eq!(parse!("Sun 00 2028"), date!(2028-002));
+ assert_eq!(parse!("Mon 01 2028"), date!(2028-003));
+ assert_eq!(parse!("Tue 01 2028"), date!(2028-004));
+ assert_eq!(parse!("Wed 01 2028"), date!(2028-005));
+ assert_eq!(parse!("Thu 01 2028"), date!(2028-006));
+ assert_eq!(parse!("Fri 01 2028"), date!(2028-007));
+ assert_eq!(parse!("Mon 09 2028"), date!(2028-059));
+ assert_eq!(parse!("Tue 09 2028"), date!(2028-060));
+ assert_eq!(parse!("Wed 09 2028"), date!(2028-061));
+ assert_eq!(parse!("Thu 09 2028"), date!(2028-062));
+ assert_eq!(parse!("Fri 09 2028"), date!(2028-063));
+ assert_eq!(parse!("Sat 09 2028"), date!(2028-064));
+ assert_eq!(parse!("Sun 09 2028"), date!(2028-065));
+ assert_eq!(parse!("Mon 10 2028"), date!(2028-066));
+ assert_eq!(parse!("Tue 10 2028"), date!(2028-067));
// CB
- assert_dwy!(Fri 00 2016 => 001);
- assert_dwy!(Sat 00 2016 => 002);
- assert_dwy!(Sun 00 2016 => 003);
- assert_dwy!(Mon 01 2016 => 004);
- assert_dwy!(Tue 01 2016 => 005);
- assert_dwy!(Wed 01 2016 => 006);
- assert_dwy!(Thu 01 2016 => 007);
- assert_dwy!(Sun 08 2016 => 059);
- assert_dwy!(Mon 09 2016 => 060);
- assert_dwy!(Tue 09 2016 => 061);
- assert_dwy!(Wed 09 2016 => 062);
- assert_dwy!(Thu 09 2016 => 063);
- assert_dwy!(Fri 09 2016 => 064);
- assert_dwy!(Sat 09 2016 => 065);
- assert_dwy!(Sun 09 2016 => 066);
- assert_dwy!(Mon 10 2016 => 067);
+ assert_eq!(parse!("Fri 00 2016"), date!(2016-001));
+ assert_eq!(parse!("Sat 00 2016"), date!(2016-002));
+ assert_eq!(parse!("Sun 00 2016"), date!(2016-003));
+ assert_eq!(parse!("Mon 01 2016"), date!(2016-004));
+ assert_eq!(parse!("Tue 01 2016"), date!(2016-005));
+ assert_eq!(parse!("Wed 01 2016"), date!(2016-006));
+ assert_eq!(parse!("Thu 01 2016"), date!(2016-007));
+ assert_eq!(parse!("Sun 08 2016"), date!(2016-059));
+ assert_eq!(parse!("Mon 09 2016"), date!(2016-060));
+ assert_eq!(parse!("Tue 09 2016"), date!(2016-061));
+ assert_eq!(parse!("Wed 09 2016"), date!(2016-062));
+ assert_eq!(parse!("Thu 09 2016"), date!(2016-063));
+ assert_eq!(parse!("Fri 09 2016"), date!(2016-064));
+ assert_eq!(parse!("Sat 09 2016"), date!(2016-065));
+ assert_eq!(parse!("Sun 09 2016"), date!(2016-066));
+ assert_eq!(parse!("Mon 10 2016"), date!(2016-067));
// DC
- assert_dwy!(Thu 00 2032 => 001);
- assert_dwy!(Fri 00 2032 => 002);
- assert_dwy!(Sat 00 2032 => 003);
- assert_dwy!(Sun 00 2032 => 004);
- assert_dwy!(Mon 01 2032 => 005);
- assert_dwy!(Tue 01 2032 => 006);
- assert_dwy!(Wed 01 2032 => 007);
- assert_dwy!(Sat 08 2032 => 059);
- assert_dwy!(Sun 08 2032 => 060);
- assert_dwy!(Mon 09 2032 => 061);
- assert_dwy!(Tue 09 2032 => 062);
- assert_dwy!(Wed 09 2032 => 063);
- assert_dwy!(Thu 09 2032 => 064);
- assert_dwy!(Fri 09 2032 => 065);
- assert_dwy!(Sat 09 2032 => 066);
- assert_dwy!(Sun 09 2032 => 067);
+ assert_eq!(parse!("Thu 00 2032"), date!(2032-001));
+ assert_eq!(parse!("Fri 00 2032"), date!(2032-002));
+ assert_eq!(parse!("Sat 00 2032"), date!(2032-003));
+ assert_eq!(parse!("Sun 00 2032"), date!(2032-004));
+ assert_eq!(parse!("Mon 01 2032"), date!(2032-005));
+ assert_eq!(parse!("Tue 01 2032"), date!(2032-006));
+ assert_eq!(parse!("Wed 01 2032"), date!(2032-007));
+ assert_eq!(parse!("Sat 08 2032"), date!(2032-059));
+ assert_eq!(parse!("Sun 08 2032"), date!(2032-060));
+ assert_eq!(parse!("Mon 09 2032"), date!(2032-061));
+ assert_eq!(parse!("Tue 09 2032"), date!(2032-062));
+ assert_eq!(parse!("Wed 09 2032"), date!(2032-063));
+ assert_eq!(parse!("Thu 09 2032"), date!(2032-064));
+ assert_eq!(parse!("Fri 09 2032"), date!(2032-065));
+ assert_eq!(parse!("Sat 09 2032"), date!(2032-066));
+ assert_eq!(parse!("Sun 09 2032"), date!(2032-067));
// ED
- assert_dwy!(Wed 00 2020 => 001);
- assert_dwy!(Thu 00 2020 => 002);
- assert_dwy!(Fri 00 2020 => 003);
- assert_dwy!(Sat 00 2020 => 004);
- assert_dwy!(Sun 00 2020 => 005);
- assert_dwy!(Mon 01 2020 => 006);
- assert_dwy!(Tue 01 2020 => 007);
- assert_dwy!(Fri 08 2020 => 059);
- assert_dwy!(Sat 08 2020 => 060);
- assert_dwy!(Sun 08 2020 => 061);
- assert_dwy!(Mon 09 2020 => 062);
- assert_dwy!(Tue 09 2020 => 063);
- assert_dwy!(Wed 09 2020 => 064);
- assert_dwy!(Thu 09 2020 => 065);
- assert_dwy!(Fri 09 2020 => 066);
- assert_dwy!(Sat 09 2020 => 067);
+ assert_eq!(parse!("Wed 00 2020"), date!(2020-001));
+ assert_eq!(parse!("Thu 00 2020"), date!(2020-002));
+ assert_eq!(parse!("Fri 00 2020"), date!(2020-003));
+ assert_eq!(parse!("Sat 00 2020"), date!(2020-004));
+ assert_eq!(parse!("Sun 00 2020"), date!(2020-005));
+ assert_eq!(parse!("Mon 01 2020"), date!(2020-006));
+ assert_eq!(parse!("Tue 01 2020"), date!(2020-007));
+ assert_eq!(parse!("Fri 08 2020"), date!(2020-059));
+ assert_eq!(parse!("Sat 08 2020"), date!(2020-060));
+ assert_eq!(parse!("Sun 08 2020"), date!(2020-061));
+ assert_eq!(parse!("Mon 09 2020"), date!(2020-062));
+ assert_eq!(parse!("Tue 09 2020"), date!(2020-063));
+ assert_eq!(parse!("Wed 09 2020"), date!(2020-064));
+ assert_eq!(parse!("Thu 09 2020"), date!(2020-065));
+ assert_eq!(parse!("Fri 09 2020"), date!(2020-066));
+ assert_eq!(parse!("Sat 09 2020"), date!(2020-067));
// FE
- assert_dwy!(Tue 00 2036 => 001);
- assert_dwy!(Wed 00 2036 => 002);
- assert_dwy!(Thu 00 2036 => 003);
- assert_dwy!(Fri 00 2036 => 004);
- assert_dwy!(Sat 00 2036 => 005);
- assert_dwy!(Sun 00 2036 => 006);
- assert_dwy!(Mon 01 2036 => 007);
- assert_dwy!(Thu 08 2036 => 059);
- assert_dwy!(Fri 08 2036 => 060);
- assert_dwy!(Sat 08 2036 => 061);
- assert_dwy!(Sun 08 2036 => 062);
- assert_dwy!(Mon 09 2036 => 063);
- assert_dwy!(Tue 09 2036 => 064);
- assert_dwy!(Wed 09 2036 => 065);
- assert_dwy!(Thu 09 2036 => 066);
- assert_dwy!(Fri 09 2036 => 067);
+ assert_eq!(parse!("Tue 00 2036"), date!(2036-001));
+ assert_eq!(parse!("Wed 00 2036"), date!(2036-002));
+ assert_eq!(parse!("Thu 00 2036"), date!(2036-003));
+ assert_eq!(parse!("Fri 00 2036"), date!(2036-004));
+ assert_eq!(parse!("Sat 00 2036"), date!(2036-005));
+ assert_eq!(parse!("Sun 00 2036"), date!(2036-006));
+ assert_eq!(parse!("Mon 01 2036"), date!(2036-007));
+ assert_eq!(parse!("Thu 08 2036"), date!(2036-059));
+ assert_eq!(parse!("Fri 08 2036"), date!(2036-060));
+ assert_eq!(parse!("Sat 08 2036"), date!(2036-061));
+ assert_eq!(parse!("Sun 08 2036"), date!(2036-062));
+ assert_eq!(parse!("Mon 09 2036"), date!(2036-063));
+ assert_eq!(parse!("Tue 09 2036"), date!(2036-064));
+ assert_eq!(parse!("Wed 09 2036"), date!(2036-065));
+ assert_eq!(parse!("Thu 09 2036"), date!(2036-066));
+ assert_eq!(parse!("Fri 09 2036"), date!(2036-067));
// GF
- assert_dwy!(Mon 01 2024 => 001);
- assert_dwy!(Tue 01 2024 => 002);
- assert_dwy!(Wed 01 2024 => 003);
- assert_dwy!(Thu 01 2024 => 004);
- assert_dwy!(Fri 01 2024 => 005);
- assert_dwy!(Sat 01 2024 => 006);
- assert_dwy!(Sun 01 2024 => 007);
- assert_dwy!(Wed 09 2024 => 059);
- assert_dwy!(Thu 09 2024 => 060);
- assert_dwy!(Fri 09 2024 => 061);
- assert_dwy!(Sat 09 2024 => 062);
- assert_dwy!(Sun 09 2024 => 063);
- assert_dwy!(Mon 10 2024 => 064);
- assert_dwy!(Tue 10 2024 => 065);
- assert_dwy!(Wed 10 2024 => 066);
- assert_dwy!(Thu 10 2024 => 067);
+ assert_eq!(parse!("Mon 01 2024"), date!(2024-001));
+ assert_eq!(parse!("Tue 01 2024"), date!(2024-002));
+ assert_eq!(parse!("Wed 01 2024"), date!(2024-003));
+ assert_eq!(parse!("Thu 01 2024"), date!(2024-004));
+ assert_eq!(parse!("Fri 01 2024"), date!(2024-005));
+ assert_eq!(parse!("Sat 01 2024"), date!(2024-006));
+ assert_eq!(parse!("Sun 01 2024"), date!(2024-007));
+ assert_eq!(parse!("Wed 09 2024"), date!(2024-059));
+ assert_eq!(parse!("Thu 09 2024"), date!(2024-060));
+ assert_eq!(parse!("Fri 09 2024"), date!(2024-061));
+ assert_eq!(parse!("Sat 09 2024"), date!(2024-062));
+ assert_eq!(parse!("Sun 09 2024"), date!(2024-063));
+ assert_eq!(parse!("Mon 10 2024"), date!(2024-064));
+ assert_eq!(parse!("Tue 10 2024"), date!(2024-065));
+ assert_eq!(parse!("Wed 10 2024"), date!(2024-066));
+ assert_eq!(parse!("Thu 10 2024"), date!(2024-067));
}
#[test]
#[allow(clippy::zero_prefixed_literal)]
fn test_parse_sunday_based_week() {
- macro_rules! assert_dwy {
- ($weekday:ident $week:literal $year:literal => $ordinal:literal) => {
- assert_eq!(
- Date::parse(
- concat!(
- stringify!($weekday),
- " ",
- stringify!($week),
- " ",
- stringify!($year)
- ),
- "%a %U %Y"
- ),
- Ok(date!($year - $ordinal))
- );
+ macro_rules! parse {
+ ($s:literal) => {
+ Date::parse($s, "%a %U %Y").unwrap()
};
}
// A
- assert_dwy!(Sun 01 2018 => 001);
- assert_dwy!(Mon 01 2018 => 002);
- assert_dwy!(Tue 01 2018 => 003);
- assert_dwy!(Wed 01 2018 => 004);
- assert_dwy!(Thu 01 2018 => 005);
- assert_dwy!(Fri 01 2018 => 006);
- assert_dwy!(Sat 01 2018 => 007);
+ assert_eq!(parse!("Sun 01 2018"), date!(2018-001));
+ assert_eq!(parse!("Mon 01 2018"), date!(2018-002));
+ assert_eq!(parse!("Tue 01 2018"), date!(2018-003));
+ assert_eq!(parse!("Wed 01 2018"), date!(2018-004));
+ assert_eq!(parse!("Thu 01 2018"), date!(2018-005));
+ assert_eq!(parse!("Fri 01 2018"), date!(2018-006));
+ assert_eq!(parse!("Sat 01 2018"), date!(2018-007));
// B
- assert_dwy!(Sat 00 2023 => 001);
- assert_dwy!(Sun 01 2023 => 002);
- assert_dwy!(Mon 01 2023 => 003);
- assert_dwy!(Tue 01 2023 => 004);
- assert_dwy!(Wed 01 2023 => 005);
- assert_dwy!(Thu 01 2023 => 006);
- assert_dwy!(Fri 01 2023 => 007);
+ assert_eq!(parse!("Sat 00 2023"), date!(2023-001));
+ assert_eq!(parse!("Sun 01 2023"), date!(2023-002));
+ assert_eq!(parse!("Mon 01 2023"), date!(2023-003));
+ assert_eq!(parse!("Tue 01 2023"), date!(2023-004));
+ assert_eq!(parse!("Wed 01 2023"), date!(2023-005));
+ assert_eq!(parse!("Thu 01 2023"), date!(2023-006));
+ assert_eq!(parse!("Fri 01 2023"), date!(2023-007));
// C
- assert_dwy!(Fri 00 2022 => 001);
- assert_dwy!(Sat 00 2022 => 002);
- assert_dwy!(Sun 01 2022 => 003);
- assert_dwy!(Mon 01 2022 => 004);
- assert_dwy!(Tue 01 2022 => 005);
- assert_dwy!(Wed 01 2022 => 006);
- assert_dwy!(Thu 01 2022 => 007);
+ assert_eq!(parse!("Fri 00 2022"), date!(2022-001));
+ assert_eq!(parse!("Sat 00 2022"), date!(2022-002));
+ assert_eq!(parse!("Sun 01 2022"), date!(2022-003));
+ assert_eq!(parse!("Mon 01 2022"), date!(2022-004));
+ assert_eq!(parse!("Tue 01 2022"), date!(2022-005));
+ assert_eq!(parse!("Wed 01 2022"), date!(2022-006));
+ assert_eq!(parse!("Thu 01 2022"), date!(2022-007));
// D
- assert_dwy!(Thu 00 2021 => 001);
- assert_dwy!(Fri 00 2021 => 002);
- assert_dwy!(Sat 00 2021 => 003);
- assert_dwy!(Sun 01 2021 => 004);
- assert_dwy!(Mon 01 2021 => 005);
- assert_dwy!(Tue 01 2021 => 006);
- assert_dwy!(Wed 01 2021 => 007);
+ assert_eq!(parse!("Thu 00 2021"), date!(2021-001));
+ assert_eq!(parse!("Fri 00 2021"), date!(2021-002));
+ assert_eq!(parse!("Sat 00 2021"), date!(2021-003));
+ assert_eq!(parse!("Sun 01 2021"), date!(2021-004));
+ assert_eq!(parse!("Mon 01 2021"), date!(2021-005));
+ assert_eq!(parse!("Tue 01 2021"), date!(2021-006));
+ assert_eq!(parse!("Wed 01 2021"), date!(2021-007));
// E
- assert_dwy!(Wed 00 2026 => 001);
- assert_dwy!(Thu 00 2026 => 002);
- assert_dwy!(Fri 00 2026 => 003);
- assert_dwy!(Sat 00 2026 => 004);
- assert_dwy!(Sun 01 2026 => 005);
- assert_dwy!(Mon 01 2026 => 006);
- assert_dwy!(Tue 01 2026 => 007);
+ assert_eq!(parse!("Wed 00 2026"), date!(2026-001));
+ assert_eq!(parse!("Thu 00 2026"), date!(2026-002));
+ assert_eq!(parse!("Fri 00 2026"), date!(2026-003));
+ assert_eq!(parse!("Sat 00 2026"), date!(2026-004));
+ assert_eq!(parse!("Sun 01 2026"), date!(2026-005));
+ assert_eq!(parse!("Mon 01 2026"), date!(2026-006));
+ assert_eq!(parse!("Tue 01 2026"), date!(2026-007));
// F
- assert_dwy!(Tue 00 2025 => 001);
- assert_dwy!(Wed 00 2025 => 002);
- assert_dwy!(Thu 00 2025 => 003);
- assert_dwy!(Fri 00 2025 => 004);
- assert_dwy!(Sat 00 2025 => 005);
- assert_dwy!(Sun 01 2025 => 006);
- assert_dwy!(Mon 01 2025 => 007);
+ assert_eq!(parse!("Tue 00 2025"), date!(2025-001));
+ assert_eq!(parse!("Wed 00 2025"), date!(2025-002));
+ assert_eq!(parse!("Thu 00 2025"), date!(2025-003));
+ assert_eq!(parse!("Fri 00 2025"), date!(2025-004));
+ assert_eq!(parse!("Sat 00 2025"), date!(2025-005));
+ assert_eq!(parse!("Sun 01 2025"), date!(2025-006));
+ assert_eq!(parse!("Mon 01 2025"), date!(2025-007));
// G
- assert_dwy!(Mon 00 2019 => 001);
- assert_dwy!(Tue 00 2019 => 002);
- assert_dwy!(Wed 00 2019 => 003);
- assert_dwy!(Thu 00 2019 => 004);
- assert_dwy!(Fri 00 2019 => 005);
- assert_dwy!(Sat 00 2019 => 006);
- assert_dwy!(Sun 01 2019 => 007);
+ assert_eq!(parse!("Mon 00 2019"), date!(2019-001));
+ assert_eq!(parse!("Tue 00 2019"), date!(2019-002));
+ assert_eq!(parse!("Wed 00 2019"), date!(2019-003));
+ assert_eq!(parse!("Thu 00 2019"), date!(2019-004));
+ assert_eq!(parse!("Fri 00 2019"), date!(2019-005));
+ assert_eq!(parse!("Sat 00 2019"), date!(2019-006));
+ assert_eq!(parse!("Sun 01 2019"), date!(2019-007));
// AG
- assert_dwy!(Sun 01 2024 => 001);
- assert_dwy!(Mon 01 2024 => 002);
- assert_dwy!(Tue 01 2024 => 003);
- assert_dwy!(Wed 01 2024 => 004);
- assert_dwy!(Thu 01 2024 => 005);
- assert_dwy!(Fri 01 2024 => 006);
- assert_dwy!(Sat 01 2024 => 007);
- assert_dwy!(Tue 09 2024 => 059);
- assert_dwy!(Wed 09 2024 => 060);
- assert_dwy!(Thu 09 2024 => 061);
- assert_dwy!(Fri 09 2024 => 062);
- assert_dwy!(Sat 09 2024 => 063);
- assert_dwy!(Sun 10 2024 => 064);
- assert_dwy!(Mon 10 2024 => 065);
- assert_dwy!(Tue 10 2024 => 066);
- assert_dwy!(Wed 10 2024 => 067);
+ assert_eq!(parse!("Sun 01 2024"), date!(2024-001));
+ assert_eq!(parse!("Mon 01 2024"), date!(2024-002));
+ assert_eq!(parse!("Tue 01 2024"), date!(2024-003));
+ assert_eq!(parse!("Wed 01 2024"), date!(2024-004));
+ assert_eq!(parse!("Thu 01 2024"), date!(2024-005));
+ assert_eq!(parse!("Fri 01 2024"), date!(2024-006));
+ assert_eq!(parse!("Sat 01 2024"), date!(2024-007));
+ assert_eq!(parse!("Tue 09 2024"), date!(2024-059));
+ assert_eq!(parse!("Wed 09 2024"), date!(2024-060));
+ assert_eq!(parse!("Thu 09 2024"), date!(2024-061));
+ assert_eq!(parse!("Fri 09 2024"), date!(2024-062));
+ assert_eq!(parse!("Sat 09 2024"), date!(2024-063));
+ assert_eq!(parse!("Sun 10 2024"), date!(2024-064));
+ assert_eq!(parse!("Mon 10 2024"), date!(2024-065));
+ assert_eq!(parse!("Tue 10 2024"), date!(2024-066));
+ assert_eq!(parse!("Wed 10 2024"), date!(2024-067));
// BA
- assert_dwy!(Sat 00 2012 => 001);
- assert_dwy!(Sun 01 2012 => 002);
- assert_dwy!(Mon 01 2012 => 003);
- assert_dwy!(Tue 01 2012 => 004);
- assert_dwy!(Wed 01 2012 => 005);
- assert_dwy!(Thu 01 2012 => 006);
- assert_dwy!(Fri 01 2012 => 007);
- assert_dwy!(Mon 09 2012 => 059);
- assert_dwy!(Tue 09 2012 => 060);
- assert_dwy!(Wed 09 2012 => 061);
- assert_dwy!(Thu 09 2012 => 062);
- assert_dwy!(Fri 09 2012 => 063);
- assert_dwy!(Sat 09 2012 => 064);
- assert_dwy!(Sun 10 2012 => 065);
- assert_dwy!(Mon 10 2012 => 066);
- assert_dwy!(Tue 10 2012 => 067);
+ assert_eq!(parse!("Sat 00 2012"), date!(2012-001));
+ assert_eq!(parse!("Sun 01 2012"), date!(2012-002));
+ assert_eq!(parse!("Mon 01 2012"), date!(2012-003));
+ assert_eq!(parse!("Tue 01 2012"), date!(2012-004));
+ assert_eq!(parse!("Wed 01 2012"), date!(2012-005));
+ assert_eq!(parse!("Thu 01 2012"), date!(2012-006));
+ assert_eq!(parse!("Fri 01 2012"), date!(2012-007));
+ assert_eq!(parse!("Mon 09 2012"), date!(2012-059));
+ assert_eq!(parse!("Tue 09 2012"), date!(2012-060));
+ assert_eq!(parse!("Wed 09 2012"), date!(2012-061));
+ assert_eq!(parse!("Thu 09 2012"), date!(2012-062));
+ assert_eq!(parse!("Fri 09 2012"), date!(2012-063));
+ assert_eq!(parse!("Sat 09 2012"), date!(2012-064));
+ assert_eq!(parse!("Sun 10 2012"), date!(2012-065));
+ assert_eq!(parse!("Mon 10 2012"), date!(2012-066));
+ assert_eq!(parse!("Tue 10 2012"), date!(2012-067));
// CB
- assert_dwy!(Fri 00 2028 => 001);
- assert_dwy!(Sat 00 2028 => 002);
- assert_dwy!(Sun 01 2028 => 003);
- assert_dwy!(Mon 01 2028 => 004);
- assert_dwy!(Tue 01 2028 => 005);
- assert_dwy!(Wed 01 2028 => 006);
- assert_dwy!(Thu 01 2028 => 007);
- assert_dwy!(Sun 09 2028 => 059);
- assert_dwy!(Mon 09 2028 => 060);
- assert_dwy!(Tue 09 2028 => 061);
- assert_dwy!(Wed 09 2028 => 062);
- assert_dwy!(Thu 09 2028 => 063);
- assert_dwy!(Fri 09 2028 => 064);
- assert_dwy!(Sat 09 2028 => 065);
- assert_dwy!(Sun 10 2028 => 066);
- assert_dwy!(Mon 10 2028 => 067);
+ assert_eq!(parse!("Fri 00 2028"), date!(2028-001));
+ assert_eq!(parse!("Sat 00 2028"), date!(2028-002));
+ assert_eq!(parse!("Sun 01 2028"), date!(2028-003));
+ assert_eq!(parse!("Mon 01 2028"), date!(2028-004));
+ assert_eq!(parse!("Tue 01 2028"), date!(2028-005));
+ assert_eq!(parse!("Wed 01 2028"), date!(2028-006));
+ assert_eq!(parse!("Thu 01 2028"), date!(2028-007));
+ assert_eq!(parse!("Sun 09 2028"), date!(2028-059));
+ assert_eq!(parse!("Mon 09 2028"), date!(2028-060));
+ assert_eq!(parse!("Tue 09 2028"), date!(2028-061));
+ assert_eq!(parse!("Wed 09 2028"), date!(2028-062));
+ assert_eq!(parse!("Thu 09 2028"), date!(2028-063));
+ assert_eq!(parse!("Fri 09 2028"), date!(2028-064));
+ assert_eq!(parse!("Sat 09 2028"), date!(2028-065));
+ assert_eq!(parse!("Sun 10 2028"), date!(2028-066));
+ assert_eq!(parse!("Mon 10 2028"), date!(2028-067));
// DC
- assert_dwy!(Thu 00 2016 => 001);
- assert_dwy!(Fri 00 2016 => 002);
- assert_dwy!(Sat 00 2016 => 003);
- assert_dwy!(Sun 01 2016 => 004);
- assert_dwy!(Mon 01 2016 => 005);
- assert_dwy!(Tue 01 2016 => 006);
- assert_dwy!(Wed 01 2016 => 007);
- assert_dwy!(Sat 08 2016 => 059);
- assert_dwy!(Sun 09 2016 => 060);
- assert_dwy!(Mon 09 2016 => 061);
- assert_dwy!(Tue 09 2016 => 062);
- assert_dwy!(Wed 09 2016 => 063);
- assert_dwy!(Thu 09 2016 => 064);
- assert_dwy!(Fri 09 2016 => 065);
- assert_dwy!(Sat 09 2016 => 066);
- assert_dwy!(Sun 10 2016 => 067);
+ assert_eq!(parse!("Thu 00 2016"), date!(2016-001));
+ assert_eq!(parse!("Fri 00 2016"), date!(2016-002));
+ assert_eq!(parse!("Sat 00 2016"), date!(2016-003));
+ assert_eq!(parse!("Sun 01 2016"), date!(2016-004));
+ assert_eq!(parse!("Mon 01 2016"), date!(2016-005));
+ assert_eq!(parse!("Tue 01 2016"), date!(2016-006));
+ assert_eq!(parse!("Wed 01 2016"), date!(2016-007));
+ assert_eq!(parse!("Sat 08 2016"), date!(2016-059));
+ assert_eq!(parse!("Sun 09 2016"), date!(2016-060));
+ assert_eq!(parse!("Mon 09 2016"), date!(2016-061));
+ assert_eq!(parse!("Tue 09 2016"), date!(2016-062));
+ assert_eq!(parse!("Wed 09 2016"), date!(2016-063));
+ assert_eq!(parse!("Thu 09 2016"), date!(2016-064));
+ assert_eq!(parse!("Fri 09 2016"), date!(2016-065));
+ assert_eq!(parse!("Sat 09 2016"), date!(2016-066));
+ assert_eq!(parse!("Sun 10 2016"), date!(2016-067));
// ED
- assert_dwy!(Wed 00 2032 => 001);
- assert_dwy!(Thu 00 2032 => 002);
- assert_dwy!(Fri 00 2032 => 003);
- assert_dwy!(Sat 00 2032 => 004);
- assert_dwy!(Sun 01 2032 => 005);
- assert_dwy!(Mon 01 2032 => 006);
- assert_dwy!(Tue 01 2032 => 007);
- assert_dwy!(Fri 08 2032 => 059);
- assert_dwy!(Sat 08 2032 => 060);
- assert_dwy!(Sun 09 2032 => 061);
- assert_dwy!(Mon 09 2032 => 062);
- assert_dwy!(Tue 09 2032 => 063);
- assert_dwy!(Wed 09 2032 => 064);
- assert_dwy!(Thu 09 2032 => 065);
- assert_dwy!(Fri 09 2032 => 066);
- assert_dwy!(Sat 09 2032 => 067);
+ assert_eq!(parse!("Wed 00 2032"), date!(2032-001));
+ assert_eq!(parse!("Thu 00 2032"), date!(2032-002));
+ assert_eq!(parse!("Fri 00 2032"), date!(2032-003));
+ assert_eq!(parse!("Sat 00 2032"), date!(2032-004));
+ assert_eq!(parse!("Sun 01 2032"), date!(2032-005));
+ assert_eq!(parse!("Mon 01 2032"), date!(2032-006));
+ assert_eq!(parse!("Tue 01 2032"), date!(2032-007));
+ assert_eq!(parse!("Fri 08 2032"), date!(2032-059));
+ assert_eq!(parse!("Sat 08 2032"), date!(2032-060));
+ assert_eq!(parse!("Sun 09 2032"), date!(2032-061));
+ assert_eq!(parse!("Mon 09 2032"), date!(2032-062));
+ assert_eq!(parse!("Tue 09 2032"), date!(2032-063));
+ assert_eq!(parse!("Wed 09 2032"), date!(2032-064));
+ assert_eq!(parse!("Thu 09 2032"), date!(2032-065));
+ assert_eq!(parse!("Fri 09 2032"), date!(2032-066));
+ assert_eq!(parse!("Sat 09 2032"), date!(2032-067));
// FE
- assert_dwy!(Tue 00 2020 => 001);
- assert_dwy!(Wed 00 2020 => 002);
- assert_dwy!(Thu 00 2020 => 003);
- assert_dwy!(Fri 00 2020 => 004);
- assert_dwy!(Sat 00 2020 => 005);
- assert_dwy!(Sun 01 2020 => 006);
- assert_dwy!(Mon 01 2020 => 007);
- assert_dwy!(Thu 08 2020 => 059);
- assert_dwy!(Fri 08 2020 => 060);
- assert_dwy!(Sat 08 2020 => 061);
- assert_dwy!(Sun 09 2020 => 062);
- assert_dwy!(Mon 09 2020 => 063);
- assert_dwy!(Tue 09 2020 => 064);
- assert_dwy!(Wed 09 2020 => 065);
- assert_dwy!(Thu 09 2020 => 066);
- assert_dwy!(Fri 09 2020 => 067);
+ assert_eq!(parse!("Tue 00 2020"), date!(2020-001));
+ assert_eq!(parse!("Wed 00 2020"), date!(2020-002));
+ assert_eq!(parse!("Thu 00 2020"), date!(2020-003));
+ assert_eq!(parse!("Fri 00 2020"), date!(2020-004));
+ assert_eq!(parse!("Sat 00 2020"), date!(2020-005));
+ assert_eq!(parse!("Sun 01 2020"), date!(2020-006));
+ assert_eq!(parse!("Mon 01 2020"), date!(2020-007));
+ assert_eq!(parse!("Thu 08 2020"), date!(2020-059));
+ assert_eq!(parse!("Fri 08 2020"), date!(2020-060));
+ assert_eq!(parse!("Sat 08 2020"), date!(2020-061));
+ assert_eq!(parse!("Sun 09 2020"), date!(2020-062));
+ assert_eq!(parse!("Mon 09 2020"), date!(2020-063));
+ assert_eq!(parse!("Tue 09 2020"), date!(2020-064));
+ assert_eq!(parse!("Wed 09 2020"), date!(2020-065));
+ assert_eq!(parse!("Thu 09 2020"), date!(2020-066));
+ assert_eq!(parse!("Fri 09 2020"), date!(2020-067));
// GF
- assert_dwy!(Mon 00 2036 => 001);
- assert_dwy!(Tue 00 2036 => 002);
- assert_dwy!(Wed 00 2036 => 003);
- assert_dwy!(Thu 00 2036 => 004);
- assert_dwy!(Fri 00 2036 => 005);
- assert_dwy!(Sat 00 2036 => 006);
- assert_dwy!(Sun 01 2036 => 007);
- assert_dwy!(Wed 08 2036 => 059);
- assert_dwy!(Thu 08 2036 => 060);
- assert_dwy!(Fri 08 2036 => 061);
- assert_dwy!(Sat 08 2036 => 062);
- assert_dwy!(Sun 09 2036 => 063);
- assert_dwy!(Mon 09 2036 => 064);
- assert_dwy!(Tue 09 2036 => 065);
- assert_dwy!(Wed 09 2036 => 066);
- assert_dwy!(Thu 09 2036 => 067);
+ assert_eq!(parse!("Mon 00 2036"), date!(2036-001));
+ assert_eq!(parse!("Tue 00 2036"), date!(2036-002));
+ assert_eq!(parse!("Wed 00 2036"), date!(2036-003));
+ assert_eq!(parse!("Thu 00 2036"), date!(2036-004));
+ assert_eq!(parse!("Fri 00 2036"), date!(2036-005));
+ assert_eq!(parse!("Sat 00 2036"), date!(2036-006));
+ assert_eq!(parse!("Sun 01 2036"), date!(2036-007));
+ assert_eq!(parse!("Wed 08 2036"), date!(2036-059));
+ assert_eq!(parse!("Thu 08 2036"), date!(2036-060));
+ assert_eq!(parse!("Fri 08 2036"), date!(2036-061));
+ assert_eq!(parse!("Sat 08 2036"), date!(2036-062));
+ assert_eq!(parse!("Sun 09 2036"), date!(2036-063));
+ assert_eq!(parse!("Mon 09 2036"), date!(2036-064));
+ assert_eq!(parse!("Tue 09 2036"), date!(2036-065));
+ assert_eq!(parse!("Wed 09 2036"), date!(2036-066));
+ assert_eq!(parse!("Thu 09 2036"), date!(2036-067));
}
#[test]
@@ -2028,7 +2004,7 @@ mod test {
}
#[test]
- fn as_wo() {
+ fn as_yo() {
assert_eq!(date!(2019-01-01).as_yo(), (2019, 1));
}
diff --git a/src/duration.rs b/src/duration.rs
index ec569ca7a..bb3a4d507 100644
--- a/src/duration.rs
+++ b/src/duration.rs
@@ -1,4 +1,6 @@
-#[cfg(feature = "std")]
+#[allow(unused_imports)]
+use crate::shim::*;
+#[cfg(not(feature = "alloc"))]
use crate::Instant;
use crate::{
ConversionRangeError,
@@ -235,7 +237,8 @@ impl Duration {
/// assert_eq!(Duration::seconds(-1).abs(), Duration::seconds(1));
/// ```
#[inline(always)]
- pub const fn abs(self) -> Self {
+ #[rustversion::attr(since(1.39), const)]
+ pub fn abs(self) -> Self {
Self {
seconds: self.seconds.abs(),
nanoseconds: self.nanoseconds.abs(),
@@ -244,7 +247,7 @@ impl Duration {
/// Convert the existing `Duration` to a `std::time::Duration` and its sign.
#[inline(always)]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
pub(crate) fn sign_abs_std(self) -> (Sign, StdDuration) {
(
self.sign(),
@@ -746,8 +749,8 @@ impl Duration {
/// Runs a closure, returning the duration of time it took to run. The
/// return value of the closure is provided in the second part of the tuple.
#[inline(always)]
- #[cfg(feature = "std")]
- #[cfg_attr(doc, doc(cfg(feature = "std")))]
+ #[cfg(not(feature = "alloc"))]
+ #[cfg_attr(doc, doc(cfg(not(feature = "alloc"))))]
pub fn time_fn(f: impl FnOnce() -> T) -> (Self, T) {
let start = Instant::now();
let return_value = f();
@@ -849,7 +852,7 @@ impl Duration {
}
#[inline(always)]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
#[deprecated(since = "0.2.0", note = "Use the `time_fn` function")]
pub fn span(f: F) -> Self {
Self::time_fn(f).0
@@ -885,11 +888,11 @@ impl TryFrom for Duration {
original
.as_secs()
.try_into()
- .map_err(|_| ConversionRangeError)?,
+ .map_err(|_| ConversionRangeError::new())?,
original
.subsec_nanos()
.try_into()
- .map_err(|_| ConversionRangeError)?,
+ .map_err(|_| ConversionRangeError::new())?,
))
}
}
@@ -903,11 +906,11 @@ impl TryFrom for StdDuration {
duration
.seconds
.try_into()
- .map_err(|_| ConversionRangeError)?,
+ .map_err(|_| ConversionRangeError::new())?,
duration
.nanoseconds
.try_into()
- .map_err(|_| ConversionRangeError)?,
+ .map_err(|_| ConversionRangeError::new())?,
))
}
}
@@ -1556,7 +1559,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn time_fn() {
let (time, value) = Duration::time_fn(|| {
std::thread::sleep(100.std_milliseconds());
@@ -1699,7 +1702,7 @@ mod test {
duration -= 500.milliseconds();
assert_eq!(duration, 1.seconds());
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
{
let mut duration = 1.std_seconds();
assert_panics!(duration -= 2.seconds());
diff --git a/src/error.rs b/src/error.rs
index 819f44608..2c411e740 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,7 +1,9 @@
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
use crate::format::ParseError;
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
use core::fmt;
+#[cfg(not(feature = "alloc"))]
+use std::boxed::Box;
/// A unified error type for anything returned by a method in the time crate.
///
@@ -10,7 +12,11 @@ use core::fmt;
// Boxing the `ComponentRangeError` reduces the size of `Error` from 72 bytes to
// 16.
#[allow(clippy::missing_docs_in_private_items)] // variants only
-#[non_exhaustive]
+#[rustversion::attr(since(1.40), non_exhaustive)]
+#[rustversion::attr(
+ before(1.40),
+ doc("This enum is non-exhaustive. Additional variants may be added at any time.")
+)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
ConversionRange(ConversionRangeError),
@@ -22,21 +28,36 @@ impl fmt::Display for Error {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- Self::ConversionRange(e) => e.fmt(f),
- Self::ComponentRange(e) => e.fmt(f),
- Self::Parse(e) => e.fmt(f),
+ Error::ConversionRange(e) => e.fmt(f),
+ Error::ComponentRange(e) => e.fmt(f),
+ Error::Parse(e) => e.fmt(f),
}
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl std::error::Error for Error {}
/// An error type indicating that a conversion failed because the target type
/// could not store the initial value.
-#[non_exhaustive]
+#[allow(clippy::missing_docs_in_private_items)]
+#[rustversion::attr(since(1.40), non_exhaustive)]
+#[rustversion::attr(
+ before(1.40),
+ doc("This struct is non-exhaustive. Additional variants may be added at any time.")
+)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct ConversionRangeError;
+pub struct ConversionRangeError {
+ #[allow(clippy::missing_docs_in_private_items)]
+ nonexhaustive: (),
+}
+
+impl ConversionRangeError {
+ #[allow(clippy::missing_docs_in_private_items)]
+ pub(crate) const fn new() -> Self {
+ Self { nonexhaustive: () }
+ }
+}
impl fmt::Display for ConversionRangeError {
#[inline(always)]
@@ -45,13 +66,13 @@ impl fmt::Display for ConversionRangeError {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl std::error::Error for ConversionRangeError {}
impl From for Error {
#[inline(always)]
fn from(original: ConversionRangeError) -> Self {
- Self::ConversionRange(original)
+ Error::ConversionRange(original)
}
}
@@ -59,9 +80,12 @@ impl From for Error {
/// range, causing a failure.
// i64 is the narrowest type fitting all use cases. This eliminates the need
// for a type parameter.
-#[allow(missing_copy_implementations)] // Non-copy fields may be added.
-#[non_exhaustive]
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[rustversion::attr(since(1.40), non_exhaustive)]
+#[rustversion::attr(
+ before(1.40),
+ doc("This struct is non-exhaustive. Additional fields may be added at any time.")
+)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ComponentRangeError {
/// Name of the component.
pub(crate) name: &'static str,
@@ -99,16 +123,16 @@ impl fmt::Display for ComponentRangeError {
impl From for Error {
#[inline(always)]
fn from(original: ComponentRangeError) -> Self {
- Self::ComponentRange(Box::new(original))
+ Error::ComponentRange(Box::new(original))
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl std::error::Error for ComponentRangeError {}
impl From for Error {
#[inline(always)]
fn from(original: ParseError) -> Self {
- Self::Parse(original)
+ Error::Parse(original)
}
}
diff --git a/src/format/date.rs b/src/format/date.rs
index 83042ae8b..222e57a97 100644
--- a/src/format/date.rs
+++ b/src/format/date.rs
@@ -9,9 +9,9 @@ use super::{
},
Padding, ParseError, ParseResult, ParsedItems,
};
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
-use crate::{Date, Sign, Weekday};
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
+use crate::{shim::*, Date, Sign, Weekday};
use core::{
fmt::{self, Formatter},
num::{NonZeroU16, NonZeroU8},
@@ -141,7 +141,7 @@ pub(crate) fn parse_C(items: &mut ParsedItems, s: &mut &str, padding: Padding) -
items.year = (try_consume_digits::(s, (2 - padding_length)..=(3 - padding_length))
.ok_or(ParseError::InvalidYear)?
* 100
- + items.year.unwrap_or(0).rem_euclid(100))
+ + items.year.unwrap_or(0).rem_euclid_shim(100))
.into();
Ok(())
@@ -166,7 +166,12 @@ pub(crate) fn parse_d(items: &mut ParsedItems, s: &mut &str, padding: Padding) -
/// Week-based year, last two digits (`00`-`99`)
#[inline(always)]
pub(crate) fn fmt_g(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
- pad!(f, padding(Zero), 2, date.iso_year_week().0.rem_euclid(100))
+ pad!(
+ f,
+ padding(Zero),
+ 2,
+ date.iso_year_week().0.rem_euclid_shim(100)
+ )
}
/// Week-based year, last two digits (`00`-`99`)
@@ -222,10 +227,10 @@ pub(crate) fn fmt_j(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt:
/// Day of the year, zero-padded to width 3 (`001`-`366`)
#[inline(always)]
pub(crate) fn parse_j(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
- items.ordinal_day =
- try_consume_exact_digits::(s, 3, padding.default_to(Padding::Zero))
- .ok_or(ParseError::InvalidDayOfYear)?
- .into();
+ items.ordinal_day = NonZeroU16::new(
+ try_consume_exact_digits_in_range(s, 3, 1..=366, padding.default_to(Padding::Zero))
+ .ok_or(ParseError::InvalidDayOfYear)?,
+ );
Ok(())
}
@@ -239,9 +244,10 @@ pub(crate) fn fmt_m(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt:
/// Month of the year, zero-padded (`01`-`12`)
#[inline(always)]
pub(crate) fn parse_m(items: &mut ParsedItems, s: &mut &str, padding: Padding) -> ParseResult<()> {
- items.month = try_consume_exact_digits::(s, 2, padding.default_to(Padding::Zero))
- .ok_or(ParseError::InvalidMonth)?
- .into();
+ items.month = NonZeroU8::new(
+ try_consume_exact_digits_in_range(s, 2, 1..=12, padding.default_to(Padding::Zero))
+ .ok_or(ParseError::InvalidMonth)?,
+ );
Ok(())
}
@@ -343,7 +349,7 @@ pub(crate) fn parse_W(items: &mut ParsedItems, s: &mut &str, padding: Padding) -
/// Last two digits of year (`00`-`99`)
#[inline(always)]
pub(crate) fn fmt_y(f: &mut Formatter<'_>, date: Date, padding: Padding) -> fmt::Result {
- pad!(f, padding(Zero), 2, date.year().rem_euclid(100))
+ pad!(f, padding(Zero), 2, date.year().rem_euclid_shim(100))
}
/// Last two digits of year (`00`-`99`)
diff --git a/src/format/mod.rs b/src/format/mod.rs
index 120189183..d4e66bc50 100644
--- a/src/format/mod.rs
+++ b/src/format/mod.rs
@@ -37,8 +37,8 @@ pub(crate) mod parse;
pub(crate) mod parse_items;
pub(crate) mod time;
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
use crate::{Date, Time, UtcOffset};
use core::fmt::{self, Display, Formatter};
#[allow(unreachable_pub)] // rust-lang/rust#64762
@@ -71,7 +71,7 @@ impl Padding {
#[inline(always)]
pub(crate) fn default_to(self, value: Self) -> Self {
match self {
- Self::Default => value,
+ Padding::Default => value,
_ => self,
}
}
diff --git a/src/format/parse.rs b/src/format/parse.rs
index cbd19dcd9..a490fca57 100644
--- a/src/format/parse.rs
+++ b/src/format/parse.rs
@@ -1,22 +1,31 @@
//! Parsing for various types.
use super::{parse_fmt_string, FormatItem, Padding, Specifier};
-use crate::{UtcOffset, Weekday};
+use crate::{shim::*, ComponentRangeError, UtcOffset, Weekday};
use core::{
fmt::{self, Display, Formatter},
num::{NonZeroU16, NonZeroU8},
ops::{Bound, RangeBounds},
str::FromStr,
};
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
use std::error::Error;
+#[cfg(feature = "alloc")]
+use alloc::boxed::Box;
+#[cfg(not(feature = "alloc"))]
+use std::boxed::Box;
+
/// Helper type to avoid repeating the error type.
pub(crate) type ParseResult = Result;
/// An error ocurred while parsing.
-#[non_exhaustive]
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[rustversion::attr(since(1.40), non_exhaustive)]
+#[rustversion::attr(
+ before(1.40),
+ doc("This enum is non-exhaustive. Additional variants may be added at any time.")
+)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ParseError {
/// The second present was not valid.
InvalidSecond,
@@ -55,6 +64,15 @@ pub enum ParseError {
UnexpectedEndOfString,
/// There was not enough information provided to create the requested type.
InsufficientInformation,
+ /// A component was out of range.
+ ComponentOutOfRange(Box),
+}
+
+impl From for ParseError {
+ #[inline(always)]
+ fn from(error: ComponentRangeError) -> Self {
+ ParseError::ComponentOutOfRange(Box::new(error))
+ }
}
impl Display for ParseError {
@@ -82,11 +100,12 @@ impl Display for ParseError {
InsufficientInformation => {
f.write_str("insufficient information provided to create the requested type")
}
+ ComponentOutOfRange(e) => write!(f, "{}", e),
}
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl Error for ParseError {}
/// A value representing a time that is either "AM" or "PM".
@@ -252,7 +271,7 @@ pub(crate) fn try_consume_digits_in_range(
num_digits: impl RangeBounds,
range: impl RangeBounds,
) -> Option {
- try_consume_digits(s, num_digits).filter(|value| range.contains(value))
+ try_consume_digits(s, num_digits).filter(|value| range_contains(&range, value))
}
/// Attempt to consume an exact number of digits.
@@ -291,13 +310,13 @@ pub(crate) fn try_consume_exact_digits(
/// Attempt to consume an exact number of digits. Returns `None` if the value is
/// not within the allowed range.
#[inline]
-pub(crate) fn try_consume_exact_digits_in_range(
+pub(crate) fn try_consume_exact_digits_in_range>(
s: &mut &str,
num_digits: usize,
- range: impl RangeBounds,
+ range: U,
padding: Padding,
) -> Option {
- try_consume_exact_digits(s, num_digits, padding).filter(|value| range.contains(value))
+ try_consume_exact_digits(s, num_digits, padding).filter(|value| range_contains(&range, value))
}
/// Consume all leading padding up to the number of characters.
diff --git a/src/format/parse_items.rs b/src/format/parse_items.rs
index 94c283331..3386b7d2d 100644
--- a/src/format/parse_items.rs
+++ b/src/format/parse_items.rs
@@ -1,8 +1,8 @@
//! Parse formats used in the `format` and `parse` methods.
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
use crate::format::{FormatItem, Padding, Specifier};
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
/// Parse the formatting string. Panics if not valid.
#[inline(always)]
diff --git a/src/format/time.rs b/src/format/time.rs
index b55fbe589..6449b0135 100644
--- a/src/format/time.rs
+++ b/src/format/time.rs
@@ -10,6 +10,7 @@ use crate::{
},
Padding, ParseError, ParseResult, ParsedItems,
},
+ shim::*,
Time,
};
use core::{
@@ -40,7 +41,7 @@ pub(crate) fn fmt_I(f: &mut Formatter<'_>, time: Time, padding: Padding) -> fmt:
f,
padding(Zero),
2,
- (time.hour() as i8 - 1).rem_euclid(12) + 1
+ (time.hour() as i8 - 1).rem_euclid_shim(12) + 1
)
}
diff --git a/src/instant.rs b/src/instant.rs
index 29edb57b9..583ddae9d 100644
--- a/src/instant.rs
+++ b/src/instant.rs
@@ -30,7 +30,7 @@ use std::time::Instant as StdInstant;
///
/// This implementation allows for operations with signed [`Duration`]s, but is
/// otherwise identical to [`std::time::Instant`].
-#[cfg_attr(doc, doc(cfg(feature = "std")))]
+#[cfg_attr(doc, doc(cfg(not(feature = "alloc"))))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant {
/// Inner representation, using `std::time::Instant`.
diff --git a/src/lib.rs b/src/lib.rs
index 92a22b4cc..adf664dfe 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,18 +1,20 @@
//! Simple time handling.
//!
-//! ![rustc 1.40.0](https://img.shields.io/badge/rustc-1.40.0-blue)
+//! ![rustc 1.34.0](https://img.shields.io/badge/rustc-1.34.0-blue)
//!
//! # Feature flags in Cargo
//!
-//! ## `std`
+//! ## `alloc`
//!
//! Currently, all structs except `Instant` can be used with `#![no_std]`. As
//! support for the standard library is enabled by default, you muse use
-//! `default_features = false` in your `Cargo.toml` to enable this.
+//! the `alloc` feature to enable `#![no_std]` support. As time relies on an
+//! allocator for some functionality, a global allocator must be present. This
+//! inherently requires a greater minimum supported Rust version of 1.36.0.
//!
//! ```toml
//! [dependencies]
-//! time = { version = "0.2", default-features = false }
+//! time = { version = "0.2", features = ["alloc"] }
//! ```
//!
//! Of the structs that are usable, some methods may only be enabled due a
@@ -24,16 +26,9 @@
//! To enable it, use the `serde` feature. This is not enabled by default. It
//! _is_ compatible with `#![no_std]`, so long as an allocator is present.
//!
-//! With the standard library:
-//! ```toml
-//! [dependencies]
-//! time = { version = "0.2", features = ["serde"] }
-//! ```
-//!
-//! With `#![no_std]` support:
//! ```toml
//! [dependencies]
-//! time = { version = "0.2", default-features = false, features = ["serde"] }
+//! time = { version = "0.2", features = ["alloc", "serde"] }
//! ```
//!
//! ## `deprecated`
@@ -41,12 +36,11 @@
//! Using the `deprecated` feature allows using deprecated v0.1 methods. Enabled
//! by default.
//!
-//! With the standard library, the normal `time = 0.2` will work as expected.
+//! To _disable_ this feature:
//!
-//! With `#![no_std]` support:
//! ```toml
//! [dependencies]
-//! time = { version = "0.2", default-features = false, features = ["deprecated"] }
+//! time = { version = "0.2", default-features = false }
//! ```
//!
//! ## `panicking-api`
@@ -58,6 +52,9 @@
//!
//! Library authors should avoid using this feature.
//!
+//! This feature will be removed in a future release, as there are provided
+//! macros to perform the equivalent calculations at compile-time.
+//!
//! ```toml
//! [dependencies]
//! time = { version = "0.2", features = ["panicking-api"] }
@@ -119,7 +116,7 @@
//! | `0` | Pad with zeros | `%0d` => `05` |
#![cfg_attr(doc, feature(doc_cfg))]
-#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(feature = "alloc", no_std)]
#![forbid(unsafe_code)]
#![deny(
anonymous_parameters,
@@ -157,7 +154,7 @@
clippy::cast_possible_wrap,
clippy::cast_lossless,
clippy::module_name_repetitions,
- clippy::must_use_candidate // rust-lang/rust-clippy#4779
+ clippy::must_use_candidate
)]
#![cfg_attr(test, allow(clippy::cognitive_complexity, clippy::too_many_lines))]
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
@@ -168,6 +165,17 @@
// Unfortunately, this also means we can't have a `time` mod.
extern crate self as time;
+#[rustversion::before(1.34.0)]
+compile_error!("The time crate has a minimum supported rust version of 1.34.0.");
+
+#[cfg(feature = "alloc")]
+#[rustversion::before(1.36.0)]
+compile_error!(
+ "Using the time crate without the standard library enabled requires a global allocator. This \
+ was stabilized in Rust 1.36.0. You can either upgrade or enable the standard library."
+);
+
+#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;
@@ -191,26 +199,32 @@ macro_rules! format_conditional {
#[cfg_attr(doc, doc(cfg(feature = "panicking-api")))]
macro_rules! assert_value_in_range {
($value:ident in $start:expr => $end:expr) => {
- if !($start..=$end).contains(&$value) {
- panic!(
- concat!(stringify!($value), " must be in the range {}..={} (was {})"),
- $start,
- $end,
- $value,
- );
+ #[allow(unused_comparisons)]
+ {
+ if $value < $start || $value > $end {
+ panic!(
+ concat!(stringify!($value), " must be in the range {}..={} (was {})"),
+ $start,
+ $end,
+ $value,
+ );
+ }
}
};
($value:ident in $start:expr => $end:expr, given $($conditional:ident),+ $(,)?) => {
- if !($start..=$end).contains(&$value) {
- panic!(
- concat!(stringify!($value), " must be in the range {}..={} given{} (was {})"),
- $start,
- $end,
- &format_conditional!($($conditional),+),
- $value,
- );
- };
+ #[allow(unused_comparisons)]
+ {
+ if $value < $start || $value > $end {
+ panic!(
+ concat!(stringify!($value), " must be in the range {}..={} given{} (was {})"),
+ $start,
+ $end,
+ &format_conditional!($($conditional),+),
+ $value,
+ );
+ };
+ }
};
}
@@ -218,31 +232,37 @@ macro_rules! assert_value_in_range {
/// Returns `None` if the value is not in range.
macro_rules! ensure_value_in_range {
($value:ident in $start:expr => $end:expr) => {
- if !($start..=$end).contains(&$value) {
- return Err(ComponentRangeError {
- name: stringify!($value),
- minimum: i64::from($start),
- maximum: i64::from($end),
- value: i64::from($value),
- given: Vec::new(),
- });
+ #[allow(unused_comparisons)]
+ {
+ if $value < $start || $value > $end {
+ return Err(ComponentRangeError {
+ name: stringify!($value),
+ minimum: i64::from($start),
+ maximum: i64::from($end),
+ value: i64::from($value),
+ given: Vec::new(),
+ });
+ }
}
};
($value:ident in $start:expr => $end:expr, given $($conditional:ident),+ $(,)?) => {
- if !($start..=$end).contains(&$value) {
- return Err(ComponentRangeError {
- name: stringify!($value),
- minimum: i64::from($start),
- maximum: i64::from($end),
- value: i64::from($value),
- given: vec![$((stringify!($conditional), i64::from($conditional))),+],
- });
- };
+ #[allow(unused_comparisons)]
+ {
+ if $value < $start || $value > $end {
+ return Err(ComponentRangeError {
+ name: stringify!($value),
+ minimum: i64::from($start),
+ maximum: i64::from($end),
+ value: i64::from($value),
+ given: vec![$((stringify!($conditional), i64::from($conditional))),+],
+ });
+ };
+ }
};
}
-#[cfg(all(test, feature = "std"))]
+#[cfg(all(test, not(feature = "alloc")))]
macro_rules! assert_panics {
($e:expr $(, $message:literal)?) => {
#[allow(box_pointers)]
@@ -267,7 +287,7 @@ mod duration;
mod error;
mod format;
/// The `Instant` struct and its associated `impl`s.
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
mod instant;
pub mod internals;
/// A collection of traits extending built-in numerical types.
@@ -277,7 +297,10 @@ mod offset_date_time;
/// The `PrimitiveDateTime` struct and its associated `impl`s.
mod primitive_date_time;
#[cfg(feature = "serde")]
+#[allow(missing_copy_implementations, missing_debug_implementations)]
mod serde;
+/// Shims to provide functionality on older versions of rustc.
+mod shim;
/// The `Sign` struct and its associated `impl`s.
mod sign;
/// The `Time` struct and its associated `impl`s.
@@ -293,7 +316,7 @@ pub use error::{ComponentRangeError, ConversionRangeError, Error};
pub(crate) use format::DeferredFormat;
use format::ParseResult;
pub use format::{validate_format_string, ParseError};
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
pub use instant::Instant;
pub use numerical_traits::{NumericalDuration, NumericalStdDuration, NumericalStdDurationShort};
pub use offset_date_time::OffsetDateTime;
@@ -415,8 +438,8 @@ pub mod prelude {
/// A stable alternative to [`alloc::v1::prelude`](https://doc.rust-lang.org/stable/alloc/prelude/v1/index.html).
/// Useful anywhere `#![no_std]` is allowed.
-#[cfg(not(feature = "std"))]
-mod no_std_prelude {
+#[cfg(feature = "alloc")]
+mod alloc_prelude {
#![allow(unused_imports)]
pub(crate) use alloc::{
borrow::ToOwned,
@@ -426,6 +449,7 @@ mod no_std_prelude {
};
}
+#[allow(clippy::missing_docs_in_private_items)]
mod private {
use super::*;
@@ -474,19 +498,19 @@ pub fn parse(s: &str, format: &str) -> ParseResult {
// For some back-compatibility, we're also implementing some deprecated types
// and methods. They will be removed completely in 0.3.
-#[cfg(all(feature = "std", feature = "deprecated"))]
+#[cfg(all(not(feature = "alloc"), feature = "deprecated"))]
#[cfg_attr(tarpaulin, skip)]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(since = "0.2.0", note = "Use `Instant`")]
pub type PreciseTime = Instant;
-#[cfg(all(feature = "std", feature = "deprecated"))]
+#[cfg(all(not(feature = "alloc"), feature = "deprecated"))]
#[cfg_attr(tarpaulin, skip)]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(since = "0.2.0", note = "Use `Instant`")]
pub type SteadyTime = Instant;
-#[cfg(all(feature = "std", feature = "deprecated"))]
+#[cfg(all(not(feature = "alloc"), feature = "deprecated"))]
#[cfg_attr(tarpaulin, skip)]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(
@@ -503,7 +527,7 @@ pub fn precise_time_ns() -> u64 {
.expect("You really shouldn't be using this in the year 2554...")
}
-#[cfg(all(feature = "std", feature = "deprecated"))]
+#[cfg(all(not(feature = "alloc"), feature = "deprecated"))]
#[cfg_attr(tarpaulin, skip)]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(
diff --git a/src/offset_date_time.rs b/src/offset_date_time.rs
index 3451b751b..207ca8084 100644
--- a/src/offset_date_time.rs
+++ b/src/offset_date_time.rs
@@ -1,5 +1,5 @@
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
use crate::{
format::parse::{parse, ParseResult, ParsedItems},
offset, Date, DeferredFormat, Duration, PrimitiveDateTime, Time, UtcOffset, Weekday,
@@ -40,8 +40,8 @@ impl OffsetDateTime {
/// assert_eq!(OffsetDateTime::now().offset(), offset!(UTC));
/// ```
#[inline(always)]
- #[cfg(feature = "std")]
- #[cfg_attr(doc, doc(cfg(feature = "std")))]
+ #[cfg(not(feature = "alloc"))]
+ #[cfg_attr(doc, doc(cfg(not(feature = "alloc"))))]
pub fn now() -> Self {
PrimitiveDateTime::now().using_offset(offset!(UTC))
}
@@ -777,7 +777,7 @@ mod test {
use crate::{date, prelude::*, time};
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn now() {
assert!(OffsetDateTime::now().year() >= 2019);
assert_eq!(OffsetDateTime::now().offset(), offset!(UTC));
@@ -1204,7 +1204,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn hash() {
use std::{collections::hash_map::DefaultHasher, hash::Hash};
diff --git a/src/primitive_date_time.rs b/src/primitive_date_time.rs
index 032a9cfd5..4b843b28a 100644
--- a/src/primitive_date_time.rs
+++ b/src/primitive_date_time.rs
@@ -1,19 +1,19 @@
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
-#[cfg(feature = "std")]
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
+#[cfg(not(feature = "alloc"))]
use crate::Sign;
use crate::{
format::parse::{parse, ParseResult, ParsedItems},
time, Date, DeferredFormat, Duration, OffsetDateTime, Time, UtcOffset, Weekday,
};
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
use core::convert::{From, TryFrom};
use core::{
cmp::Ordering,
ops::{Add, AddAssign, Sub, SubAssign},
time::Duration as StdDuration,
};
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
use std::time::SystemTime;
/// Combined date and time.
@@ -55,8 +55,8 @@ impl PrimitiveDateTime {
/// assert!(PrimitiveDateTime::now().year() >= 2019);
/// ```
#[inline(always)]
- #[cfg(feature = "std")]
- #[cfg_attr(doc, doc(cfg(feature = "std")))]
+ #[cfg(not(feature = "alloc"))]
+ #[cfg_attr(doc, doc(cfg(not(feature = "alloc"))))]
pub fn now() -> Self {
SystemTime::now().into()
}
@@ -481,7 +481,7 @@ impl Add for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl Add for SystemTime {
type Output = Self;
@@ -528,7 +528,7 @@ impl AddAssign for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl AddAssign for SystemTime {
#[inline(always)]
fn add_assign(&mut self, duration: Duration) {
@@ -564,7 +564,7 @@ impl Sub for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl Sub for SystemTime {
type Output = Self;
@@ -588,7 +588,7 @@ impl SubAssign for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl SubAssign for SystemTime {
#[inline(always)]
fn sub_assign(&mut self, duration: Duration) {
@@ -605,7 +605,7 @@ impl Sub for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl Sub for PrimitiveDateTime {
type Output = Duration;
@@ -615,7 +615,7 @@ impl Sub for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl Sub for SystemTime {
type Output = Duration;
@@ -632,7 +632,7 @@ impl PartialOrd for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl PartialEq for PrimitiveDateTime {
#[inline(always)]
fn eq(&self, rhs: &SystemTime) -> bool {
@@ -640,7 +640,7 @@ impl PartialEq for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl PartialEq for SystemTime {
#[inline(always)]
fn eq(&self, rhs: &PrimitiveDateTime) -> bool {
@@ -648,7 +648,7 @@ impl PartialEq for SystemTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl PartialOrd for PrimitiveDateTime {
#[inline(always)]
fn partial_cmp(&self, other: &SystemTime) -> Option {
@@ -656,7 +656,7 @@ impl PartialOrd for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl PartialOrd for SystemTime {
#[inline(always)]
fn partial_cmp(&self, other: &PrimitiveDateTime) -> Option {
@@ -683,7 +683,7 @@ impl Ord for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
impl From for PrimitiveDateTime {
// There is definitely some way to have this conversion be infallible, but
// it won't be an issue for over 500 years.
@@ -700,7 +700,7 @@ impl From for PrimitiveDateTime {
}
}
-#[cfg(feature = "std")]
+#[cfg(not(feature = "alloc"))]
#[allow(clippy::fallible_impl_from)]
impl From for SystemTime {
#[inline]
@@ -731,7 +731,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn now() {
assert!(PrimitiveDateTime::now().year() >= 2019);
}
@@ -956,7 +956,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn std_add_duration() {
assert_eq!(
SystemTime::from(date!(2019-01-01).midnight()) + 5.days(),
@@ -1027,7 +1027,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn std_add_assign_duration() {
let mut ny19 = SystemTime::from(date!(2019-01-01).midnight());
ny19 += 5.days();
@@ -1087,7 +1087,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn std_sub_duration() {
assert_eq!(
SystemTime::from(date!(2019-01-06).midnight()) - 5.days(),
@@ -1142,7 +1142,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn std_sub_assign_duration() {
let mut ny19 = SystemTime::from(date!(2019-01-06).midnight());
ny19 -= 5.days();
@@ -1182,7 +1182,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn std_sub_datetime() {
assert_eq!(
SystemTime::from(date!(2019-01-02).midnight()) - date!(2019-01-01).midnight(),
@@ -1203,7 +1203,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn sub_std() {
assert_eq!(
date!(2019-01-02).midnight() - SystemTime::from(date!(2019-01-01).midnight()),
@@ -1319,7 +1319,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn eq_std() {
let now_datetime = PrimitiveDateTime::now();
let now_systemtime = SystemTime::from(now_datetime);
@@ -1327,16 +1327,16 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn std_eq() {
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
let now_datetime = PrimitiveDateTime::now();
let now_systemtime = SystemTime::from(now_datetime);
assert_eq!(now_datetime, now_systemtime);
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn ord_std() {
assert_eq!(
date!(2019-01-01).midnight(),
@@ -1383,7 +1383,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn std_ord() {
assert_eq!(
SystemTime::from(date!(2019-01-01).midnight()),
@@ -1430,7 +1430,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn from_std() {
assert_eq!(
PrimitiveDateTime::from(SystemTime::UNIX_EPOCH),
@@ -1439,7 +1439,7 @@ mod test {
}
#[test]
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
fn to_std() {
assert_eq!(
SystemTime::from(PrimitiveDateTime::unix_epoch()),
diff --git a/src/serde/sign.rs b/src/serde/sign.rs
index 2e056efd7..0f0eb6ea2 100644
--- a/src/serde/sign.rs
+++ b/src/serde/sign.rs
@@ -23,9 +23,9 @@ impl TryFrom for crate::Sign {
#[inline]
fn try_from(original: Sign) -> Result {
match original {
- Sign(1) => Ok(Self::Positive),
- Sign(-1) => Ok(Self::Negative),
- Sign(0) => Ok(Self::Zero),
+ Sign(1) => Ok(crate::Sign::Positive),
+ Sign(-1) => Ok(crate::Sign::Negative),
+ Sign(0) => Ok(crate::Sign::Zero),
_ => Err("invalid value"),
}
}
diff --git a/src/serde/weekday.rs b/src/serde/weekday.rs
index 9b45a1fc2..82c14dea5 100644
--- a/src/serde/weekday.rs
+++ b/src/serde/weekday.rs
@@ -17,13 +17,13 @@ impl TryFrom for crate::Weekday {
#[inline]
fn try_from(original: Weekday) -> Result {
match original {
- Weekday(1) => Ok(Self::Monday),
- Weekday(2) => Ok(Self::Tuesday),
- Weekday(3) => Ok(Self::Wednesday),
- Weekday(4) => Ok(Self::Thursday),
- Weekday(5) => Ok(Self::Friday),
- Weekday(6) => Ok(Self::Saturday),
- Weekday(7) => Ok(Self::Sunday),
+ Weekday(1) => Ok(crate::Weekday::Monday),
+ Weekday(2) => Ok(crate::Weekday::Tuesday),
+ Weekday(3) => Ok(crate::Weekday::Wednesday),
+ Weekday(4) => Ok(crate::Weekday::Thursday),
+ Weekday(5) => Ok(crate::Weekday::Friday),
+ Weekday(6) => Ok(crate::Weekday::Saturday),
+ Weekday(7) => Ok(crate::Weekday::Sunday),
_ => Err("invalid value"),
}
}
diff --git a/src/shim.rs b/src/shim.rs
new file mode 100644
index 000000000..74488110d
--- /dev/null
+++ b/src/shim.rs
@@ -0,0 +1,81 @@
+#![allow(clippy::missing_docs_in_private_items)]
+
+use core::{
+ ops::{
+ Bound::{Excluded, Included, Unbounded},
+ RangeBounds,
+ },
+ time::Duration,
+};
+
+/// Check if a range contains the given value. Equivalent to
+/// `range.contains(&item)`, but works on older compilers.
+pub(crate) fn range_contains(range: &impl RangeBounds, item: &U) -> bool
+where
+ T: PartialOrd,
+ U: ?Sized + PartialOrd,
+{
+ (match range.start_bound() {
+ Included(start) => start <= item,
+ Excluded(start) => start < item,
+ Unbounded => true,
+ }) && (match range.end_bound() {
+ Included(end) => item <= end,
+ Excluded(end) => item < end,
+ Unbounded => true,
+ })
+}
+
+pub(crate) trait EuclidShim {
+ /// Get the Euclidean remainder.
+ fn rem_euclid_shim(self, rhs: Self) -> Self;
+}
+
+macro_rules! impl_euclid_shim_signed {
+ ($($type:ty),* $(,)?) => {
+ $(
+ impl EuclidShim for $type {
+ #[inline]
+ fn rem_euclid_shim(self, rhs: Self) -> Self {
+ let r = self % rhs;
+ if r < 0 {
+ if rhs < 0 {
+ r - rhs
+ } else {
+ r + rhs
+ }
+ } else {
+ r
+ }
+ }
+ }
+ )*
+ };
+}
+impl_euclid_shim_signed![i8, i16, i32, i64, i128, isize];
+
+macro_rules! impl_euclid_shim_unsigned {
+ ($($type:ty),* $(,)?) => {
+ $(
+ impl EuclidShim for $type {
+ #[inline]
+ fn rem_euclid_shim(self, rhs: Self) -> Self {
+ self % rhs
+ }
+ }
+ )*
+ };
+}
+impl_euclid_shim_unsigned![u8, u16, u32, u64, u128, usize];
+
+pub(crate) trait DurationShim {
+ /// Get the number of seconds in a `Duration` as a 64 bit float.
+ fn as_secs_f64(&self) -> f64;
+}
+impl DurationShim for Duration {
+ #[inline]
+ #[allow(clippy::cast_precision_loss)]
+ fn as_secs_f64(&self) -> f64 {
+ (self.as_secs() as f64) + (self.as_nanos() as f64) / (1_000_000_000.)
+ }
+}
diff --git a/src/time_mod.rs b/src/time_mod.rs
index 032f4113f..09105e8e3 100644
--- a/src/time_mod.rs
+++ b/src/time_mod.rs
@@ -1,9 +1,10 @@
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
-#[cfg(feature = "std")]
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
+#[cfg(not(feature = "alloc"))]
use crate::PrimitiveDateTime;
use crate::{
format::{parse, parse::AmPm, ParseError, ParseResult, ParsedItems},
+ shim::*,
ComponentRangeError, DeferredFormat, Duration,
};
use core::{
@@ -401,8 +402,8 @@ impl Time {
/// println!("{:?}", Time::now());
/// ```
#[inline(always)]
- #[cfg(feature = "std")]
- #[cfg_attr(doc, doc(cfg(feature = "std")))]
+ #[cfg(not(feature = "alloc"))]
+ #[cfg_attr(doc, doc(cfg(not(feature = "alloc"))))]
pub fn now() -> Self {
PrimitiveDateTime::now().time()
}
@@ -588,25 +589,21 @@ impl Time {
}
match items {
- items!(hour_24, minute, second) => Ok(Self::try_from_hms(hour_24, minute, second)
- .expect("components are checked when parsing")),
+ items!(hour_24, minute, second) => {
+ Self::try_from_hms(hour_24, minute, second).map_err(Into::into)
+ }
items!(hour_12, minute, second, am_pm) => {
- Ok(
- Self::try_from_hms(hour_12_to_24(hour_12, am_pm), minute, second)
- .expect("components are checked when parsing"),
- )
+ Self::try_from_hms(hour_12_to_24(hour_12, am_pm), minute, second)
+ .map_err(Into::into)
}
- items!(hour_24, minute) => Ok(Self::try_from_hms(hour_24, minute, 0)
- .expect("components are checked when parsing")),
+ items!(hour_24, minute) => Self::try_from_hms(hour_24, minute, 0).map_err(Into::into),
items!(hour_12, minute, am_pm) => {
- Ok(Self::try_from_hms(hour_12_to_24(hour_12, am_pm), minute, 0)
- .expect("components are checked when parsing"))
+ Self::try_from_hms(hour_12_to_24(hour_12, am_pm), minute, 0).map_err(Into::into)
}
- items!(hour_24) => {
- Ok(Self::try_from_hms(hour_24, 0, 0).expect("components are checked when parsing"))
+ items!(hour_24) => Self::try_from_hms(hour_24, 0, 0).map_err(Into::into),
+ items!(hour_12, am_pm) => {
+ Self::try_from_hms(hour_12_to_24(hour_12, am_pm), 0, 0).map_err(Into::into)
}
- items!(hour_12, am_pm) => Ok(Self::try_from_hms(hour_12_to_24(hour_12, am_pm), 0, 0)
- .expect("components are checked when parsing")),
_ => Err(ParseError::InsufficientInformation),
}
}
@@ -636,7 +633,7 @@ impl Add for Time {
self.nanoseconds_since_midnight()
+ duration
.whole_nanoseconds()
- .rem_euclid(NANOS_PER_DAY as i128) as u64,
+ .rem_euclid_shim(NANOS_PER_DAY as i128) as u64,
)
}
}
@@ -890,7 +887,7 @@ mod test {
assert_eq!(time.second(), 3);
assert_eq!(time.nanosecond(), 0);
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
{
assert_panics!(Time::from_hms(24, 0, 0), "24 isn't a valid hour");
assert_panics!(Time::from_hms(0, 60, 0), "60 isn't a valid minute");
@@ -922,7 +919,7 @@ mod test {
assert_eq!(time.millisecond(), 4);
assert_eq!(time.nanosecond(), 4_000_000);
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
{
assert_panics!(Time::from_hms_milli(24, 0, 0, 0), "24 isn't a valid hour");
assert_panics!(Time::from_hms_milli(0, 60, 0, 0), "60 isn't a valid minute");
@@ -960,7 +957,7 @@ mod test {
assert_eq!(time.microsecond(), 4);
assert_eq!(time.nanosecond(), 4_000);
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
{
assert_panics!(Time::from_hms_micro(24, 0, 0, 0), "24 isn't a valid hour");
assert_panics!(Time::from_hms_micro(0, 60, 0, 0), "60 isn't a valid minute");
@@ -997,7 +994,7 @@ mod test {
assert_eq!(time.second(), 3);
assert_eq!(time.nanosecond(), 4);
- #[cfg(feature = "std")]
+ #[cfg(not(feature = "alloc"))]
{
assert_panics!(Time::from_hms_nano(24, 0, 0, 0), "24 isn't a valid hour.");
assert_panics!(Time::from_hms_nano(0, 60, 0, 0), "60 isn't a valid minute.");
diff --git a/src/utc_offset.rs b/src/utc_offset.rs
index a4c79b7f5..aba1b0f46 100644
--- a/src/utc_offset.rs
+++ b/src/utc_offset.rs
@@ -1,5 +1,5 @@
-#[cfg(not(feature = "std"))]
-use crate::no_std_prelude::*;
+#[cfg(feature = "alloc")]
+use crate::alloc_prelude::*;
use crate::{
format::{parse, ParseError, ParseResult, ParsedItems},
DeferredFormat, Duration,
diff --git a/time-macros-impl/src/date.rs b/time-macros-impl/src/date.rs
index d7421a932..cc0bb8945 100644
--- a/time-macros-impl/src/date.rs
+++ b/time-macros-impl/src/date.rs
@@ -36,9 +36,11 @@ impl Parse for Date {
let (year, ordinal) = if input.peek(Ident) {
let week = {
let week = input.parse::()?;
- match week.to_string() {
- s if s.starts_with("W") => LitInt::new(&s[1..], week.span()),
- _ => return error!(week.span(), "expected week value to start with `W`"),
+ let week_str = week.to_string();
+ if week_str.starts_with("W") {
+ LitInt::new(&week_str[1..], week.span())
+ } else {
+ return error!(week.span(), "expected week value to start with `W`");
}
};
input.parse::()?;
@@ -69,7 +71,7 @@ impl Parse for Date {
// TODO Replace use `LitInt` extension methods when dtolnay/syn#748 is
// resolved.
- if !(-100_000..=100_000).contains(&year) {
+ if year < -100_000 || year > 100_000 {
return error!(year_span, "value must be in the range -100_000..=100_000");
}
diff --git a/time-macros-impl/src/ext.rs b/time-macros-impl/src/ext.rs
index 2e62a41a5..f5aa790ca 100644
--- a/time-macros-impl/src/ext.rs
+++ b/time-macros-impl/src/ext.rs
@@ -1,3 +1,4 @@
+use crate::shim::*;
use proc_macro2::Span;
use std::{
fmt::{Debug, Display},
@@ -26,7 +27,7 @@ impl LitIntExtension for LitInt {
}
fn ensure_in_range(&self, range: impl RangeBounds + Debug) -> Result<()> {
- if range.contains(&self.value()?) {
+ if range_contains(&range, &self.value()?) {
Ok(())
} else {
error!(self.span(), "value must be in range {:?}", range)
diff --git a/time-macros-impl/src/lib.rs b/time-macros-impl/src/lib.rs
index 71cee0162..0fd1b4589 100644
--- a/time-macros-impl/src/lib.rs
+++ b/time-macros-impl/src/lib.rs
@@ -32,7 +32,8 @@
clippy::cast_possible_wrap,
clippy::cast_lossless,
clippy::module_name_repetitions,
- clippy::must_use_candidate
+ clippy::must_use_candidate,
+ clippy::use_self, // Some things aren't allowed in older compilers.
)]
extern crate proc_macro;
@@ -64,6 +65,7 @@ mod kw {
mod date;
mod ext;
mod offset;
+mod shim;
mod time;
mod time_crate;
diff --git a/time-macros-impl/src/shim.rs b/time-macros-impl/src/shim.rs
new file mode 100644
index 000000000..74488110d
--- /dev/null
+++ b/time-macros-impl/src/shim.rs
@@ -0,0 +1,81 @@
+#![allow(clippy::missing_docs_in_private_items)]
+
+use core::{
+ ops::{
+ Bound::{Excluded, Included, Unbounded},
+ RangeBounds,
+ },
+ time::Duration,
+};
+
+/// Check if a range contains the given value. Equivalent to
+/// `range.contains(&item)`, but works on older compilers.
+pub(crate) fn range_contains(range: &impl RangeBounds, item: &U) -> bool
+where
+ T: PartialOrd,
+ U: ?Sized + PartialOrd,
+{
+ (match range.start_bound() {
+ Included(start) => start <= item,
+ Excluded(start) => start < item,
+ Unbounded => true,
+ }) && (match range.end_bound() {
+ Included(end) => item <= end,
+ Excluded(end) => item < end,
+ Unbounded => true,
+ })
+}
+
+pub(crate) trait EuclidShim {
+ /// Get the Euclidean remainder.
+ fn rem_euclid_shim(self, rhs: Self) -> Self;
+}
+
+macro_rules! impl_euclid_shim_signed {
+ ($($type:ty),* $(,)?) => {
+ $(
+ impl EuclidShim for $type {
+ #[inline]
+ fn rem_euclid_shim(self, rhs: Self) -> Self {
+ let r = self % rhs;
+ if r < 0 {
+ if rhs < 0 {
+ r - rhs
+ } else {
+ r + rhs
+ }
+ } else {
+ r
+ }
+ }
+ }
+ )*
+ };
+}
+impl_euclid_shim_signed![i8, i16, i32, i64, i128, isize];
+
+macro_rules! impl_euclid_shim_unsigned {
+ ($($type:ty),* $(,)?) => {
+ $(
+ impl EuclidShim for $type {
+ #[inline]
+ fn rem_euclid_shim(self, rhs: Self) -> Self {
+ self % rhs
+ }
+ }
+ )*
+ };
+}
+impl_euclid_shim_unsigned![u8, u16, u32, u64, u128, usize];
+
+pub(crate) trait DurationShim {
+ /// Get the number of seconds in a `Duration` as a 64 bit float.
+ fn as_secs_f64(&self) -> f64;
+}
+impl DurationShim for Duration {
+ #[inline]
+ #[allow(clippy::cast_precision_loss)]
+ fn as_secs_f64(&self) -> f64 {
+ (self.as_secs() as f64) + (self.as_nanos() as f64) / (1_000_000_000.)
+ }
+}
diff --git a/time-macros-impl/src/time.rs b/time-macros-impl/src/time.rs
index 0f7aa2ed6..b03f21d25 100644
--- a/time-macros-impl/src/time.rs
+++ b/time-macros-impl/src/time.rs
@@ -17,16 +17,16 @@ impl Parse for AmPm {
use crate::kw::{am, pm, AM, PM};
if input.peek(am) {
input.parse::()?;
- Ok(Self::Am)
+ Ok(AmPm::Am)
} else if input.peek(AM) {
input.parse::()?;
- Ok(Self::Am)
+ Ok(AmPm::Am)
} else if input.peek(pm) {
input.parse::()?;
- Ok(Self::Pm)
+ Ok(AmPm::Pm)
} else if input.peek(PM) {
input.parse::()?;
- Ok(Self::Pm)
+ Ok(AmPm::Pm)
} else {
error!("expected am or pm")
}
diff --git a/time-macros-impl/src/time_crate/date.rs b/time-macros-impl/src/time_crate/date.rs
index 1e033afd0..ac088915c 100644
--- a/time-macros-impl/src/time_crate/date.rs
+++ b/time-macros-impl/src/time_crate/date.rs
@@ -1,4 +1,5 @@
use super::Weekday::{self, *};
+use crate::shim::*;
fn is_leap_year(year: i32) -> bool {
(year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))
@@ -89,7 +90,7 @@ impl Date {
match (day as i32 + (13 * (month as i32 + 1)) / 5 + adjusted_year + adjusted_year / 4
- adjusted_year / 100
+ adjusted_year / 400)
- .rem_euclid(7)
+ .rem_euclid_shim(7)
{
0 => Saturday,
1 => Sunday,