@@ -4,18 +4,11 @@ use chrono::{prelude::*, Duration, LocalResult};
44use ordered_float:: NotNan ;
55use serde:: { Deserialize , Serialize , Serializer } ;
66
7- /// Represents NumericDate (see <https://datatracker.ietf.org/doc/html/rfc7519#section-2>)
8- /// where the range is restricted to those in which microseconds can be exactly represented,
9- /// which is approximately between the years 1685 and 2255, which was considered to be sufficient
10- /// for the purposes of this crate. Note that leap seconds are ignored by this type, just as
11- /// they're ignored by NumericDate in the JWT standard.
7+ /// JSON numeric value representing the number of seconds from
8+ /// 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap
9+ /// seconds.
1210///
13- /// An f64 value has 52 explicit mantissa bits, meaning that the biggest contiguous range
14- /// of integer values is from -2^53 to 2^53 (52 zeros after the mantissa's implicit 1).
15- /// Using this value to represent exact microseconds gives a maximum range of
16- /// +-2^53 / (1000000 * 60 * 60 * 24 * 365.25) ~= +-285,
17- /// which is centered around the Unix epoch start date Jan 1, 1970, 00:00:00 UTC, giving
18- /// the years 1685 to 2255.
11+ /// See: <https://datatracker.ietf.org/doc/html/rfc7519#section-2>
1912#[ derive( Debug , Serialize , Deserialize , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
2013pub struct NumericDate ( #[ serde( serialize_with = "interop_serialize" ) ] NotNan < f64 > ) ;
2114
@@ -40,9 +33,6 @@ pub enum NumericDateConversionError {
4033
4134 #[ error( "Invalid float literal" ) ]
4235 InvalidFloatLiteral ,
43-
44- #[ error( "Out of valid microsecond-precision range of NumericDate" ) ]
45- OutOfMicrosecondPrecisionRange ,
4636}
4737
4838impl From < ordered_float:: FloatIsNan > for NumericDateConversionError {
@@ -52,28 +42,17 @@ impl From<ordered_float::FloatIsNan> for NumericDateConversionError {
5242}
5343
5444impl NumericDate {
55- /// This is -2^53 / 1_000_000, which is the smallest NumericDate that faithfully
56- /// represents full microsecond precision.
57- pub const MIN : NumericDate =
58- NumericDate ( unsafe { NotNan :: new_unchecked ( -9_007_199_254.740_992 ) } ) ;
59- /// This is 2^53 / 1_000_000, which is the largest NumericDate that faithfully
60- /// represents full microsecond precision.
61- pub const MAX : NumericDate =
62- NumericDate ( unsafe { NotNan :: new_unchecked ( 9_007_199_254.740_992 ) } ) ;
63-
6445 /// Return the f64-valued number of seconds represented by this NumericDate.
6546 pub fn as_seconds ( self ) -> f64 {
6647 * self . 0
6748 }
49+
6850 /// Try to create NumericDate from a f64 value, returning error upon out-of-range.
6951 pub fn try_from_seconds ( seconds : f64 ) -> Result < Self , NumericDateConversionError > {
7052 let seconds = NotNan :: new ( seconds) ?;
71- if seconds. abs ( ) > * Self :: MAX . 0 {
72- Err ( NumericDateConversionError :: OutOfMicrosecondPrecisionRange )
73- } else {
74- Ok ( NumericDate ( seconds) )
75- }
53+ Ok ( NumericDate ( seconds) )
7654 }
55+
7756 /// Decompose NumericDate for use in Utc.timestamp and Utc.timestamp_opt
7857 fn into_whole_seconds_and_fractional_nanoseconds ( self ) -> ( i64 , u32 ) {
7958 let whole_seconds = self . 0 . floor ( ) as i64 ;
@@ -88,7 +67,7 @@ impl std::ops::Add<Duration> for NumericDate {
8867 type Output = NumericDate ;
8968 fn add ( self , rhs : Duration ) -> Self :: Output {
9069 let self_dtu: DateTime < Utc > = self . into ( ) ;
91- Self :: Output :: try_from ( self_dtu + rhs) . unwrap ( )
70+ Self :: Output :: from ( self_dtu + rhs)
9271 }
9372}
9473
@@ -107,7 +86,7 @@ impl std::ops::Sub<Duration> for NumericDate {
10786 type Output = NumericDate ;
10887 fn sub ( self , rhs : Duration ) -> Self :: Output {
10988 let self_dtu: DateTime < Utc > = self . into ( ) ;
110- Self :: Output :: try_from ( self_dtu - rhs) . unwrap ( )
89+ Self :: Output :: from ( self_dtu - rhs)
11190 }
11291}
11392
@@ -133,10 +112,8 @@ impl TryFrom<f64> for NumericDate {
133112 }
134113}
135114
136- impl TryFrom < DateTime < Utc > > for NumericDate {
137- type Error = NumericDateConversionError ;
138-
139- fn try_from ( dtu : DateTime < Utc > ) -> Result < Self , Self :: Error > {
115+ impl From < DateTime < Utc > > for NumericDate {
116+ fn from ( dtu : DateTime < Utc > ) -> Self {
140117 // Have to take seconds and nanoseconds separately in order to get the full allowable
141118 // range of microsecond-precision values as described above.
142119 let whole_seconds = dtu. timestamp ( ) as f64 ;
@@ -146,14 +123,14 @@ impl TryFrom<DateTime<Utc>> for NumericDate {
146123 } ;
147124
148125 Self :: try_from_seconds ( whole_seconds + fractional_seconds)
126+ // UNWRAP SAFETY: input value can't be NaN nor infinite.
127+ . unwrap ( )
149128 }
150129}
151130
152- impl TryFrom < DateTime < FixedOffset > > for NumericDate {
153- type Error = NumericDateConversionError ;
154- fn try_from ( dtfo : DateTime < FixedOffset > ) -> Result < Self , Self :: Error > {
155- let dtu = DateTime :: < Utc > :: from ( dtfo) ;
156- NumericDate :: try_from ( dtu)
131+ impl From < DateTime < FixedOffset > > for NumericDate {
132+ fn from ( dtfo : DateTime < FixedOffset > ) -> Self {
133+ DateTime :: < Utc > :: from ( dtfo) . into ( )
157134 }
158135}
159136
0 commit comments