@@ -1278,3 +1278,104 @@ fn hours_in_day_dst_changes() {
12781278 assert_eq!( spring. hours_in_day_with_provider( provider) , Ok ( 23.0 ) ) ;
12791279 } )
12801280}
1281+
1282+ // Case where midnight occurs twice (e.g., Antarctica/Casey on 2010-03-05).
1283+ // Upstream tests: https://github.com/tc39/test262/pull/5047
1284+ #[ test]
1285+ fn test_same_date_starts_twice ( ) {
1286+ test_all_providers ! ( provider: {
1287+ let zdt1 = ZonedDateTime :: from_utf8_with_provider(
1288+ b"2010-03-04T23:10:00+11:00[Antarctica/Casey]" ,
1289+ Disambiguation :: Compatible ,
1290+ OffsetDisambiguation :: Use ,
1291+ provider,
1292+ ) ;
1293+ if zdt1. is_err( ) {
1294+ std:: println!( "Antarctica/Casey not supported by provider, skipping test." ) ;
1295+ return ;
1296+ }
1297+ let zdt1 = zdt1. unwrap( ) ;
1298+
1299+ let zdt2 = ZonedDateTime :: from_utf8_with_provider(
1300+ b"2010-03-05T00:45:00+11:00[Antarctica/Casey]" ,
1301+ Disambiguation :: Compatible ,
1302+ OffsetDisambiguation :: Use ,
1303+ provider,
1304+ ) . unwrap( ) ;
1305+
1306+ let zdt3 = ZonedDateTime :: from_utf8_with_provider(
1307+ b"2010-03-04T23:10:00+08:00[Antarctica/Casey]" ,
1308+ Disambiguation :: Compatible ,
1309+ OffsetDisambiguation :: Use ,
1310+ provider,
1311+ ) . unwrap( ) ;
1312+
1313+ let zdt4 = ZonedDateTime :: from_utf8_with_provider(
1314+ b"2010-03-05T00:45:00+08:00[Antarctica/Casey]" ,
1315+ Disambiguation :: Compatible ,
1316+ OffsetDisambiguation :: Use ,
1317+ provider,
1318+ ) . unwrap( ) ;
1319+
1320+ let start_of_march4 = "2010-03-04T00:00:00+11:00[Antarctica/Casey]" ;
1321+ let start_of_march5 = "2010-03-05T00:00:00+11:00[Antarctica/Casey]" ;
1322+ let start_of_march6 = "2010-03-06T00:00:00+08:00[Antarctica/Casey]" ;
1323+
1324+ // Hours in day
1325+ assert_eq!( zdt1. hours_in_day_with_provider( provider) . unwrap( ) , 24.0 ) ;
1326+ assert_eq!( zdt2. hours_in_day_with_provider( provider) . unwrap( ) , 27.0 ) ;
1327+ assert_eq!( zdt3. hours_in_day_with_provider( provider) . unwrap( ) , 24.0 ) ;
1328+ assert_eq!( zdt4. hours_in_day_with_provider( provider) . unwrap( ) , 27.0 ) ;
1329+
1330+ // Start of day
1331+ assert_eq!( zdt1. start_of_day_with_provider( provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march4) ;
1332+ assert_eq!( zdt2. start_of_day_with_provider( provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1333+ assert_eq!( zdt3. start_of_day_with_provider( provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march4) ;
1334+ assert_eq!( zdt4. start_of_day_with_provider( provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1335+
1336+ // Rounding down
1337+ for rounding_mode in [ RoundingMode :: Floor , RoundingMode :: Trunc ] {
1338+ let options = RoundingOptions {
1339+ smallest_unit: Some ( Unit :: Day ) ,
1340+ rounding_mode: Some ( rounding_mode) ,
1341+ ..Default :: default ( )
1342+ } ;
1343+ assert_eq!( zdt1. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march4) ;
1344+ assert_eq!( zdt2. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1345+ assert_eq!( zdt3. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march4) ;
1346+ assert_eq!( zdt4. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1347+ }
1348+
1349+ // Rounding to nearest
1350+ for rounding_mode in [
1351+ RoundingMode :: HalfCeil ,
1352+ RoundingMode :: HalfEven ,
1353+ RoundingMode :: HalfExpand ,
1354+ RoundingMode :: HalfFloor ,
1355+ RoundingMode :: HalfTrunc ,
1356+ ] {
1357+ let options = RoundingOptions {
1358+ smallest_unit: Some ( Unit :: Day ) ,
1359+ rounding_mode: Some ( rounding_mode) ,
1360+ ..Default :: default ( )
1361+ } ;
1362+ assert_eq!( zdt1. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1363+ assert_eq!( zdt2. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1364+ assert_eq!( zdt3. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1365+ assert_eq!( zdt4. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1366+ }
1367+
1368+ // Rounding up
1369+ for rounding_mode in [ RoundingMode :: Ceil , RoundingMode :: Expand ] {
1370+ let options = RoundingOptions {
1371+ smallest_unit: Some ( Unit :: Day ) ,
1372+ rounding_mode: Some ( rounding_mode) ,
1373+ ..Default :: default ( )
1374+ } ;
1375+ assert_eq!( zdt1. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1376+ assert_eq!( zdt2. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march6) ;
1377+ assert_eq!( zdt3. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march5) ;
1378+ assert_eq!( zdt4. round_with_provider( options, provider) . unwrap( ) . to_string_with_provider( provider) . unwrap( ) , start_of_march6) ;
1379+ }
1380+ } )
1381+ }
0 commit comments