Skip to content

Commit 1d3a87b

Browse files
jungshikCommit Bot
authored and
Commit Bot
committedApr 4, 2018
Reland "Implement a new spec for timezone offset calculation"
This is a reland of dbdede0 after a webkit layout test (geolocation-api/timestamp.html) was fixed by https://chromium-review.googlesource.com/c/chromium/src/+/994343 . Original change's description: > 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} Bug: v8:3547, chromium:417640, v8:5714 Change-Id: I47536c111143f75e3cfeecf5d9761c43a98a10f5 Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng;master.tryserver.blink:linux_trusty_blink_rel Reviewed-on: https://chromium-review.googlesource.com/995971 Commit-Queue: Jungshik Shin <[email protected]> Reviewed-by: Clemens Hammacher <[email protected]> Cr-Commit-Position: refs/heads/master@{#52372}
1 parent 539a244 commit 1d3a87b

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.