@@ -14,27 +14,40 @@ use icu_calendar::{
14
14
15
15
#[ derive( Debug , Copy , Clone ) ]
16
16
struct Duration {
17
- days : u32 ,
18
- milliseconds : u32 ,
17
+ milliseconds : i64 ,
19
18
}
20
19
21
20
impl Duration {
22
- fn to_i64 ( & self ) -> i64 {
23
- self . days as i64 * MILLISECONDS_IN_DAY as i64 + self . milliseconds as i64
21
+ const fn new ( days : u32 , millis_in_day : u32 ) -> Self {
22
+ Self {
23
+ milliseconds : days as i64 * MILLISECONDS_IN_DAY + millis_in_day as i64 ,
24
+ }
25
+ }
26
+ }
27
+
28
+ impl core:: ops:: Mul < i64 > for Duration {
29
+ type Output = Self ;
30
+
31
+ fn mul ( self , rhs : i64 ) -> Self :: Output {
32
+ Self {
33
+ milliseconds : self . milliseconds * rhs,
34
+ }
24
35
}
25
36
}
26
37
27
38
macro_rules! duration_from_day_fraction {
28
39
( $n: tt $( / $d: tt) +) => { {
29
40
let days = ( $n $( / $d) +) as u32 ;
30
- // This works by using exact rounding in the first term, and intermediate rounding in the second term
31
41
let milliseconds = ( ( MILLISECONDS_IN_DAY as i128 * $n as i128 $( / $d as i128 ) +) - ( $n as i128 $( / $d as i128 ) + * MILLISECONDS_IN_DAY as i128 ) ) as u32 ;
32
- Duration { days, milliseconds }
42
+ Duration :: new ( days, milliseconds)
33
43
} } ;
34
44
( $n: tt $( / $d: tt) +, exact) => { {
35
- let d = duration_from_day_fraction!( $n $( / $d) +) ;
36
- assert!( ( d. milliseconds as i128 $( * $d as i128 ) +) % MILLISECONDS_IN_DAY as i128 == 0 , "inexact" ) ;
37
- d
45
+ let days = ( $n $( / $d) +) as u32 ;
46
+ // This works by using exact rounding in the first term, and intermediate rounding in the second term
47
+ let milliseconds = ( ( MILLISECONDS_IN_DAY as i128 * $n as i128 $( / $d as i128 ) +) - ( $n as i128 $( / $d as i128 ) + * MILLISECONDS_IN_DAY as i128 ) ) as u32 ;
48
+ // milliseconds needs to be a multiple of (MILLISECONDS_IN_DAY / $denominators) to be exact
49
+ assert!( ( milliseconds as i128 $( * $d as i128 ) +) % MILLISECONDS_IN_DAY as i128 == 0 , "inexact" ) ;
50
+ Duration :: new( days, milliseconds)
38
51
} } ;
39
52
}
40
53
@@ -62,55 +75,43 @@ struct LocalMoment {
62
75
local_milliseconds : u32 ,
63
76
}
64
77
65
- impl LocalMoment {
66
- /// Adds a specific [`Duration`] to this moment `n` times.
67
- fn add_duration_times_n ( & self , duration : Duration , n : i64 ) -> LocalMoment {
68
- let temp = self . local_milliseconds as i64 + ( duration. milliseconds as i64 * n) ;
69
- let ( extra_days, local_milliseconds) = (
70
- temp. div_euclid ( MILLISECONDS_IN_DAY ) ,
71
- temp. rem_euclid ( MILLISECONDS_IN_DAY ) ,
72
- ) ;
73
- let rata_die = self . rata_die + extra_days + ( duration. days as i64 * n) as i64 ;
74
- let local_milliseconds = u32:: try_from ( local_milliseconds) . unwrap ( ) ;
78
+ impl core:: ops:: Add < Duration > for LocalMoment {
79
+ type Output = Self ;
80
+
81
+ fn add ( self , duration : Duration ) -> Self :: Output {
82
+ let temp = self . local_milliseconds as i64 + duration. milliseconds ;
75
83
Self {
76
- rata_die,
77
- local_milliseconds,
84
+ rata_die : self . rata_die + temp . div_euclid ( MILLISECONDS_IN_DAY ) ,
85
+ local_milliseconds : temp . rem_euclid ( MILLISECONDS_IN_DAY ) as u32 ,
78
86
}
79
87
}
80
-
81
- /// Converts this moment to an i64 local timestamp in milliseconds (with Rata Die epoch)
82
- fn to_i64 ( & self ) -> i64 {
83
- ( self . rata_die . to_i64_date ( ) * MILLISECONDS_IN_DAY ) + self . local_milliseconds as i64
84
- }
85
88
}
86
89
87
90
#[ test]
88
91
fn test_local_moment_add ( ) {
92
+ #![ allow( clippy:: erasing_op) ]
89
93
let local_moment = LocalMoment {
90
94
rata_die : RataDie :: new ( 1000 ) ,
91
95
local_milliseconds : 0 ,
92
96
} ;
93
- let duration = Duration {
94
- days : 77 ,
95
- milliseconds : 25000000 ,
96
- } ;
97
- assert_eq ! ( local_moment. add_duration_times_n( duration, 0 ) , local_moment) ;
97
+ let duration = Duration :: new ( 77 , 25000000 ) ;
98
+ assert_eq ! ( local_moment + duration * 0 , local_moment) ;
98
99
assert_eq ! (
99
- local_moment. add_duration_times_n ( duration, 1 ) ,
100
+ local_moment + duration * 1 ,
100
101
LocalMoment {
101
102
rata_die: RataDie :: new( 1077 ) ,
102
103
local_milliseconds: 25000000
103
104
}
104
105
) ;
105
106
assert_eq ! (
106
- local_moment. add_duration_times_n ( duration, - 1 ) ,
107
+ local_moment + duration * - 1 ,
107
108
LocalMoment {
108
109
rata_die: RataDie :: new( 922 ) ,
109
110
local_milliseconds: 61400000
110
111
}
111
112
) ;
112
113
assert_eq ! (
113
- local_moment. add_duration_times_n ( duration, -500 ) ,
114
+ local_moment + duration * -500 ,
114
115
LocalMoment {
115
116
rata_die: RataDie :: new( -37645 ) ,
116
117
local_milliseconds: 28000000 ,
@@ -148,13 +149,12 @@ fn periodic_duration_on_or_before(
148
149
duration : Duration ,
149
150
) -> LocalMoment {
150
151
// For now, do math as i64 milliseconds, which covers 600 million years.
151
- let upper_bound = LocalMoment {
152
- rata_die : rata_die + 1 ,
153
- local_milliseconds : 0 ,
154
- }
155
- . to_i64 ( ) ;
156
- let num_periods = ( upper_bound - base_moment. to_i64 ( ) - 1 ) . div_euclid ( duration. to_i64 ( ) ) ;
157
- base_moment. add_duration_times_n ( duration, num_periods)
152
+ base_moment
153
+ + duration
154
+ * ( ( rata_die - base_moment. rata_die + 1 ) * MILLISECONDS_IN_DAY
155
+ - base_moment. local_milliseconds as i64
156
+ - 1 )
157
+ . div_euclid ( duration. milliseconds )
158
158
}
159
159
160
160
impl icu_calendar:: cal:: scaffold:: UnstableSealed for FastPingqi { }
@@ -177,12 +177,11 @@ impl chinese::Rules for FastPingqi {
177
177
178
178
// Skip the months before the year
179
179
while solar_term < 0 {
180
- let next_new_moon = new_moon. add_duration_times_n ( MEAN_SYNODIC_MONTH_LENGTH , 1 ) ;
180
+ let next_new_moon = new_moon + MEAN_SYNODIC_MONTH_LENGTH ;
181
181
182
182
if major_solar_term. rata_die < next_new_moon. rata_die {
183
183
solar_term += 1 ;
184
- major_solar_term =
185
- major_solar_term. add_duration_times_n ( MEAN_GREGORIAN_SOLAR_TERM_LENGTH , 1 ) ;
184
+ major_solar_term = major_solar_term + MEAN_GREGORIAN_SOLAR_TERM_LENGTH ;
186
185
}
187
186
188
187
new_moon = next_new_moon;
@@ -195,12 +194,11 @@ impl chinese::Rules for FastPingqi {
195
194
196
195
// Iterate over the 12 solar terms, producing potentially 13 months
197
196
while solar_term < 12 {
198
- let next_new_moon = new_moon. add_duration_times_n ( MEAN_SYNODIC_MONTH_LENGTH , 1 ) ;
197
+ let next_new_moon = new_moon + MEAN_SYNODIC_MONTH_LENGTH ;
199
198
200
199
if major_solar_term. rata_die < next_new_moon. rata_die {
201
200
solar_term += 1 ;
202
- major_solar_term =
203
- major_solar_term. add_duration_times_n ( MEAN_GREGORIAN_SOLAR_TERM_LENGTH , 1 ) ;
201
+ major_solar_term = major_solar_term + MEAN_GREGORIAN_SOLAR_TERM_LENGTH ;
204
202
} else {
205
203
leap_month = Some ( month as u8 + 1 ) ;
206
204
}
0 commit comments