mirror of
https://github.com/chronotope/chrono.git
synced 2025-09-30 14:32:19 +00:00
Remove dependency on num-traits
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
This commit is contained in:
parent
eb927846b6
commit
b0983c25d9
@ -4,7 +4,7 @@
|
||||
//! A collection of parsed date and time items.
|
||||
//! They can be constructed incrementally while being checked for consistency.
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
use core::convert::TryFrom;
|
||||
|
||||
use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
|
||||
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
|
||||
@ -136,7 +136,7 @@ impl Parsed {
|
||||
/// Tries to set the [`year`](#structfield.year) field from given value.
|
||||
#[inline]
|
||||
pub fn set_year(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.year, value.to_i32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value.
|
||||
@ -145,7 +145,7 @@ impl Parsed {
|
||||
if value < 0 {
|
||||
return Err(OUT_OF_RANGE);
|
||||
}
|
||||
set_if_consistent(&mut self.year_div_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value.
|
||||
@ -154,13 +154,13 @@ impl Parsed {
|
||||
if value < 0 {
|
||||
return Err(OUT_OF_RANGE);
|
||||
}
|
||||
set_if_consistent(&mut self.year_mod_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`isoyear`](#structfield.isoyear) field from given value.
|
||||
#[inline]
|
||||
pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.isoyear, value.to_i32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value.
|
||||
@ -169,7 +169,10 @@ impl Parsed {
|
||||
if value < 0 {
|
||||
return Err(OUT_OF_RANGE);
|
||||
}
|
||||
set_if_consistent(&mut self.isoyear_div_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(
|
||||
&mut self.isoyear_div_100,
|
||||
i32::try_from(value).map_err(|_| OUT_OF_RANGE)?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value.
|
||||
@ -178,31 +181,34 @@ impl Parsed {
|
||||
if value < 0 {
|
||||
return Err(OUT_OF_RANGE);
|
||||
}
|
||||
set_if_consistent(&mut self.isoyear_mod_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(
|
||||
&mut self.isoyear_mod_100,
|
||||
i32::try_from(value).map_err(|_| OUT_OF_RANGE)?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tries to set the [`month`](#structfield.month) field from given value.
|
||||
#[inline]
|
||||
pub fn set_month(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.month, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value.
|
||||
#[inline]
|
||||
pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.week_from_sun, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value.
|
||||
#[inline]
|
||||
pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.week_from_mon, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`isoweek`](#structfield.isoweek) field from given value.
|
||||
#[inline]
|
||||
pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.isoweek, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`weekday`](#structfield.weekday) field from given value.
|
||||
@ -214,13 +220,13 @@ impl Parsed {
|
||||
/// Tries to set the [`ordinal`](#structfield.ordinal) field from given value.
|
||||
#[inline]
|
||||
pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.ordinal, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`day`](#structfield.day) field from given value.
|
||||
#[inline]
|
||||
pub fn set_day(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.day, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value.
|
||||
@ -244,7 +250,7 @@ impl Parsed {
|
||||
/// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value.
|
||||
#[inline]
|
||||
pub fn set_hour(&mut self, value: i64) -> ParseResult<()> {
|
||||
let v = value.to_u32().ok_or(OUT_OF_RANGE)?;
|
||||
let v = u32::try_from(value).map_err(|_| OUT_OF_RANGE)?;
|
||||
set_if_consistent(&mut self.hour_div_12, v / 12)?;
|
||||
set_if_consistent(&mut self.hour_mod_12, v % 12)?;
|
||||
Ok(())
|
||||
@ -253,19 +259,19 @@ impl Parsed {
|
||||
/// Tries to set the [`minute`](#structfield.minute) field from given value.
|
||||
#[inline]
|
||||
pub fn set_minute(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.minute, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`second`](#structfield.second) field from given value.
|
||||
#[inline]
|
||||
pub fn set_second(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.second, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value.
|
||||
#[inline]
|
||||
pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.nanosecond, value.to_u32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Tries to set the [`timestamp`](#structfield.timestamp) field from given value.
|
||||
@ -277,7 +283,7 @@ impl Parsed {
|
||||
/// Tries to set the [`offset`](#structfield.offset) field from given value.
|
||||
#[inline]
|
||||
pub fn set_offset(&mut self, value: i64) -> ParseResult<()> {
|
||||
set_if_consistent(&mut self.offset, value.to_i32().ok_or(OUT_OF_RANGE)?)
|
||||
set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
|
||||
}
|
||||
|
||||
/// Returns a parsed naive date out of given fields.
|
||||
|
29
src/lib.rs
29
src/lib.rs
@ -422,6 +422,8 @@ mod oldtime;
|
||||
// this reexport is to aid the transition and should not be in the prelude!
|
||||
pub use oldtime::{Duration, OutOfRangeError};
|
||||
|
||||
use core::fmt;
|
||||
|
||||
#[cfg(feature = "__doctest")]
|
||||
#[cfg_attr(feature = "__doctest", cfg(doctest))]
|
||||
use doc_comment::doctest;
|
||||
@ -517,3 +519,30 @@ pub use naive::__BenchYearFlags;
|
||||
pub mod serde {
|
||||
pub use super::datetime::serde::*;
|
||||
}
|
||||
|
||||
/// Out of range error type used in various converting APIs
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct OutOfRange {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl OutOfRange {
|
||||
const fn new() -> OutOfRange {
|
||||
OutOfRange { _private: () }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OutOfRange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "out of range")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for OutOfRange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "out of range")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for OutOfRange {}
|
||||
|
49
src/month.rs
49
src/month.rs
@ -1,8 +1,10 @@
|
||||
use core::fmt;
|
||||
use core::{convert::TryFrom, fmt};
|
||||
|
||||
#[cfg(feature = "rkyv")]
|
||||
use rkyv::{Archive, Deserialize, Serialize};
|
||||
|
||||
use crate::OutOfRange;
|
||||
|
||||
/// The month of the year.
|
||||
///
|
||||
/// This enum is just a convenience implementation.
|
||||
@ -10,11 +12,11 @@ use rkyv::{Archive, Deserialize, Serialize};
|
||||
///
|
||||
/// It is possible to convert from a date to a month independently
|
||||
/// ```
|
||||
/// use num_traits::FromPrimitive;
|
||||
/// # use std::convert::TryFrom;
|
||||
/// use chrono::prelude::*;
|
||||
/// let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap();
|
||||
/// // `2019-10-28T09:10:11Z`
|
||||
/// let month = Month::from_u32(date.month());
|
||||
/// let month = Month::try_from(u8::try_from(date.month()).unwrap()).ok();
|
||||
/// assert_eq!(month, Some(Month::October))
|
||||
/// ```
|
||||
/// Or from a Month to an integer usable by dates
|
||||
@ -157,6 +159,28 @@ impl Month {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Month {
|
||||
type Error = OutOfRange;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
1 => Ok(Month::January),
|
||||
2 => Ok(Month::February),
|
||||
3 => Ok(Month::March),
|
||||
4 => Ok(Month::April),
|
||||
5 => Ok(Month::May),
|
||||
6 => Ok(Month::June),
|
||||
7 => Ok(Month::July),
|
||||
8 => Ok(Month::August),
|
||||
9 => Ok(Month::September),
|
||||
10 => Ok(Month::October),
|
||||
11 => Ok(Month::November),
|
||||
12 => Ok(Month::December),
|
||||
_ => Err(OutOfRange::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::FromPrimitive for Month {
|
||||
/// Returns an `Option<Month>` from a i64, assuming a 1-index, January = 1.
|
||||
///
|
||||
@ -325,8 +349,25 @@ mod month_serde {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::convert::TryFrom;
|
||||
|
||||
use super::Month;
|
||||
use crate::{Datelike, TimeZone, Utc};
|
||||
use crate::{Datelike, OutOfRange, TimeZone, Utc};
|
||||
|
||||
#[test]
|
||||
fn test_month_enum_try_from() {
|
||||
assert_eq!(Month::try_from(1), Ok(Month::January));
|
||||
assert_eq!(Month::try_from(2), Ok(Month::February));
|
||||
assert_eq!(Month::try_from(12), Ok(Month::December));
|
||||
assert_eq!(Month::try_from(13), Err(OutOfRange::new()));
|
||||
|
||||
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));
|
||||
|
||||
let month = Month::January;
|
||||
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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_month_enum_primitive_parse() {
|
||||
|
@ -9,7 +9,6 @@ use core::convert::TryFrom;
|
||||
use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign};
|
||||
use core::{fmt, str};
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
#[cfg(feature = "rkyv")]
|
||||
use rkyv::{Archive, Deserialize, Serialize};
|
||||
|
||||
@ -1030,7 +1029,7 @@ impl NaiveDate {
|
||||
let year = self.year();
|
||||
let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
|
||||
let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal());
|
||||
let cycle = (cycle as i32).checked_add(rhs.num_days().to_i32()?)?;
|
||||
let cycle = (cycle as i32).checked_add(i32::try_from(rhs.num_days()).ok()?)?;
|
||||
let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097);
|
||||
year_div_400 += cycle_div_400y;
|
||||
|
||||
@ -1062,7 +1061,7 @@ impl NaiveDate {
|
||||
let year = self.year();
|
||||
let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
|
||||
let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal());
|
||||
let cycle = (cycle as i32).checked_sub(rhs.num_days().to_i32()?)?;
|
||||
let cycle = (cycle as i32).checked_sub(i32::try_from(rhs.num_days()).ok()?)?;
|
||||
let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097);
|
||||
year_div_400 += cycle_div_400y;
|
||||
|
||||
|
@ -5,11 +5,11 @@
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||
use core::borrow::Borrow;
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt::Write;
|
||||
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use core::{fmt, str};
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
#[cfg(feature = "rkyv")]
|
||||
use rkyv::{Archive, Deserialize, Serialize};
|
||||
|
||||
@ -211,8 +211,8 @@ impl NaiveDateTime {
|
||||
pub fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> {
|
||||
let days = secs.div_euclid(86_400);
|
||||
let secs = secs.rem_euclid(86_400);
|
||||
let date = days
|
||||
.to_i32()
|
||||
let date = i32::try_from(days)
|
||||
.ok()
|
||||
.and_then(|days| days.checked_add(719_163))
|
||||
.and_then(NaiveDate::from_num_days_from_ce_opt);
|
||||
let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs);
|
||||
|
@ -16,8 +16,8 @@
|
||||
#![cfg_attr(feature = "__internal_bench", allow(missing_docs))]
|
||||
|
||||
use crate::Weekday;
|
||||
use core::convert::TryFrom;
|
||||
use core::{fmt, i32};
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
/// The internal date representation. This also includes the packed `Mdf` value.
|
||||
pub(super) type DateImpl = i32;
|
||||
@ -319,7 +319,7 @@ impl Of {
|
||||
#[inline]
|
||||
pub(super) fn weekday(&self) -> Weekday {
|
||||
let Of(of) = *self;
|
||||
Weekday::from_u32(((of >> 4) + (of & 0b111)) % 7).unwrap()
|
||||
Weekday::try_from((((of >> 4) + (of & 0b111)) % 7) as u8).unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -327,7 +327,7 @@ impl Of {
|
||||
// week ordinal = ordinal + delta
|
||||
let Of(of) = *self;
|
||||
let weekord = (of >> 4).wrapping_add(self.flags().isoweek_delta());
|
||||
(weekord / 7, Weekday::from_u32(weekord % 7).unwrap())
|
||||
(weekord / 7, Weekday::try_from((weekord % 7) as u8).unwrap())
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
|
||||
|
@ -1,8 +1,10 @@
|
||||
use core::fmt;
|
||||
use core::{convert::TryFrom, fmt};
|
||||
|
||||
#[cfg(feature = "rkyv")]
|
||||
use rkyv::{Archive, Deserialize, Serialize};
|
||||
|
||||
use crate::OutOfRange;
|
||||
|
||||
/// The day of week.
|
||||
///
|
||||
/// The order of the days of week depends on the context.
|
||||
@ -12,12 +14,12 @@ use rkyv::{Archive, Deserialize, Serialize};
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use chrono::Weekday;
|
||||
/// use num_traits::cast::FromPrimitive;
|
||||
/// use std::convert::TryFrom;
|
||||
///
|
||||
/// let monday = "Monday".parse::<Weekday>().unwrap();
|
||||
/// assert_eq!(monday, Weekday::Mon);
|
||||
///
|
||||
/// let sunday = Weekday::from_u8(6).unwrap();
|
||||
/// let sunday = Weekday::try_from(6).unwrap();
|
||||
/// assert_eq!(sunday, Weekday::Sun);
|
||||
///
|
||||
/// assert_eq!(sunday.num_days_from_monday(), 6); // starts counting with Monday = 0
|
||||
@ -153,6 +155,26 @@ impl fmt::Display for Weekday {
|
||||
}
|
||||
}
|
||||
|
||||
/// Any weekday can be represented as an integer from 0 to 6, which equals to
|
||||
/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation.
|
||||
/// Do not heavily depend on this though; use explicit methods whenever possible.
|
||||
impl TryFrom<u8> for Weekday {
|
||||
type Error = OutOfRange;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(Weekday::Mon),
|
||||
1 => Ok(Weekday::Tue),
|
||||
2 => Ok(Weekday::Wed),
|
||||
3 => Ok(Weekday::Thu),
|
||||
4 => Ok(Weekday::Fri),
|
||||
5 => Ok(Weekday::Sat),
|
||||
6 => Ok(Weekday::Sun),
|
||||
_ => Err(OutOfRange::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Any weekday can be represented as an integer from 0 to 6, which equals to
|
||||
/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation.
|
||||
/// Do not heavily depend on this though; use explicit methods whenever possible.
|
||||
@ -210,14 +232,13 @@ impl fmt::Debug for ParseWeekdayError {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use super::Weekday;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_num_days_from() {
|
||||
for i in 0..7 {
|
||||
let base_day = Weekday::from_u64(i).unwrap();
|
||||
let base_day = Weekday::try_from(i).unwrap();
|
||||
|
||||
assert_eq!(base_day.num_days_from_monday(), base_day.num_days_from(Weekday::Mon));
|
||||
assert_eq!(base_day.num_days_from_sunday(), base_day.num_days_from(Weekday::Sun));
|
||||
|
Loading…
x
Reference in New Issue
Block a user