@@ -135,7 +135,9 @@ impl Calendar for Iso {
135
135
136
136
// The days of the week are the same every 400 years
137
137
// so we normalize to the nearest multiple of 400
138
- let years_since_400 = date. 0 . year % 400 ;
138
+ let years_since_400 = date. 0 . year . rem_euclid ( 400 ) ;
139
+ debug_assert ! ( years_since_400 >= 0 ) ; // rem_euclid returns positive numbers
140
+ let years_since_400 = years_since_400 as u32 ;
139
141
let leap_years_since_400 = years_since_400 / 4 - years_since_400 / 100 ;
140
142
// The number of days to the current year
141
143
// Can never cause an overflow because years_since_400 has a maximum value of 399.
@@ -169,7 +171,7 @@ impl Calendar for Iso {
169
171
}
170
172
} ;
171
173
let january_1_2000 = 5 ; // Saturday
172
- let day_offset = ( january_1_2000 + year_offset + month_offset + date. 0 . day as i32 ) % 7 ;
174
+ let day_offset = ( january_1_2000 + year_offset + month_offset + date. 0 . day as u32 ) % 7 ;
173
175
174
176
// We calculated in a zero-indexed fashion, but ISO specifies one-indexed
175
177
types:: IsoWeekday :: from ( ( day_offset + 1 ) as usize )
@@ -832,4 +834,49 @@ mod test {
832
834
check ( -1439 , 1969 , 12 , 31 , 0 , 1 ) ;
833
835
check ( -2879 , 1969 , 12 , 30 , 0 , 1 ) ;
834
836
}
837
+
838
+ #[ test]
839
+ fn test_continuity_near_year_zero ( ) {
840
+ // https://github.com/unicode-org/icu4x/issues/4893
841
+ const ONE_DAY_DURATION : DateDuration < Iso > = DateDuration {
842
+ years : 0 ,
843
+ months : 0 ,
844
+ weeks : 0 ,
845
+ days : 1 ,
846
+ marker : core:: marker:: PhantomData ,
847
+ } ;
848
+
849
+ let mut iso_date = Date :: try_new_iso_date ( -10 , 1 , 1 ) . unwrap ( ) ;
850
+ let mut rata_die = iso_date. to_fixed ( ) ;
851
+ let mut weekday = iso_date. day_of_week ( ) ;
852
+
853
+ for _ in 0 ..( 366 * 20 ) {
854
+ let next_iso_date = iso_date. added ( ONE_DAY_DURATION ) ;
855
+ let next_rata_die = next_iso_date. to_fixed ( ) ;
856
+ assert_eq ! (
857
+ next_rata_die,
858
+ rata_die + 1 ,
859
+ "{iso_date:?}..{next_iso_date:?}"
860
+ ) ;
861
+ let next_weekday = next_iso_date. day_of_week ( ) ;
862
+ assert_eq ! (
863
+ ( next_weekday as usize ) % 7 ,
864
+ ( weekday as usize + 1 ) % 7 ,
865
+ "{iso_date:?}..{next_iso_date:?}"
866
+ ) ;
867
+ if iso_date. month ( ) . code . parsed ( ) . unwrap ( ) . 0 == 2 && iso_date. day_of_month ( ) . 0 == 28 {
868
+ assert_eq ! ( next_iso_date. is_in_leap_year( ) , iso_date. is_in_leap_year( ) ) ;
869
+ if iso_date. is_in_leap_year ( ) {
870
+ assert_eq ! ( next_iso_date. month( ) . code. parsed( ) . unwrap( ) . 0 , 2 ) ;
871
+ assert_eq ! ( next_iso_date. day_of_month( ) . 0 , 29 ) ;
872
+ } else {
873
+ assert_eq ! ( next_iso_date. month( ) . code. parsed( ) . unwrap( ) . 0 , 3 ) ;
874
+ assert_eq ! ( next_iso_date. day_of_month( ) . 0 , 1 ) ;
875
+ }
876
+ }
877
+ iso_date = next_iso_date;
878
+ rata_die = next_rata_die;
879
+ weekday = next_weekday;
880
+ }
881
+ }
835
882
}
0 commit comments