Skip to content

Commit dbdede0

Browse files
jungshikCommit Bot
authored and
Commit Bot
committedApr 3, 2018
Implement a new spec for timezone offset calculation
tc39/ecma262#778 was recently merged to Ecma 262. It changes the way to convert between "local time" and UTC in such a way that it'd work for all timezones whether or not there has been any change in the timezone offset of the standard time. For instance, Europe/Moscow and some parts of US state of Indiana have changed the standard (non-DST) timezone offset a few times. The previous spec assumes that the the standard timezone offset is constant, but the new spec take into account the offset change history. In addition, it specifies a new way to calculate the timezone offset during a timezone transition (either in and out of DST or timezone offset shift). During a negative transition (e.g. fall backward / getting out of DST), repeated times are to be interpreted as if the offset before the transition is in effect. During a positive transition (e.g. spring forward / getting into DST), skipped times are to be treated similarly. That is, they are to be interpreted as if the offset before the transition is in effect. With icu-timezone-data, v8 is compliant to the new spec for the past and the future as well as now whether or not the standard timezone offset of a given timezone has changed over time (e.g. Europe/Moscow, Pacific/Apia). With icu-timezone-data, Australia/Lord_Howe (30 minute DST change) also works per spec. Without icu-timezone-data, it works only for timezones of which the standard timezone offset is the same as the current offset (e.g. most North American timezones other than parts of Indiana) and of which the DST shift is an hour. For instance, it doesn't work for Europe/Moscow in 2010 when the standard timezone offset was +4h because the current (2018) standard timezone offset is +3h. Neither does it for Lord Howe in Australia with the DST shift of 0.5 hr. This CL used to require one of the two ICU CLs below, but not any more. https://chromium-review.googlesource.com/c/chromium/deps/icu/+/572652 https://chromium-review.googlesource.com/851265 (a proposed CL to the upstream ICU). Bug: v8:3547,chromium:417640,v8:5714 Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng Change-Id: Ib162295da5bee31b2390bd0918157014aebd3e33 Reviewed-on: https://chromium-review.googlesource.com/572148 Commit-Queue: Jungshik Shin <[email protected]> Reviewed-by: Daniel Ehrenberg <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> Cr-Commit-Position: refs/heads/master@{#52332}
1 parent ef01379 commit dbdede0

21 files changed

+435
-88
lines changed
 

‎src/base/platform/platform-aix.cc

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,21 @@ namespace base {
3939
class AIXTimezoneCache : public PosixTimezoneCache {
4040
const char* LocalTimezone(double time) override;
4141

42-
double LocalTimeOffset() override;
42+
double LocalTimeOffset(double time_ms, bool is_utc) override;
4343

4444
~AIXTimezoneCache() override {}
4545
};
4646

47-
const char* AIXTimezoneCache::LocalTimezone(double time) {
48-
if (std::isnan(time)) return "";
49-
time_t tv = static_cast<time_t>(floor(time / msPerSecond));
47+
const char* AIXTimezoneCache::LocalTimezone(double time_ms) {
48+
if (std::isnan(time_ms)) return "";
49+
time_t tv = static_cast<time_t>(floor(time_ms / msPerSecond));
5050
struct tm tm;
5151
struct tm* t = localtime_r(&tv, &tm);
5252
if (nullptr == t) return "";
5353
return tzname[0]; // The location of the timezone string on AIX.
5454
}
5555

56-
double AIXTimezoneCache::LocalTimeOffset() {
56+
double AIXTimezoneCache::LocalTimeOffset(double time_ms, bool is_utc) {
5757
// On AIX, struct tm does not contain a tm_gmtoff field.
5858
time_t utc = time(nullptr);
5959
DCHECK_NE(utc, -1);

‎src/base/platform/platform-cygwin.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ uint8_t* RandomizedVirtualAlloc(size_t size, DWORD flags, DWORD protect,
6666
class CygwinTimezoneCache : public PosixTimezoneCache {
6767
const char* LocalTimezone(double time) override;
6868

69-
double LocalTimeOffset() override;
69+
double LocalTimeOffset(double time_ms, bool is_utc) override;
7070

7171
~CygwinTimezoneCache() override {}
7272
};
@@ -80,7 +80,7 @@ const char* CygwinTimezoneCache::LocalTimezone(double time) {
8080
return tzname[0]; // The location of the timezone string on Cygwin.
8181
}
8282

83-
double CygwinTimezoneCache::LocalTimeOffset() {
83+
double LocalTimeOffset(double time_ms, bool is_utc) {
8484
// On Cygwin, struct tm does not contain a tm_gmtoff field.
8585
time_t utc = time(nullptr);
8686
DCHECK_NE(utc, -1);

‎src/base/platform/platform-posix-time.cc

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ const char* PosixDefaultTimezoneCache::LocalTimezone(double time) {
1818
return t->tm_zone;
1919
}
2020

21-
double PosixDefaultTimezoneCache::LocalTimeOffset() {
21+
double PosixDefaultTimezoneCache::LocalTimeOffset(double time_ms, bool is_utc) {
22+
// Preserve the old behavior for non-ICU implementation by ignoring both
23+
// time_ms and is_utc.
2224
time_t tv = time(nullptr);
2325
struct tm tm;
2426
struct tm* t = localtime_r(&tv, &tm);

‎src/base/platform/platform-posix-time.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace base {
1313
class PosixDefaultTimezoneCache : public PosixTimezoneCache {
1414
public:
1515
const char* LocalTimezone(double time_ms) override;
16-
double LocalTimeOffset() override;
16+
double LocalTimeOffset(double time_ms, bool is_utc) override;
1717

1818
~PosixDefaultTimezoneCache() override {}
1919
};

‎src/base/platform/platform-solaris.cc

+2-3
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ namespace base {
3737
class SolarisTimezoneCache : public PosixTimezoneCache {
3838
const char* LocalTimezone(double time) override;
3939

40-
double LocalTimeOffset() override;
41-
40+
double LocalTimeOffset(double time, bool is_utc) override;
4241
~SolarisTimezoneCache() override {}
4342
};
4443

@@ -51,7 +50,7 @@ const char* SolarisTimezoneCache::LocalTimezone(double time) {
5150
return tzname[0]; // The location of the timezone string on Solaris.
5251
}
5352

54-
double SolarisTimezoneCache::LocalTimeOffset() {
53+
double SolarisTimezoneCache::LocalTimeOffset(double time, bool is_utc) {
5554
tzset();
5655
return -static_cast<double>(timezone * msPerSecond);
5756
}

‎src/base/platform/platform-win32.cc

+4-2
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class WindowsTimezoneCache : public TimezoneCache {
115115

116116
const char* LocalTimezone(double time) override;
117117

118-
double LocalTimeOffset() override;
118+
double LocalTimeOffset(double time, bool is_utc) override;
119119

120120
double DaylightSavingsOffset(double time) override;
121121

@@ -466,7 +466,9 @@ const char* WindowsTimezoneCache::LocalTimezone(double time) {
466466

467467
// Returns the local time offset in milliseconds east of UTC without
468468
// taking daylight savings time into account.
469-
double WindowsTimezoneCache::LocalTimeOffset() {
469+
double WindowsTimezoneCache::LocalTimeOffset(double time_ms, bool is_utc) {
470+
// Ignore is_utc and time_ms for now. That way, the behavior wouldn't
471+
// change with icu_timezone_data disabled.
470472
// Use current time, rounded to the millisecond.
471473
Win32Time t(OS::TimeCurrentMillis());
472474
// Time::LocalOffset inlcudes any daylight savings offset, so subtract it.

‎src/base/timezone-cache.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ class TimezoneCache {
2020
// ES #sec-local-time-zone-adjustment
2121
// Local Time Zone Adjustment
2222
//
23-
// TODO(littledan): Make more accurate with another parameter along the
24-
// lines of this spec change:
2523
// https://github.com/tc39/ecma262/pull/778
26-
virtual double LocalTimeOffset() = 0;
24+
virtual double LocalTimeOffset(double time_ms, bool is_utc) = 0;
2725

2826
// Called when the local timezone changes
2927
virtual void Clear() = 0;

‎src/date.cc

+71-1
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,14 @@ void DateCache::ResetDateCache() {
5252
dst_usage_counter_ = 0;
5353
before_ = &dst_[0];
5454
after_ = &dst_[1];
55-
local_offset_ms_ = kInvalidLocalOffsetInMs;
5655
ymd_valid_ = false;
56+
#ifdef V8_INTL_SUPPORT
57+
if (!FLAG_icu_timezone_data) {
58+
#endif
59+
local_offset_ms_ = kInvalidLocalOffsetInMs;
60+
#ifdef V8_INTL_SUPPORT
61+
}
62+
#endif
5763
tz_cache_->Clear();
5864
tz_name_ = nullptr;
5965
dst_tz_name_ = nullptr;
@@ -206,6 +212,70 @@ void DateCache::BreakDownTime(int64_t time_ms, int* year, int* month, int* day,
206212
*ms = time_in_day_ms % 1000;
207213
}
208214

215+
// Implements LocalTimeZonedjustment(t, isUTC)
216+
// ECMA 262 - ES#sec-local-time-zone-adjustment
217+
int DateCache::GetLocalOffsetFromOS(int64_t time_ms, bool is_utc) {
218+
double offset;
219+
#ifdef V8_INTL_SUPPORT
220+
if (FLAG_icu_timezone_data) {
221+
offset = tz_cache_->LocalTimeOffset(static_cast<double>(time_ms), is_utc);
222+
} else {
223+
#endif
224+
// When ICU timezone data is not used, we need to compute the timezone
225+
// offset for a given local time.
226+
//
227+
// The following shows that using DST for (t - LocalTZA - hour) produces
228+
// correct conversion where LocalTZA is the timezone offset in winter (no
229+
// DST) and the timezone offset is assumed to have no historical change.
230+
// Note that it does not work for the past and the future if LocalTZA (no
231+
// DST) is different from the current LocalTZA (no DST). For instance,
232+
// this will break for Europe/Moscow in 2012 ~ 2013 because LocalTZA was
233+
// 4h instead of the current 3h (as of 2018).
234+
//
235+
// Consider transition to DST at local time L1.
236+
// Let L0 = L1 - hour, L2 = L1 + hour,
237+
// U1 = UTC time that corresponds to L1,
238+
// U0 = U1 - hour.
239+
// Transitioning to DST moves local clock one hour forward L1 => L2, so
240+
// U0 = UTC time that corresponds to L0 = L0 - LocalTZA,
241+
// U1 = UTC time that corresponds to L1 = L1 - LocalTZA,
242+
// U1 = UTC time that corresponds to L2 = L2 - LocalTZA - hour.
243+
// Note that DST(U0 - hour) = 0, DST(U0) = 0, DST(U1) = 1.
244+
// U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour),
245+
// U1 = L1 - LocalTZA - DST(L1 - LocalTZA - hour),
246+
// U1 = L2 - LocalTZA - DST(L2 - LocalTZA - hour).
247+
//
248+
// Consider transition from DST at local time L1.
249+
// Let L0 = L1 - hour,
250+
// U1 = UTC time that corresponds to L1,
251+
// U0 = U1 - hour, U2 = U1 + hour.
252+
// Transitioning from DST moves local clock one hour back L1 => L0, so
253+
// U0 = UTC time that corresponds to L0 (before transition)
254+
// = L0 - LocalTZA - hour.
255+
// U1 = UTC time that corresponds to L0 (after transition)
256+
// = L0 - LocalTZA = L1 - LocalTZA - hour
257+
// U2 = UTC time that corresponds to L1 = L1 - LocalTZA.
258+
// Note that DST(U0) = 1, DST(U1) = 0, DST(U2) = 0.
259+
// U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour) = L0 - LocalTZA - DST(U0).
260+
// U2 = L1 - LocalTZA - DST(L1 - LocalTZA - hour) = L1 - LocalTZA - DST(U1).
261+
// It is impossible to get U1 from local time.
262+
if (local_offset_ms_ == kInvalidLocalOffsetInMs) {
263+
// This gets the constant LocalTZA (arguments are ignored).
264+
local_offset_ms_ =
265+
tz_cache_->LocalTimeOffset(static_cast<double>(time_ms), is_utc);
266+
}
267+
offset = local_offset_ms_;
268+
if (!is_utc) {
269+
const int kMsPerHour = 3600 * 1000;
270+
time_ms -= (offset + kMsPerHour);
271+
}
272+
offset += DaylightSavingsOffsetInMs(time_ms);
273+
#ifdef V8_INTL_SUPPORT
274+
}
275+
#endif
276+
DCHECK_LT(offset, kInvalidLocalOffsetInMs);
277+
return static_cast<int>(offset);
278+
}
209279

210280
void DateCache::ExtendTheAfterSegment(int time_sec, int offset_ms) {
211281
if (after_->offset_ms == offset_ms &&

‎src/date.h

+10-55
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,9 @@ class DateCache {
7575
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
7676
}
7777

78-
79-
// ECMA 262 - 15.9.1.7.
80-
int LocalOffsetInMs() {
81-
if (local_offset_ms_ == kInvalidLocalOffsetInMs) {
82-
local_offset_ms_ = GetLocalOffsetFromOS();
83-
}
84-
return local_offset_ms_;
78+
// ECMA 262 - ES#sec-local-time-zone-adjustment
79+
int LocalOffsetInMs(int64_t time, bool is_utc) {
80+
return GetLocalOffsetFromOS(time, is_utc);
8581
}
8682

8783

@@ -103,53 +99,16 @@ class DateCache {
10399
return static_cast<int>((time_ms - local_ms) / kMsPerMin);
104100
}
105101

106-
// ECMA 262 - 15.9.1.9
107-
// LocalTime(t) = t + LocalTZA + DaylightSavingTA(t)
102+
// ECMA 262 - ES#sec-localtime-t
103+
// LocalTime(t) = t + LocalTZA(t, true)
108104
int64_t ToLocal(int64_t time_ms) {
109-
return time_ms + LocalOffsetInMs() + DaylightSavingsOffsetInMs(time_ms);
105+
return time_ms + LocalOffsetInMs(time_ms, true);
110106
}
111107

112-
// ECMA 262 - 15.9.1.9
113-
// UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
108+
// ECMA 262 - ES#sec-utc-t
109+
// UTC(t) = t - LocalTZA(t, false)
114110
int64_t ToUTC(int64_t time_ms) {
115-
// We need to compute UTC time that corresponds to the given local time.
116-
// Literally following spec here leads to incorrect time computation at
117-
// the points were we transition to and from DST.
118-
//
119-
// The following shows that using DST for (t - LocalTZA - hour) produces
120-
// correct conversion.
121-
//
122-
// Consider transition to DST at local time L1.
123-
// Let L0 = L1 - hour, L2 = L1 + hour,
124-
// U1 = UTC time that corresponds to L1,
125-
// U0 = U1 - hour.
126-
// Transitioning to DST moves local clock one hour forward L1 => L2, so
127-
// U0 = UTC time that corresponds to L0 = L0 - LocalTZA,
128-
// U1 = UTC time that corresponds to L1 = L1 - LocalTZA,
129-
// U1 = UTC time that corresponds to L2 = L2 - LocalTZA - hour.
130-
// Note that DST(U0 - hour) = 0, DST(U0) = 0, DST(U1) = 1.
131-
// U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour),
132-
// U1 = L1 - LocalTZA - DST(L1 - LocalTZA - hour),
133-
// U1 = L2 - LocalTZA - DST(L2 - LocalTZA - hour).
134-
//
135-
// Consider transition from DST at local time L1.
136-
// Let L0 = L1 - hour,
137-
// U1 = UTC time that corresponds to L1,
138-
// U0 = U1 - hour, U2 = U1 + hour.
139-
// Transitioning from DST moves local clock one hour back L1 => L0, so
140-
// U0 = UTC time that corresponds to L0 (before transition)
141-
// = L0 - LocalTZA - hour.
142-
// U1 = UTC time that corresponds to L0 (after transition)
143-
// = L0 - LocalTZA = L1 - LocalTZA - hour
144-
// U2 = UTC time that corresponds to L1 = L1 - LocalTZA.
145-
// Note that DST(U0) = 1, DST(U1) = 0, DST(U2) = 0.
146-
// U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour) = L0 - LocalTZA - DST(U0).
147-
// U2 = L1 - LocalTZA - DST(L1 - LocalTZA - hour) = L1 - LocalTZA - DST(U1).
148-
// It is impossible to get U1 from local time.
149-
150-
const int kMsPerHour = 3600 * 1000;
151-
time_ms -= LocalOffsetInMs();
152-
return time_ms - DaylightSavingsOffsetInMs(time_ms - kMsPerHour);
111+
return time_ms - LocalOffsetInMs(time_ms, false);
153112
}
154113

155114

@@ -208,11 +167,7 @@ class DateCache {
208167
return static_cast<int>(tz_cache_->DaylightSavingsOffset(time_ms));
209168
}
210169

211-
virtual int GetLocalOffsetFromOS() {
212-
double offset = tz_cache_->LocalTimeOffset();
213-
DCHECK_LT(offset, kInvalidLocalOffsetInMs);
214-
return static_cast<int>(offset);
215-
}
170+
virtual int GetLocalOffsetFromOS(int64_t time_ms, bool is_utc);
216171

217172
private:
218173
// The implementation relies on the fact that no time zones have

‎src/intl.cc

+26-7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "src/isolate.h"
1515
#include "src/objects-inl.h"
1616
#include "src/string-case.h"
17+
#include "unicode/basictz.h"
1718
#include "unicode/calendar.h"
1819
#include "unicode/gregocal.h"
1920
#include "unicode/timezone.h"
@@ -373,23 +374,41 @@ icu::TimeZone* ICUTimezoneCache::GetTimeZone() {
373374
return timezone_;
374375
}
375376

376-
bool ICUTimezoneCache::GetOffsets(double time_ms, int32_t* raw_offset,
377-
int32_t* dst_offset) {
377+
bool ICUTimezoneCache::GetOffsets(double time_ms, bool is_utc,
378+
int32_t* raw_offset, int32_t* dst_offset) {
378379
UErrorCode status = U_ZERO_ERROR;
379-
GetTimeZone()->getOffset(time_ms, false, *raw_offset, *dst_offset, status);
380+
// TODO(jshin): ICU TimeZone class handles skipped time differently from
381+
// Ecma 262 (https://github.com/tc39/ecma262/pull/778) and icu::TimeZone
382+
// class does not expose the necessary API. Fixing
383+
// http://bugs.icu-project.org/trac/ticket/13268 would make it easy to
384+
// implement the proposed spec change. A proposed fix for ICU is
385+
// https://chromium-review.googlesource.com/851265 .
386+
// In the meantime, use an internal (still public) API of icu::BasicTimeZone.
387+
// Once it's accepted by the upstream, get rid of cast. Note that casting
388+
// TimeZone to BasicTimeZone is safe because we know that icu::TimeZone used
389+
// here is a BasicTimeZone.
390+
if (is_utc) {
391+
GetTimeZone()->getOffset(time_ms, false, *raw_offset, *dst_offset, status);
392+
} else {
393+
static_cast<const icu::BasicTimeZone*>(GetTimeZone())
394+
->getOffsetFromLocal(time_ms, icu::BasicTimeZone::kFormer,
395+
icu::BasicTimeZone::kFormer, *raw_offset,
396+
*dst_offset, status);
397+
}
398+
380399
return U_SUCCESS(status);
381400
}
382401

383402
double ICUTimezoneCache::DaylightSavingsOffset(double time_ms) {
384403
int32_t raw_offset, dst_offset;
385-
if (!GetOffsets(time_ms, &raw_offset, &dst_offset)) return 0;
404+
if (!GetOffsets(time_ms, true, &raw_offset, &dst_offset)) return 0;
386405
return dst_offset;
387406
}
388407

389-
double ICUTimezoneCache::LocalTimeOffset() {
408+
double ICUTimezoneCache::LocalTimeOffset(double time_ms, bool is_utc) {
390409
int32_t raw_offset, dst_offset;
391-
if (!GetOffsets(icu::Calendar::getNow(), &raw_offset, &dst_offset)) return 0;
392-
return raw_offset;
410+
if (!GetOffsets(time_ms, is_utc, &raw_offset, &dst_offset)) return 0;
411+
return raw_offset + dst_offset;
393412
}
394413

395414
void ICUTimezoneCache::Clear() {

‎src/intl.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,15 @@ class ICUTimezoneCache : public base::TimezoneCache {
4848

4949
double DaylightSavingsOffset(double time_ms) override;
5050

51-
double LocalTimeOffset() override;
51+
double LocalTimeOffset(double time_ms, bool is_utc) override;
5252

5353
void Clear() override;
5454

5555
private:
5656
icu::TimeZone* GetTimeZone();
5757

58-
bool GetOffsets(double time_ms, int32_t* raw_offset, int32_t* dst_offset);
58+
bool GetOffsets(double time_ms, bool is_utc, int32_t* raw_offset,
59+
int32_t* dst_offset);
5960

6061
icu::TimeZone* timezone_;
6162

‎test/cctest/test-date.cc

+3-5
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,8 @@ class DateCacheMock: public DateCache {
5353
return rule == nullptr ? 0 : rule->offset_sec * 1000;
5454
}
5555

56-
57-
virtual int GetLocalOffsetFromOS() {
58-
return local_offset_;
56+
virtual int GetLocalOffsetFromOS(int64_t time_sec, bool is_utc) {
57+
return local_offset_ + GetDaylightSavingsOffsetFromOS(time_sec);
5958
}
6059

6160
private:
@@ -113,8 +112,7 @@ static void CheckDST(int64_t time) {
113112
Isolate* isolate = CcTest::i_isolate();
114113
DateCache* date_cache = isolate->date_cache();
115114
int64_t actual = date_cache->ToLocal(time);
116-
int64_t expected = time + date_cache->GetLocalOffsetFromOS() +
117-
date_cache->GetDaylightSavingsOffsetFromOS(time / 1000);
115+
int64_t expected = time + date_cache->GetLocalOffsetFromOS(time, true);
118116
CHECK_EQ(actual, expected);
119117
}
120118

‎test/mjsunit/mjsunit.status

+12
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@
181181
# noi18n cannot turn on ICU backend for Date
182182
'icu-date-to-string': [PASS, ['no_i18n == True', SKIP]],
183183
'icu-date-lord-howe': [PASS, ['no_i18n == True', SKIP]],
184+
'tzoffset-transition-apia': [PASS, ['no_i18n == True', SKIP]],
185+
'tzoffset-transition-lord-howe': [PASS, ['no_i18n == True', SKIP]],
186+
'tzoffset-transition-moscow': [PASS, ['no_i18n == True', SKIP]],
187+
'tzoffset-transition-new-york': [PASS, ['no_i18n == True', SKIP]],
188+
'tzoffset-seoul': [PASS, ['no_i18n == True', SKIP]],
184189

185190
# TODO(bmeurer): Flaky timeouts (sometimes <1s, sometimes >3m).
186191
'unicodelctest': [PASS, NO_VARIANTS],
@@ -609,6 +614,13 @@
609614
'icu-date-to-string': [SKIP],
610615
'icu-date-lord-howe': [SKIP],
611616
'regress/regress-6288': [SKIP],
617+
'tzoffset-transition-apia': [SKIP],
618+
'tzoffset-transition-lord-howe': [SKIP],
619+
'tzoffset-transition-moscow': [SKIP],
620+
'tzoffset-transition-new-york': [SKIP],
621+
'tzoffset-transition-new-york-noi18n': [SKIP],
622+
'tzoffset-seoul': [SKIP],
623+
'tzoffset-seoul-noi18n': [SKIP],
612624
}], # 'system == windows'
613625

614626
##############################################################################

‎test/mjsunit/tzoffset-seoul-noi18n.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2018 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --no-icu-timezone-data
6+
// Environment Variables: TZ=Asia/Seoul
7+
8+
// Seoul has DST (UTC+10) in 1987 and 1988.
9+
assertEquals(new Date(Date.UTC(1986, 5, 22, 3)),
10+
new Date(1986, 5, 22, 12))
11+
assertEquals(new Date(Date.UTC(1987, 5, 22, 2)),
12+
new Date(1987, 5, 22, 12))
13+
assertEquals(new Date(Date.UTC(1987, 11, 22, 3)),
14+
new Date(1987, 11, 22, 12))
15+
assertEquals(new Date(Date.UTC(1988, 5, 22, 2)),
16+
new Date(1988, 5, 22, 12))
17+
assertEquals(new Date(Date.UTC(1988, 11, 22, 3)),
18+
new Date(1988, 11, 22, 12))
19+
assertEquals(new Date(Date.UTC(1989, 5, 22, 3)),
20+
new Date(1989, 5, 22, 12))

‎test/mjsunit/tzoffset-seoul.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2018 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --icu-timezone-data
6+
// Environment Variables: TZ=Asia/Seoul
7+
8+
// Seoul has DST (UTC+10) in 1987 and 1988.
9+
assertEquals(new Date(Date.UTC(1986, 5, 22, 3)),
10+
new Date(1986, 5, 22, 12))
11+
assertEquals(new Date(Date.UTC(1987, 5, 22, 2)),
12+
new Date(1987, 5, 22, 12))
13+
assertEquals(new Date(Date.UTC(1987, 11, 22, 3)),
14+
new Date(1987, 11, 22, 12))
15+
assertEquals(new Date(Date.UTC(1988, 5, 22, 2)),
16+
new Date(1988, 5, 22, 12))
17+
assertEquals(new Date(Date.UTC(1988, 11, 22, 3)),
18+
new Date(1988, 11, 22, 12))
19+
assertEquals(new Date(Date.UTC(1989, 5, 22, 3)),
20+
new Date(1989, 5, 22, 12))
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2018 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --icu-timezone-data
6+
// Environment Variables: TZ=Pacific/Apia
7+
8+
// https://www.timeanddate.com/time/zone/samoa/apia
9+
10+
// 2011-09-24T03:00 : UTC-11 => UTC-10
11+
assertEquals(new Date(Date.UTC(2011, 8, 24, 13, 59)),
12+
new Date(2011, 8, 24, 2, 59))
13+
assertEquals(new Date(Date.UTC(2011, 8, 24, 14, 30)),
14+
new Date(2011, 8, 24, 3, 30));
15+
assertEquals(new Date(Date.UTC(2011, 8, 24, 14)),
16+
new Date(2011, 8, 24, 4));
17+
assertEquals(new Date(Date.UTC(2011, 8, 24, 14, 30)),
18+
new Date(2011, 8, 24, 4, 30));
19+
assertEquals((new Date(2011, 8, 24, 4, 30)).getTimezoneOffset(),
20+
(new Date(2011, 8, 24, 3, 30)).getTimezoneOffset());
21+
22+
// 2011-12-30T00:00 : UTC-10 => UTC+14
23+
// A whole day(2011-12-30; 24 hours) is skipped, but the skipped
24+
// time is to be interpreted with an offset before the transition.
25+
assertEquals(new Date(Date.UTC(2011, 11, 30, 9, 59)),
26+
new Date(2011, 11, 29, 23, 59));
27+
for (var h = 0; h < 24; ++h) {
28+
assertEquals(new Date(Date.UTC(2011, 11, 30, h + 10)),
29+
new Date(2011, 11, 30, h));
30+
assertEquals(new Date(Date.UTC(2011, 11, 30, h + 10, 30)),
31+
new Date(2011, 11, 30, h, 30));
32+
assertEquals(new Date(Date.UTC(2011, 11, 30, h + 10)),
33+
new Date(2011, 11, 31, h));
34+
assertEquals(new Date(Date.UTC(2011, 11, 30, h + 10, 30)),
35+
new Date(2011, 11, 31, h, 30));
36+
}
37+
assertEquals(new Date(Date.UTC(2011, 11, 31, 10)),
38+
new Date(2012, 0, 1, 0));
39+
40+
// 2012-04-01T0400: UTC+14 => UTC+13
41+
assertEquals(new Date(Date.UTC(2012, 2, 31, 13)),
42+
new Date(2012, 3, 1, 3));
43+
assertEquals(new Date(Date.UTC(2012, 2, 31, 13, 30)),
44+
new Date(2012, 3, 1, 3, 30));
45+
assertEquals(new Date(Date.UTC(2012, 2, 31, 13, 59)),
46+
new Date(2012, 3, 1, 3, 59))
47+
assertEquals(new Date(Date.UTC(2012, 2, 31, 15)),
48+
new Date(2012, 3, 1, 4))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2018 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --icu-timezone-data
6+
// Environment Variables: TZ=Australia/Lord_Howe
7+
8+
9+
// 2017-04-02T02:00 : UTC+11 => UTC+1030
10+
assertEquals(new Date(Date.UTC(2017, 3, 1, 14, 29)),
11+
new Date(2017, 3, 2, 1, 29));
12+
assertEquals(new Date(Date.UTC(2017, 3, 1, 14, 30)),
13+
new Date(2017, 3, 2, 1, 30));
14+
assertEquals(new Date(Date.UTC(2017, 3, 1, 14, 45)),
15+
new Date(2017, 3, 2, 1, 45));
16+
assertEquals(new Date(Date.UTC(2017, 3, 1, 14, 59)),
17+
new Date(2017, 3, 2, 1, 59));
18+
assertEquals(new Date(Date.UTC(2017, 3, 1, 15, 30)),
19+
new Date(2017, 3, 2, 2));
20+
assertEquals(new Date(Date.UTC(2017, 3, 1, 15, 31)),
21+
new Date(2017, 3, 2, 2, 1));
22+
23+
// 2017-10-07T02:00 : UTC+1030 => UTC+11
24+
assertEquals(new Date(Date.UTC(2017, 8, 30, 15, 29)),
25+
new Date(2017, 9, 1, 1, 59))
26+
assertEquals(new Date(Date.UTC(2017, 8, 30, 15, 30)),
27+
new Date(2017, 9, 1, 2));
28+
assertEquals(new Date(Date.UTC(2017, 8, 30, 15, 45)),
29+
new Date(2017, 9, 1, 2, 15));
30+
assertEquals(new Date(Date.UTC(2017, 8, 30, 15, 30)),
31+
new Date(2017, 9, 1, 2, 30));
32+
assertEquals(new Date(Date.UTC(2017, 8, 30, 15, 45)),
33+
new Date(2017, 9, 1, 2, 45));
34+
assertEquals((new Date(2017, 9, 1, 2, 45)).getTimezoneOffset(),
35+
(new Date(2017, 9, 1, 2, 15)).getTimezoneOffset());
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2017 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --icu-timezone-data
6+
// Environment Variables: TZ=Europe/Moscow
7+
8+
// https://www.timeanddate.com/time/zone/russia/moscow
9+
10+
// 2010-03-28T02:00 : UTC+3 => UTC+4
11+
assertEquals(new Date(Date.UTC(2010, 2, 27, 22, 59)),
12+
new Date(2010, 2, 28, 1, 59));
13+
assertEquals(new Date(Date.UTC(2010, 2, 27, 23)),
14+
new Date(2010, 2, 28, 2));
15+
assertEquals(new Date(Date.UTC(2010, 2, 27, 23, 30)),
16+
new Date(2010, 2, 28, 2, 30));
17+
assertEquals(new Date(Date.UTC(2010, 2, 27, 23)),
18+
new Date(2010, 2, 28, 3));
19+
assertEquals(new Date(Date.UTC(2010, 2, 27, 23, 30)),
20+
new Date(2010, 2, 28, 3, 30));
21+
assertEquals((new Date(2010, 2, 28, 3, 30)).getTimezoneOffset(),
22+
(new Date(2010, 2, 28, 2, 30)).getTimezoneOffset());
23+
24+
// 2010-10-31T03:00 : UTC+4 => UTC+3
25+
assertEquals(new Date(Date.UTC(2010, 9, 30, 21, 59)),
26+
new Date(2010, 9, 31, 1, 59));
27+
assertEquals(new Date(Date.UTC(2010, 9, 30, 22)),
28+
new Date(2010, 9, 31, 2));
29+
assertEquals(new Date(Date.UTC(2010, 9, 30, 22, 30)),
30+
new Date(2010, 9, 31, 2, 30));
31+
assertEquals(new Date(Date.UTC(2010, 9, 30, 22, 59)),
32+
new Date(2010, 9, 31, 2, 59))
33+
assertEquals(new Date(Date.UTC(2010, 9, 31, 0)),
34+
new Date(2010, 9, 31, 3))
35+
assertEquals(new Date(Date.UTC(2010, 9, 31, 0, 30)),
36+
new Date(2010, 9, 31, 3, 30))
37+
38+
// 2011-03-27T02:00 : UTC+3 => UTC+4
39+
assertEquals(new Date(Date.UTC(2011, 2, 26, 22, 59)),
40+
new Date(2011, 2, 27, 1, 59))
41+
assertEquals(new Date(Date.UTC(2011, 2, 26, 23)),
42+
new Date(2011, 2, 27, 2));
43+
assertEquals(new Date(Date.UTC(2011, 2, 26, 23, 30)),
44+
new Date(2011, 2, 27, 2, 30));
45+
assertEquals(new Date(Date.UTC(2011, 2, 26, 23)),
46+
new Date(2011, 2, 27, 3));
47+
assertEquals(new Date(Date.UTC(2011, 2, 26, 23, 30)),
48+
new Date(2011, 2, 27, 3, 30));
49+
assertEquals((new Date(2011, 2, 27, 3, 30)).getTimezoneOffset(),
50+
(new Date(2011, 2, 27, 2, 30)).getTimezoneOffset());
51+
52+
// No daylight saving time in 2012, 2013: UTC+4 year-round
53+
assertEquals(new Date(Date.UTC(2012, 5, 21, 0)),
54+
new Date(2012, 5, 21, 4))
55+
assertEquals(new Date(Date.UTC(2012, 11, 21, 0)),
56+
new Date(2012, 11, 21, 4))
57+
assertEquals(new Date(Date.UTC(2013, 5, 21, 0)),
58+
new Date(2013, 5, 21, 4))
59+
assertEquals(new Date(Date.UTC(2013, 11, 21, 0)),
60+
new Date(2013, 11, 21, 4))
61+
62+
// 2014-10-26T0200: UTC+4 => UTC+3 (year-round)
63+
assertEquals(new Date(Date.UTC(2014, 9, 25, 20, 59)),
64+
new Date(2014, 9, 26, 0, 59));
65+
assertEquals(new Date(Date.UTC(2014, 9, 25, 21)),
66+
new Date(2014, 9, 26, 1));
67+
assertEquals(new Date(Date.UTC(2014, 9, 25, 21, 30)),
68+
new Date(2014, 9, 26, 1, 30));
69+
assertEquals(new Date(Date.UTC(2014, 9, 25, 21, 59)),
70+
new Date(2014, 9, 26, 1, 59))
71+
assertEquals(new Date(Date.UTC(2014, 9, 25, 23)),
72+
new Date(2014, 9, 26, 2))
73+
assertEquals(new Date(Date.UTC(2014, 9, 25, 23, 1)),
74+
new Date(2014, 9, 26, 2, 1))
75+
76+
assertEquals(new Date(Date.UTC(2014, 11, 21, 0)),
77+
new Date(2014, 11, 21, 3))
78+
assertEquals(new Date(Date.UTC(2015, 5, 21, 0)),
79+
new Date(2015, 5, 21, 3))
80+
assertEquals(new Date(Date.UTC(2015, 11, 21, 0)),
81+
new Date(2015, 11, 21, 3))
82+
assertEquals(new Date(Date.UTC(2016, 5, 21, 0)),
83+
new Date(2016, 5, 21, 3))
84+
assertEquals(new Date(Date.UTC(2015, 11, 21, 0)),
85+
new Date(2015, 11, 21, 3))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2018 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --no-icu-timezone-data
6+
// Environment Variables: TZ=America/New_York
7+
8+
// 2017-03-12T02:00 : UTC-5 => UTC-4
9+
assertEquals(new Date(Date.UTC(2017, 2, 12, 6, 59)),
10+
new Date(2017, 2, 12, 1, 59))
11+
assertEquals(new Date(Date.UTC(2017, 2, 12, 7)),
12+
new Date(2017, 2, 12, 2));
13+
assertEquals(new Date(Date.UTC(2017, 2, 12, 7, 30)),
14+
new Date(2017, 2, 12, 2, 30));
15+
assertEquals(new Date(Date.UTC(2017, 2, 12, 7)),
16+
new Date(2017, 2, 12, 3));
17+
assertEquals(new Date(Date.UTC(2017, 2, 12, 7, 30)),
18+
new Date(2017, 2, 12, 3, 30));
19+
assertEquals((new Date(2017, 2, 12, 3, 30)).getTimezoneOffset(),
20+
(new Date(2017, 2, 12, 2, 30)).getTimezoneOffset());
21+
22+
// 2017-11-05T02:00 : UTC-4 => UTC-5
23+
assertEquals(new Date(Date.UTC(2017, 10, 5, 4, 59)),
24+
new Date(2017, 10, 5, 0, 59));
25+
assertEquals(new Date(Date.UTC(2017, 10, 5, 5)),
26+
new Date(2017, 10, 5, 1));
27+
assertEquals(new Date(Date.UTC(2017, 10, 5, 5, 30)),
28+
new Date(2017, 10, 5, 1, 30));
29+
assertEquals(new Date(Date.UTC(2017, 10, 5, 5, 59)),
30+
new Date(2017, 10, 5, 1, 59));
31+
assertEquals(new Date(Date.UTC(2017, 10, 5, 7)),
32+
new Date(2017, 10, 5, 2))
33+
assertEquals(new Date(Date.UTC(2017, 10, 5, 8)),
34+
new Date(2017, 10, 5, 3))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2018 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --icu-timezone-data
6+
// Environment Variables: TZ=America/New_York
7+
8+
// 2017-03-12T02:00 : UTC-5 => UTC-4
9+
assertEquals(new Date(Date.UTC(2017, 2, 12, 6, 59)),
10+
new Date(2017, 2, 12, 1, 59))
11+
assertEquals(new Date(Date.UTC(2017, 2, 12, 7)),
12+
new Date(2017, 2, 12, 2));
13+
assertEquals(new Date(Date.UTC(2017, 2, 12, 7, 30)),
14+
new Date(2017, 2, 12, 2, 30));
15+
assertEquals(new Date(Date.UTC(2017, 2, 12, 7)),
16+
new Date(2017, 2, 12, 3));
17+
assertEquals(new Date(Date.UTC(2017, 2, 12, 7, 30)),
18+
new Date(2017, 2, 12, 3, 30));
19+
assertEquals((new Date(2017, 2, 12, 3, 30)).getTimezoneOffset(),
20+
(new Date(2017, 2, 12, 2, 30)).getTimezoneOffset());
21+
22+
// 2017-11-05T02:00 : UTC-4 => UTC-5
23+
assertEquals(new Date(Date.UTC(2017, 10, 5, 4, 59)),
24+
new Date(2017, 10, 5, 0, 59));
25+
assertEquals(new Date(Date.UTC(2017, 10, 5, 5)),
26+
new Date(2017, 10, 5, 1));
27+
assertEquals(new Date(Date.UTC(2017, 10, 5, 5, 30)),
28+
new Date(2017, 10, 5, 1, 30));
29+
assertEquals(new Date(Date.UTC(2017, 10, 5, 5, 59)),
30+
new Date(2017, 10, 5, 1, 59));
31+
assertEquals(new Date(Date.UTC(2017, 10, 5, 7)),
32+
new Date(2017, 10, 5, 2))
33+
assertEquals(new Date(Date.UTC(2017, 10, 5, 8)),
34+
new Date(2017, 10, 5, 3))

‎test/mozilla/mozilla.status

+16-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,22 @@
225225

226226
# 1050186: Arm/MIPS vm is broken; probably unrelated to dates
227227
'ecma/Array/15.4.4.5-3': [PASS, ['arch == arm or arch == mipsel or arch == mips', FAIL]],
228-
'ecma/Date/15.9.5.22-2': [PASS, ['arch == arm or arch == mipsel or arch == mips', FAIL]],
228+
229+
# These 4 tests made an incorrect assumption that the timezone offset of any
230+
# given timezone has not changed over time. With icu-timezone-data enabled
231+
# and https://github.com/tc39/ecma262/pull/778 implemented, the historical
232+
# timezone offset is handled properly and these tests are broken in i18n
233+
# build. It's non-trivial to fix them because they strive to work in *any*
234+
# timezone.
235+
# TODO(jshin): Add equivalent tests with a specific timezone using TZ variable
236+
# on Linux to mjsunit.
237+
238+
'ecma/Date/15.9.5.16': [PASS, ['no_i18n == False', FAIL]],
239+
'ecma/Date/15.9.5.18': [PASS, ['no_i18n == False', FAIL]],
240+
'ecma/Date/15.9.5.22-1': [PASS, ['no_i18n == False', FAIL]],
241+
242+
# 1050186: Arm/MIPS vm is broken; probably unrelated to dates
243+
'ecma/Date/15.9.5.22-2': [PASS, ['no_i18n == False or arch == arm or arch == mipsel or arch == mips', FAIL]],
229244

230245
# Flaky test that fails due to what appears to be a bug in the test.
231246
# Occurs depending on current time

0 commit comments

Comments
 (0)
Please sign in to comment.