Skip to content

Commit 083d5d8

Browse files
Manishearthcopybara-github
authored andcommitted
[temporal] Uplift upstream fix for ZDT backwards changes
boa-dev/temporal#725 This patch uplifts an upstream fix to satisfy a spec change. R=flowerhack@google.com, rezvan@chromium.org Bug: None Change-Id: I034c7471e5106f77d1a917cc21155f09392d8811 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7884058 Reviewed-by: Rezvan Mahdavi Hezaveh <rezvan@chromium.org> Commit-Queue: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Auto-Submit: Manish Goregaokar <manishearth@google.com> Cr-Commit-Position: refs/heads/main@{#1638122} NOKEYCHECK=True GitOrigin-RevId: 288ca2e118ad3c45100dbf2803c17d0800c9c4d6
1 parent e5d231e commit 083d5d8

3 files changed

Lines changed: 274 additions & 7 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
From 9853dabe6e46fb641e888fa3fb6149d2ef712640 Mon Sep 17 00:00:00 2001
2+
From: Manish Goregaokar <manishsmail@gmail.com>
3+
Date: Thu, 28 May 2026 19:54:27 +0000
4+
Subject: [PATCH] agent-driven: fix(zoned_date_time): clamp thisNs to endNs - 1
5+
in ZonedDateTime.round when smallestUnit is Day
6+
7+
---
8+
third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time.rs | 17 ++--
9+
third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time/tests.rs | 101 +++++++++++++++++++++
10+
2 files changed, 111 insertions(+), 7 deletions(-)
11+
12+
diff --git a/third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time.rs b/third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time.rs
13+
index ff4e320..a5b1199 100644
14+
--- a/third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time.rs
15+
+++ b/third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time.rs
16+
@@ -1301,17 +1301,20 @@ impl ZonedDateTime {
17+
// c. Let startNs be ? GetStartOfDay(timeZone, dateStart).
18+
// d. Assert: thisNs ≥ startNs.
19+
// e. Let endNs be ? GetStartOfDay(timeZone, dateEnd).
20+
- // f. Assert: thisNs < endNs.
21+
+ // f. [Struck out in spec] Assert: thisNs < endNs.
22+
let start = self.time_zone.get_start_of_day(&iso_start.date, provider)?;
23+
let end = self.time_zone.get_start_of_day(&iso_end, provider)?;
24+
- if !(this_ns.0 >= start.ns.0 && this_ns.0 < end.ns.0) {
25+
+ if this_ns.0 < start.ns.0 {
26+
return Err(TemporalError::range().with_enum(ErrorMessage::ZDTOutOfDayBounds));
27+
}
28+
- // g. Let dayLengthNs be ℝ(endNs - startNs).
29+
- // h. Let dayProgressNs be TimeDurationFromEpochNanosecondsDifference(thisNs, startNs).
30+
+ // g. Set thisNs to min(thisNs, endNs - 1).
31+
+ let this_ns_val = this_ns.0.min(end.ns.0 - 1);
32+
+ // h. Let dayLengthNs be ℝ(endNs - startNs).
33+
+ // i. Let dayProgressNs be TimeDurationFromEpochNanosecondsDifference(thisNs, startNs).
34+
let day_len_ns = TimeDuration::from_nanosecond_difference(end.ns.0, start.ns.0)?;
35+
- let day_progress_ns = TimeDuration::from_nanosecond_difference(this_ns.0, start.ns.0)?;
36+
- // i. Let roundedDayNs be ! RoundTimeDurationToIncrement(dayProgressNs, dayLengthNs, roundingMode).
37+
+ let day_progress_ns =
38+
+ TimeDuration::from_nanosecond_difference(this_ns_val, start.ns.0)?;
39+
+ // j. Let roundedDayNs be ! RoundTimeDurationToIncrement(dayProgressNs, dayLengthNs, roundingMode).
40+
let rounded = if let Some(increment) = NonZeroU128::new(day_len_ns.0.unsigned_abs()) {
41+
IncrementRounder::<i128>::from_signed_num(day_progress_ns.0, increment)?
42+
.round(resolved.rounding_mode)
43+
@@ -1326,7 +1329,7 @@ impl ZonedDateTime {
44+
end.offset
45+
};
46+
47+
- // j. Let epochNanoseconds be AddTimeDurationToEpochNanoseconds(roundedDayNs, startNs).
48+
+ // k. Let epochNanoseconds be AddTimeDurationToEpochNanoseconds(roundedDayNs, startNs).
49+
let candidate = start.ns.0 + rounded;
50+
Instant::try_new(candidate)?;
51+
// 20. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
52+
diff --git a/third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time/tests.rs b/third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time/tests.rs
53+
index e56df72..0efc542 100644
54+
--- a/third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time/tests.rs
55+
+++ b/third_party/rust/chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time/tests.rs
56+
@@ -1278,3 +1278,104 @@ fn hours_in_day_dst_changes() {
57+
assert_eq!(spring.hours_in_day_with_provider(provider), Ok(23.0));
58+
})
59+
}
60+
+
61+
+// Case where midnight occurs twice (e.g., Antarctica/Casey on 2010-03-05).
62+
+// Upstream tests: https://github.com/tc39/test262/pull/5047
63+
+#[test]
64+
+fn test_same_date_starts_twice() {
65+
+ test_all_providers!(provider: {
66+
+ let zdt1 = ZonedDateTime::from_utf8_with_provider(
67+
+ b"2010-03-04T23:10:00+11:00[Antarctica/Casey]",
68+
+ Disambiguation::Compatible,
69+
+ OffsetDisambiguation::Use,
70+
+ provider,
71+
+ );
72+
+ if zdt1.is_err() {
73+
+ std::println!("Antarctica/Casey not supported by provider, skipping test.");
74+
+ return;
75+
+ }
76+
+ let zdt1 = zdt1.unwrap();
77+
+
78+
+ let zdt2 = ZonedDateTime::from_utf8_with_provider(
79+
+ b"2010-03-05T00:45:00+11:00[Antarctica/Casey]",
80+
+ Disambiguation::Compatible,
81+
+ OffsetDisambiguation::Use,
82+
+ provider,
83+
+ ).unwrap();
84+
+
85+
+ let zdt3 = ZonedDateTime::from_utf8_with_provider(
86+
+ b"2010-03-04T23:10:00+08:00[Antarctica/Casey]",
87+
+ Disambiguation::Compatible,
88+
+ OffsetDisambiguation::Use,
89+
+ provider,
90+
+ ).unwrap();
91+
+
92+
+ let zdt4 = ZonedDateTime::from_utf8_with_provider(
93+
+ b"2010-03-05T00:45:00+08:00[Antarctica/Casey]",
94+
+ Disambiguation::Compatible,
95+
+ OffsetDisambiguation::Use,
96+
+ provider,
97+
+ ).unwrap();
98+
+
99+
+ let start_of_march4 = "2010-03-04T00:00:00+11:00[Antarctica/Casey]";
100+
+ let start_of_march5 = "2010-03-05T00:00:00+11:00[Antarctica/Casey]";
101+
+ let start_of_march6 = "2010-03-06T00:00:00+08:00[Antarctica/Casey]";
102+
+
103+
+ // Hours in day
104+
+ assert_eq!(zdt1.hours_in_day_with_provider(provider).unwrap(), 24.0);
105+
+ assert_eq!(zdt2.hours_in_day_with_provider(provider).unwrap(), 27.0);
106+
+ assert_eq!(zdt3.hours_in_day_with_provider(provider).unwrap(), 24.0);
107+
+ assert_eq!(zdt4.hours_in_day_with_provider(provider).unwrap(), 27.0);
108+
+
109+
+ // Start of day
110+
+ assert_eq!(zdt1.start_of_day_with_provider(provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march4);
111+
+ assert_eq!(zdt2.start_of_day_with_provider(provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
112+
+ assert_eq!(zdt3.start_of_day_with_provider(provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march4);
113+
+ assert_eq!(zdt4.start_of_day_with_provider(provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
114+
+
115+
+ // Rounding down
116+
+ for rounding_mode in [RoundingMode::Floor, RoundingMode::Trunc] {
117+
+ let options = RoundingOptions {
118+
+ smallest_unit: Some(Unit::Day),
119+
+ rounding_mode: Some(rounding_mode),
120+
+ ..Default::default()
121+
+ };
122+
+ assert_eq!(zdt1.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march4);
123+
+ assert_eq!(zdt2.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
124+
+ assert_eq!(zdt3.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march4);
125+
+ assert_eq!(zdt4.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
126+
+ }
127+
+
128+
+ // Rounding to nearest
129+
+ for rounding_mode in [
130+
+ RoundingMode::HalfCeil,
131+
+ RoundingMode::HalfEven,
132+
+ RoundingMode::HalfExpand,
133+
+ RoundingMode::HalfFloor,
134+
+ RoundingMode::HalfTrunc,
135+
+ ] {
136+
+ let options = RoundingOptions {
137+
+ smallest_unit: Some(Unit::Day),
138+
+ rounding_mode: Some(rounding_mode),
139+
+ ..Default::default()
140+
+ };
141+
+ assert_eq!(zdt1.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
142+
+ assert_eq!(zdt2.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
143+
+ assert_eq!(zdt3.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
144+
+ assert_eq!(zdt4.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
145+
+ }
146+
+
147+
+ // Rounding up
148+
+ for rounding_mode in [RoundingMode::Ceil, RoundingMode::Expand] {
149+
+ let options = RoundingOptions {
150+
+ smallest_unit: Some(Unit::Day),
151+
+ rounding_mode: Some(rounding_mode),
152+
+ ..Default::default()
153+
+ };
154+
+ assert_eq!(zdt1.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
155+
+ assert_eq!(zdt2.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march6);
156+
+ assert_eq!(zdt3.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march5);
157+
+ assert_eq!(zdt4.round_with_provider(options, provider).unwrap().to_string_with_provider(provider).unwrap(), start_of_march6);
158+
+ }
159+
+ })
160+
+}
161+
--
162+
2.54.0.823.g6e5bcc1fc9-goog
163+

chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,17 +1301,20 @@ impl ZonedDateTime {
13011301
// c. Let startNs be ? GetStartOfDay(timeZone, dateStart).
13021302
// d. Assert: thisNs ≥ startNs.
13031303
// e. Let endNs be ? GetStartOfDay(timeZone, dateEnd).
1304-
// f. Assert: thisNs < endNs.
1304+
// f. [Struck out in spec] Assert: thisNs < endNs.
13051305
let start = self.time_zone.get_start_of_day(&iso_start.date, provider)?;
13061306
let end = self.time_zone.get_start_of_day(&iso_end, provider)?;
1307-
if !(this_ns.0 >= start.ns.0 && this_ns.0 < end.ns.0) {
1307+
if this_ns.0 < start.ns.0 {
13081308
return Err(TemporalError::range().with_enum(ErrorMessage::ZDTOutOfDayBounds));
13091309
}
1310-
// g. Let dayLengthNs be ℝ(endNs - startNs).
1311-
// h. Let dayProgressNs be TimeDurationFromEpochNanosecondsDifference(thisNs, startNs).
1310+
// g. Set thisNs to min(thisNs, endNs - 1).
1311+
let this_ns_val = this_ns.0.min(end.ns.0 - 1);
1312+
// h. Let dayLengthNs be ℝ(endNs - startNs).
1313+
// i. Let dayProgressNs be TimeDurationFromEpochNanosecondsDifference(thisNs, startNs).
13121314
let day_len_ns = TimeDuration::from_nanosecond_difference(end.ns.0, start.ns.0)?;
1313-
let day_progress_ns = TimeDuration::from_nanosecond_difference(this_ns.0, start.ns.0)?;
1314-
// i. Let roundedDayNs be ! RoundTimeDurationToIncrement(dayProgressNs, dayLengthNs, roundingMode).
1315+
let day_progress_ns =
1316+
TimeDuration::from_nanosecond_difference(this_ns_val, start.ns.0)?;
1317+
// j. Let roundedDayNs be ! RoundTimeDurationToIncrement(dayProgressNs, dayLengthNs, roundingMode).
13151318
let rounded = if let Some(increment) = NonZeroU128::new(day_len_ns.0.unsigned_abs()) {
13161319
IncrementRounder::<i128>::from_signed_num(day_progress_ns.0, increment)?
13171320
.round(resolved.rounding_mode)
@@ -1326,7 +1329,7 @@ impl ZonedDateTime {
13261329
end.offset
13271330
};
13281331

1329-
// j. Let epochNanoseconds be AddTimeDurationToEpochNanoseconds(roundedDayNs, startNs).
1332+
// k. Let epochNanoseconds be AddTimeDurationToEpochNanoseconds(roundedDayNs, startNs).
13301333
let candidate = start.ns.0 + rounded;
13311334
Instant::try_new(candidate)?;
13321335
// 20. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).

chromium_crates_io/vendor/temporal_rs-v0_2/src/builtins/core/zoned_date_time/tests.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)