Index: runtime/lib/date.cc |
diff --git a/runtime/lib/date.cc b/runtime/lib/date.cc |
index 9a993428627f1649eb3abb23b9f4f31b35ce8dfd..47f5c635edc336890a50c1366ec422991a934654 100644 |
--- a/runtime/lib/date.cc |
+++ b/runtime/lib/date.cc |
@@ -2,6 +2,8 @@ |
// 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/bigint_operations.h" |
@@ -11,13 +13,98 @@ |
namespace dart { |
+typedef struct BrokenDownDate { |
+ intptr_t year; |
+ intptr_t month; // [1..12] |
+ intptr_t day; // [1..31] |
+ intptr_t hours; |
+ intptr_t minutes; |
+ intptr_t seconds; |
+} BrokenDownDate; |
+ |
+ |
+// Takes the seconds since epoch (midnight, January 1, 1970 UTC) and breaks it |
+// down into date and time. |
+// If 'dart_is_utc', then the broken down date and time are in the UTC timezone, |
+// otherwise the local timezone is used. |
+// The returned year is offset by 1900. The returned month is 0-based. |
+// Returns true if the conversion succeeds, false otherwise. |
static bool BreakDownSecondsSinceEpoch(const Integer& dart_seconds, |
const Bool& dart_is_utc, |
- OS::BrokenDownDate* result) { |
+ BrokenDownDate* result) { |
+ // Always fill the result to avoid unitialized use warnings. |
+ result->year = 0; |
+ result->month = 0; |
+ result->day = 0; |
+ result->hours = 0; |
+ result->minutes = 0; |
+ result->seconds = 0; |
+ |
bool is_utc = dart_is_utc.value(); |
- int64_t value = dart_seconds.AsInt64Value(); |
- time_t seconds = static_cast<time_t>(value); |
- return OS::BreakDownSecondsSinceEpoch(seconds, is_utc, result); |
+ int64_t seconds = dart_seconds.AsInt64Value(); |
+ |
+ struct tm tm_result; |
+ bool succeeded; |
+ if (is_utc) { |
+ succeeded = OS::GmTime(seconds, &tm_result); |
+ } else { |
+ succeeded = OS::LocalTime(seconds, &tm_result); |
+ } |
+ if (succeeded) { |
+ result->year = tm_result.tm_year; |
+ // C uses years since 1900, and not full years. |
+ // Adding 1900 could overflow the intptr_t. |
+ if (tm_result.tm_year > kIntptrMax - 1900) return false; |
+ result->year += 1900; |
+ // Dart has 1-based months (contrary to C's 0-based). |
+ result->month= tm_result.tm_mon + 1; |
+ result->day = tm_result.tm_mday; |
+ result->hours = tm_result.tm_hour; |
+ result->minutes = tm_result.tm_min; |
+ result->seconds = tm_result.tm_sec; |
+ } |
+ return succeeded; |
+} |
+ |
+ |
+static bool BrokenDownToSecondsSinceEpoch(const BrokenDownDate& broken_down, |
+ bool in_utc, |
+ int64_t* result) { |
+ // Always set the result to avoid unitialized use warnings. |
+ *result = 0; |
+ |
+ struct tm tm_broken_down; |
+ intptr_t year = broken_down.year; |
+ // C works with years since 1900. |
+ // Removing 1900 could underflow the intptr_t. |
+ if (year < kIntptrMin + 1900) return false; |
+ year -= 1900; |
+ intptr_t month = broken_down.month; |
+ // C works with 0-based months. |
+ // Avoid underflows (even though they should not matter since the date would |
+ // be invalid anyways. |
+ if (month < 0) return false; |
+ month--; |
+ tm_broken_down.tm_year = static_cast<int>(year); |
+ tm_broken_down.tm_mon = static_cast<int>(month); |
+ tm_broken_down.tm_mday = static_cast<int>(broken_down.day); |
+ tm_broken_down.tm_hour = static_cast<int>(broken_down.hours); |
+ tm_broken_down.tm_min = static_cast<int>(broken_down.minutes); |
+ tm_broken_down.tm_sec = static_cast<int>(broken_down.seconds); |
+ // Verify that casting to int did not change the value. |
+ if (tm_broken_down.tm_year != year |
+ || tm_broken_down.tm_mon != month |
+ || tm_broken_down.tm_mday != broken_down.day |
+ || tm_broken_down.tm_hour != broken_down.hours |
+ || tm_broken_down.tm_min != broken_down.minutes |
+ || tm_broken_down.tm_sec != broken_down.seconds) { |
+ return false; |
+ } |
+ if (in_utc) { |
+ return OS::MkGmTime(&tm_broken_down, result); |
+ } else { |
+ return OS::MkTime(&tm_broken_down, result); |
+ } |
} |
@@ -34,24 +121,17 @@ DEFINE_NATIVE_ENTRY(DateNatives_brokenDownToSecondsSinceEpoch, 7) { |
} |
Smi& smi_years = Smi::Handle(); |
smi_years ^= dart_years.raw(); |
- OS::BrokenDownDate broken_down; |
- // mktime takes the years since 1900. |
- // TODO(floitsch): Removing 1900 could underflow the intptr_t. |
- intptr_t year = smi_years.Value() - 1900; |
- // TODO(1143): We don't handle the case yet where intptr_t and int have |
- // different sizes. |
- // ASSERT(sizeof(year) <= sizeof(broken_down.year)); |
- broken_down.year = static_cast<int>(year); |
- // libc months are 0-based (contrary to Dart' 1-based months). |
- broken_down.month = dart_month.Value() - 1; |
+ BrokenDownDate broken_down; |
+ broken_down.year = smi_years.Value(); |
+ broken_down.month = dart_month.Value(); |
broken_down.day = dart_day.Value(); |
broken_down.hours = dart_hours.Value(); |
broken_down.minutes = dart_minutes.Value(); |
broken_down.seconds = dart_seconds.Value(); |
- time_t value; |
- bool succeeded = OS::BrokenDownToSecondsSinceEpoch(broken_down, |
- dart_is_utc.value(), |
- &value); |
+ int64_t value; |
+ bool succeeded = BrokenDownToSecondsSinceEpoch(broken_down, |
+ dart_is_utc.value(), |
+ &value); |
if (!succeeded) { |
UNIMPLEMENTED(); |
} |
@@ -69,15 +149,13 @@ DEFINE_NATIVE_ENTRY(DateNatives_currentTimeMillis, 0) { |
DEFINE_NATIVE_ENTRY(DateNatives_getYear, 2) { |
GET_NATIVE_ARGUMENT(Integer, dart_seconds, arguments->At(0)); |
GET_NATIVE_ARGUMENT(Bool, dart_is_utc, arguments->At(1)); |
- OS::BrokenDownDate broken_down; |
+ BrokenDownDate broken_down; |
bool succeeded = |
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down); |
if (!succeeded) { |
UNIMPLEMENTED(); |
} |
- // C uses years since 1900, and not full years. |
- // TODO(floitsch): adding 1900 could overflow the intptr_t. |
- intptr_t year = broken_down.year + 1900; |
+ intptr_t year = broken_down.year; |
arguments->SetReturn(Integer::Handle(Integer::New(year))); |
} |
@@ -85,14 +163,13 @@ DEFINE_NATIVE_ENTRY(DateNatives_getYear, 2) { |
DEFINE_NATIVE_ENTRY(DateNatives_getMonth, 2) { |
GET_NATIVE_ARGUMENT(Integer, dart_seconds, arguments->At(0)); |
GET_NATIVE_ARGUMENT(Bool, dart_is_utc, arguments->At(1)); |
- OS::BrokenDownDate broken_down; |
+ BrokenDownDate broken_down; |
bool succeeded = |
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down); |
if (!succeeded) { |
UNIMPLEMENTED(); |
} |
- // Dart has 1-based months (contrary to C's 0-based). |
- const Smi& result = Smi::Handle(Smi::New(broken_down.month + 1)); |
+ const Smi& result = Smi::Handle(Smi::New(broken_down.month)); |
arguments->SetReturn(result); |
} |
@@ -100,7 +177,7 @@ DEFINE_NATIVE_ENTRY(DateNatives_getMonth, 2) { |
DEFINE_NATIVE_ENTRY(DateNatives_getDay, 2) { |
GET_NATIVE_ARGUMENT(Integer, dart_seconds, arguments->At(0)); |
GET_NATIVE_ARGUMENT(Bool, dart_is_utc, arguments->At(1)); |
- OS::BrokenDownDate broken_down; |
+ BrokenDownDate broken_down; |
bool succeeded = |
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down); |
if (!succeeded) { |
@@ -114,7 +191,7 @@ DEFINE_NATIVE_ENTRY(DateNatives_getDay, 2) { |
DEFINE_NATIVE_ENTRY(DateNatives_getHours, 2) { |
GET_NATIVE_ARGUMENT(Integer, dart_seconds, arguments->At(0)); |
GET_NATIVE_ARGUMENT(Bool, dart_is_utc, arguments->At(1)); |
- OS::BrokenDownDate broken_down; |
+ BrokenDownDate broken_down; |
bool succeeded = |
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down); |
if (!succeeded) { |
@@ -128,7 +205,7 @@ DEFINE_NATIVE_ENTRY(DateNatives_getHours, 2) { |
DEFINE_NATIVE_ENTRY(DateNatives_getMinutes, 2) { |
GET_NATIVE_ARGUMENT(Integer, dart_seconds, arguments->At(0)); |
GET_NATIVE_ARGUMENT(Bool, dart_is_utc, arguments->At(1)); |
- OS::BrokenDownDate broken_down; |
+ BrokenDownDate broken_down; |
bool succeeded = |
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down); |
if (!succeeded) { |
@@ -142,7 +219,7 @@ DEFINE_NATIVE_ENTRY(DateNatives_getMinutes, 2) { |
DEFINE_NATIVE_ENTRY(DateNatives_getSeconds, 2) { |
GET_NATIVE_ARGUMENT(Integer, dart_seconds, arguments->At(0)); |
GET_NATIVE_ARGUMENT(Bool, dart_is_utc, arguments->At(1)); |
- OS::BrokenDownDate broken_down; |
+ BrokenDownDate broken_down; |
bool succeeded = |
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down); |
if (!succeeded) { |