@@ -12,22 +12,62 @@ use crate::{
1212 parsers:: parse_instant,
1313 primitive:: FiniteF64 ,
1414 rounding:: { IncrementRounder , Round } ,
15- Sign , TemporalError , TemporalResult , TemporalUnwrap ,
15+ Sign , TemporalError , TemporalResult , TemporalUnwrap , NS_MAX_INSTANT ,
1616} ;
1717
18- use num_traits:: { Euclid , FromPrimitive , ToPrimitive } ;
18+ use num_traits:: { Euclid , FromPrimitive } ;
1919
2020use super :: duration:: normalized:: NormalizedTimeDuration ;
2121
2222const NANOSECONDS_PER_SECOND : f64 = 1e9 ;
2323const NANOSECONDS_PER_MINUTE : f64 = 60f64 * NANOSECONDS_PER_SECOND ;
2424const NANOSECONDS_PER_HOUR : f64 = 60f64 * NANOSECONDS_PER_MINUTE ;
2525
26+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
27+ pub struct EpochNanoseconds ( i128 ) ;
28+
29+ impl TryFrom < i128 > for EpochNanoseconds {
30+ type Error = TemporalError ;
31+ fn try_from ( value : i128 ) -> Result < Self , Self :: Error > {
32+ if !is_valid_epoch_nanos ( & value) {
33+ return Err ( TemporalError :: range ( )
34+ . with_message ( "Instant nanoseconds are not within a valid epoch range." ) ) ;
35+ }
36+ Ok ( Self ( value) )
37+ }
38+ }
39+
40+ impl TryFrom < u128 > for EpochNanoseconds {
41+ type Error = TemporalError ;
42+ fn try_from ( value : u128 ) -> Result < Self , Self :: Error > {
43+ if ( NS_MAX_INSTANT as u128 ) < value {
44+ return Err ( TemporalError :: range ( )
45+ . with_message ( "Instant nanoseconds are not within a valid epoch range." ) ) ;
46+ }
47+ Ok ( Self ( value as i128 ) )
48+ }
49+ }
50+
51+ impl TryFrom < f64 > for EpochNanoseconds {
52+ type Error = TemporalError ;
53+ fn try_from ( value : f64 ) -> Result < Self , Self :: Error > {
54+ let Some ( value) = i128:: from_f64 ( value) else {
55+ return Err ( TemporalError :: range ( )
56+ . with_message ( "Instant nanoseconds are not within a valid epoch range." ) ) ;
57+ } ;
58+ Self :: try_from ( value)
59+ }
60+ }
61+
2662/// The native Rust implementation of `Temporal.Instant`
2763#[ non_exhaustive]
2864#[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
29- pub struct Instant {
30- pub ( crate ) epoch_nanos : i128 ,
65+ pub struct Instant ( EpochNanoseconds ) ;
66+
67+ impl From < EpochNanoseconds > for Instant {
68+ fn from ( value : EpochNanoseconds ) -> Self {
69+ Self ( value)
70+ }
3171}
3272
3373// ==== Private API ====
@@ -38,17 +78,15 @@ impl Instant {
3878 ///
3979 /// Temporal-Proposal equivalent: `AddDurationToOrSubtractDurationFrom`.
4080 pub ( crate ) fn add_to_instant ( & self , duration : & TimeDuration ) -> TemporalResult < Self > {
41- let result = self . epoch_nanoseconds ( )
81+ let current_nanos = self . epoch_nanoseconds ( ) as f64 ;
82+ let result = current_nanos
4283 + duration. nanoseconds . 0
4384 + ( duration. microseconds . 0 * 1000f64 )
4485 + ( duration. milliseconds . 0 * 1_000_000f64 )
4586 + ( duration. seconds . 0 * NANOSECONDS_PER_SECOND )
4687 + ( duration. minutes . 0 * NANOSECONDS_PER_MINUTE )
4788 + ( duration. hours . 0 * NANOSECONDS_PER_HOUR ) ;
48- let nanos = i128:: from_f64 ( result) . ok_or_else ( || {
49- TemporalError :: range ( ) . with_message ( "Duration added to instant exceeded valid range." )
50- } ) ?;
51- Self :: try_new ( nanos)
89+ Ok ( Self :: from ( EpochNanoseconds :: try_from ( result) ?) )
5290 }
5391
5492 // TODO: Add test for `diff_instant`.
@@ -76,10 +114,8 @@ impl Instant {
76114 // Below are the steps from Difference Instant.
77115 // 5. Let diffRecord be DifferenceInstant(instant.[[Nanoseconds]], other.[[Nanoseconds]],
78116 // settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
79- let diff = NormalizedTimeDuration :: from_nanosecond_difference (
80- other. epoch_nanos ,
81- self . epoch_nanos ,
82- ) ?;
117+ let diff =
118+ NormalizedTimeDuration :: from_nanosecond_difference ( other. as_i128 ( ) , self . as_i128 ( ) ) ?;
83119 let ( round_record, _) = diff. round ( FiniteF64 :: default ( ) , resolved_options) ?;
84120
85121 // 6. Let norm be diffRecord.[[NormalizedTimeDuration]].
@@ -127,21 +163,15 @@ impl Instant {
127163 return Err ( TemporalError :: range ( ) . with_message ( "Increment exceeded a valid range." ) ) ;
128164 } ;
129165
130- let rounded = IncrementRounder :: < i128 > :: from_positive_parts ( self . epoch_nanos , increment) ?
166+ let rounded = IncrementRounder :: < i128 > :: from_positive_parts ( self . as_i128 ( ) , increment) ?
131167 . round_as_positive ( resolved_options. rounding_mode ) ;
132168
133169 Ok ( rounded. into ( ) )
134170 }
135171
136- /// Utility for converting `Instant` to f64.
137- ///
138- /// # Panics
139- ///
140- /// This function will panic if called on an invalid `Instant`.
141- pub ( crate ) fn to_f64 ( & self ) -> f64 {
142- self . epoch_nanos
143- . to_f64 ( )
144- . expect ( "A valid instant is representable by f64." )
172+ // Utility for converting `Instant` to `i128`.
173+ pub fn as_i128 ( & self ) -> i128 {
174+ self . 0 . 0
145175 }
146176}
147177
@@ -150,25 +180,15 @@ impl Instant {
150180impl Instant {
151181 /// Create a new validated `Instant`.
152182 #[ inline]
153- pub fn try_new ( epoch_nanoseconds : i128 ) -> TemporalResult < Self > {
154- if !is_valid_epoch_nanos ( & epoch_nanoseconds) {
155- return Err ( TemporalError :: range ( )
156- . with_message ( "Instant nanoseconds are not within a valid epoch range." ) ) ;
157- }
158- Ok ( Self {
159- epoch_nanos : epoch_nanoseconds,
160- } )
183+ pub fn try_new ( nanoseconds : i128 ) -> TemporalResult < Self > {
184+ Ok ( Self :: from ( EpochNanoseconds :: try_from ( nanoseconds) ?) )
161185 }
162186
163187 pub fn from_epoch_milliseconds ( epoch_milliseconds : i128 ) -> TemporalResult < Self > {
164188 let epoch_nanos = epoch_milliseconds
165189 . checked_mul ( 1_000_000 )
166190 . unwrap_or ( i128:: MAX ) ;
167- if !is_valid_epoch_nanos ( & epoch_nanos) {
168- return Err ( TemporalError :: range ( )
169- . with_message ( "Instant nanoseconds are not within a valid epoch range." ) ) ;
170- }
171- Ok ( Self { epoch_nanos } )
191+ Self :: try_new ( epoch_nanos)
172192 }
173193
174194 /// Adds a `Duration` to the current `Instant`, returning an error if the `Duration`
@@ -235,35 +255,26 @@ impl Instant {
235255
236256 /// Returns the `epochSeconds` value for this `Instant`.
237257 #[ must_use]
238- pub fn epoch_seconds ( & self ) -> f64 {
239- ( & self . epoch_nanos / 1_000_000_000 )
240- . to_f64 ( )
241- . expect ( "A validated Instant should be within a valid f64" )
242- . floor ( )
258+ pub fn epoch_seconds ( & self ) -> i128 {
259+ self . as_i128 ( ) / 1_000_000_000
243260 }
244261
245262 /// Returns the `epochMilliseconds` value for this `Instant`.
246263 #[ must_use]
247- pub fn epoch_milliseconds ( & self ) -> f64 {
248- ( & self . epoch_nanos / 1_000_000 )
249- . to_f64 ( )
250- . expect ( "A validated Instant should be within a valid f64" )
251- . floor ( )
264+ pub fn epoch_milliseconds ( & self ) -> i128 {
265+ self . as_i128 ( ) / 1_000_000
252266 }
253267
254268 /// Returns the `epochMicroseconds` value for this `Instant`.
255269 #[ must_use]
256- pub fn epoch_microseconds ( & self ) -> f64 {
257- ( & self . epoch_nanos / 1_000 )
258- . to_f64 ( )
259- . expect ( "A validated Instant should be within a valid f64" )
260- . floor ( )
270+ pub fn epoch_microseconds ( & self ) -> i128 {
271+ self . as_i128 ( ) / 1_000
261272 }
262273
263274 /// Returns the `epochNanoseconds` value for this `Instant`.
264275 #[ must_use]
265- pub fn epoch_nanoseconds ( & self ) -> f64 {
266- self . to_f64 ( )
276+ pub fn epoch_nanoseconds ( & self ) -> i128 {
277+ self . as_i128 ( )
267278 }
268279}
269280
@@ -326,7 +337,6 @@ mod tests {
326337 primitive:: FiniteF64 ,
327338 NS_MAX_INSTANT , NS_MIN_INSTANT ,
328339 } ;
329- use num_traits:: ToPrimitive ;
330340
331341 #[ test]
332342 #[ allow( clippy:: float_cmp) ]
@@ -338,8 +348,8 @@ mod tests {
338348 let max_instant = Instant :: try_new ( max) . unwrap ( ) ;
339349 let min_instant = Instant :: try_new ( min) . unwrap ( ) ;
340350
341- assert_eq ! ( max_instant. epoch_nanoseconds( ) , max. to_f64 ( ) . unwrap ( ) ) ;
342- assert_eq ! ( min_instant. epoch_nanoseconds( ) , min. to_f64 ( ) . unwrap ( ) ) ;
351+ assert_eq ! ( max_instant. epoch_nanoseconds( ) , max) ;
352+ assert_eq ! ( min_instant. epoch_nanoseconds( ) , min) ;
343353
344354 let max_plus_one = NS_MAX_INSTANT + 1 ;
345355 let min_minus_one = NS_MIN_INSTANT - 1 ;
0 commit comments