dart-sdk/runtime/lib/date.cc
Regis Crelier 48dc790398 Fix core lib DateTime in the VM (fixes #19923).
Symptom of the problem:
Set your Linux workstation (or Mac or MIPS board) to the Europe/London timezone
and the corelib/date_time test will fail, claiming that 1/1/1970 was a Wednesday
(it was actually a Thursday, trust me, I was already born).

Problem:
The implementation of DateTime in the VM relies on Unix time_t, the number of
seconds since the Epoch (1/1/1970 UTC). When asked for the weekday of a given
time, our implementation limits itself to a 32-bit positive range of time_t.
If the time falls outside of this range, the implementation picks an equivalent
time in the valid range with the same weekday, also in leap year or not, etc...
The issue is that DateTime is using the underlying OS in an inconsistent manner.
Let's take the example above: 1/1/1970 in the Europe/London timezone.
First, the number of seconds since the Epoch in UTC is calculated, here 0.
Then, the timezone offset at the given time is calculated using the underlying
OS. In this case, an historical deviation is taken into account. Indeed, London
stayed on British Summer Time between 27 October 1968 and 31 October 1971. See
https://en.wikipedia.org/wiki/British_Summer_Time#Periods_of_deviation for
details.
Our resulting time is therefore negative (one hour difference with UTC).
When asked about the weekday of this time, the implementation notices that the
time is not in the positive range and picks an "equivalent" time in the future.
It then asks the underlying OS about the timezone offset for this time, which
is 0 (usually no daylight saving time in January in London). Unfortunately,
this time is not really equivalent, because it ignores the original historical
deviation. The result is wrongly equivalent to 12/31/1969 23:00 in London, i.e.
a Wednesday, and not a Thursday as expected.

Solution:
We should use the underlying OS in a consistent way, by simply allowing the
value of time_t passed to the underlying OS to be negative, which is legal.

R=floitsch@google.com, rmacnak@google.com

Review URL: https://codereview.chromium.org/1845483002 .
2016-03-30 10:09:58 -07:00

52 lines
1.4 KiB
C++

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <time.h>
#include "vm/bootstrap_natives.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/os.h"
namespace dart {
static int64_t kMaxAllowedSeconds = kMaxInt32;
DEFINE_NATIVE_ENTRY(DateTime_timeZoneName, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(
Integer, dart_seconds, arguments->NativeArgAt(0));
int64_t seconds = dart_seconds.AsInt64Value();
if (llabs(seconds) > kMaxAllowedSeconds) {
Exceptions::ThrowArgumentError(dart_seconds);
}
const char* name = OS::GetTimeZoneName(seconds);
return String::New(name);
}
DEFINE_NATIVE_ENTRY(DateTime_timeZoneOffsetInSeconds, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(
Integer, dart_seconds, arguments->NativeArgAt(0));
int64_t seconds = dart_seconds.AsInt64Value();
if (llabs(seconds) > kMaxAllowedSeconds) {
Exceptions::ThrowArgumentError(dart_seconds);
}
int offset = OS::GetTimeZoneOffsetInSeconds(seconds);
return Integer::New(offset);
}
DEFINE_NATIVE_ENTRY(DateTime_localTimeZoneAdjustmentInSeconds, 0) {
int adjustment = OS::GetLocalTimeZoneAdjustmentInSeconds();
return Integer::New(adjustment);
}
DEFINE_NATIVE_ENTRY(DateTime_currentTimeMicros, 0) {
return Integer::New(OS::GetCurrentTimeMicros());
}
} // namespace dart