Index: src/date.h |
diff --git a/src/date.h b/src/date.h |
index 2e5ce39a042c791de83a4446c960225a4784cf61..813d3126ede972f628e325336e94e9e5661f132c 100644 |
--- a/src/date.h |
+++ b/src/date.h |
@@ -104,21 +104,51 @@ class DateCache { |
// ECMA 262 - 15.9.1.9 |
// LocalTime(t) = t + LocalTZA + DaylightSavingTA(t) |
- // ECMA 262 assumes that DaylightSavingTA is computed using UTC time, |
- // but we fetch DST from OS using local time, therefore we need: |
- // LocalTime(t) = t + LocalTZA + DaylightSavingTA(t + LocalTZA). |
int64_t ToLocal(int64_t time_ms) { |
- time_ms += LocalOffsetInMs(); |
- return time_ms + DaylightSavingsOffsetInMs(time_ms); |
+ return time_ms + LocalOffsetInMs() + DaylightSavingsOffsetInMs(time_ms); |
} |
// ECMA 262 - 15.9.1.9 |
// UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA) |
- // ECMA 262 assumes that DaylightSavingTA is computed using UTC time, |
- // but we fetch DST from OS using local time, therefore we need: |
- // UTC(t) = t - LocalTZA - DaylightSavingTA(t). |
int64_t ToUTC(int64_t time_ms) { |
- return time_ms - LocalOffsetInMs() - DaylightSavingsOffsetInMs(time_ms); |
+ // We need to compute UTC time that corresponds to the given local time. |
+ // Literally following spec here leads to incorrect time computation at |
+ // the points were we transition to and from DST. |
+ // |
+ // The following shows that using DST for (t - LocalTZA - hour) produces |
+ // correct conversion. |
+ // |
+ // Consider transition to DST at local time L1. |
+ // Let L0 = L1 - hour, L2 = L1 + hour, |
+ // U1 = UTC time that corresponds to L1, |
+ // U0 = U1 - hour. |
+ // Transitioning to DST moves local clock one hour forward L1 => L2, so |
+ // U0 = UTC time that corresponds to L0 = L0 - LocalTZA, |
+ // U1 = UTC time that corresponds to L1 = L1 - LocalTZA, |
+ // U1 = UTC time that corresponds to L2 = L2 - LocalTZA - hour. |
+ // Note that DST(U0 - hour) = 0, DST(U0) = 0, DST(U1) = 1. |
+ // U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour), |
+ // U1 = L1 - LocalTZA - DST(L1 - LocalTZA - hour), |
+ // U1 = L2 - LocalTZA - DST(L2 - LocalTZA - hour). |
+ // |
+ // Consider transition from DST at local time L1. |
+ // Let L0 = L1 - hour, |
+ // U1 = UTC time that corresponds to L1, |
+ // U0 = U1 - hour, U2 = U1 + hour. |
+ // Transitioning from DST moves local clock one hour back L1 => L0, so |
+ // U0 = UTC time that corresponds to L0 (before transition) |
+ // = L0 - LocalTZA - hour. |
+ // U1 = UTC time that corresponds to L0 (after transition) |
+ // = L0 - LocalTZA = L1 - LocalTZA - hour |
+ // U2 = UTC time that corresponds to L1 = L1 - LocalTZA. |
+ // Note that DST(U0) = 1, DST(U1) = 0, DST(U2) = 0. |
+ // U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour) = L0 - LocalTZA - DST(U0). |
+ // U2 = L1 - LocalTZA - DST(L1 - LocalTZA - hour) = L1 - LocalTZA - DST(U1). |
+ // It is impossible to get U1 from local time. |
+ |
+ const int kMsPerHour = 3600 * 1000; |
+ time_ms -= LocalOffsetInMs(); |
+ return time_ms - DaylightSavingsOffsetInMs(time_ms - kMsPerHour); |
} |