mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Improve SystemSnapshotMac::TimeZone()’s computation of UTC offsets.
In locations that observe daylight saving time, this method now probes different times to determine the offset when DST observance is (or is not) in effect. This replaces a hard-coded one-hour offset, accounting for Lord Howe Island, Australia, which is at a 30-minute offset. TEST=snapshot_test SystemSnapshotMacTest.TimeZone R=rsesek@chromium.org Review URL: https://codereview.chromium.org/626093005
This commit is contained in:
parent
6b451ea32a
commit
0ff46a4e60
@ -342,23 +342,45 @@ void SystemSnapshotMac::TimeZone(DaylightSavingTimeStatus* dst_status,
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
tm local;
|
||||
localtime_r(&snapshot_time_->tv_sec, &local);
|
||||
PCHECK(localtime_r(&snapshot_time_->tv_sec, &local)) << "localtime_r";
|
||||
|
||||
*standard_name = tzname[0];
|
||||
if (daylight) {
|
||||
// This assumes that the offset between standard and daylight saving time is
|
||||
// globally a constant, where a time zone’s daylight saving time is one hour
|
||||
// ahead of its standard time.
|
||||
const int kSecondsPerHour = 60 * 60;
|
||||
// Scan forward and backward, one month at a time, looking for an instance
|
||||
// when the observance of daylight saving time is different than it is in
|
||||
// |local|.
|
||||
long probe_gmtoff = local.tm_gmtoff;
|
||||
|
||||
const int kMonthDeltas[] =
|
||||
{ 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6,
|
||||
7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12 };
|
||||
for (size_t index = 0; index < arraysize(kMonthDeltas); ++index) {
|
||||
// Look at the 15th day of each month at local noon. Set tm_isdst to -1 to
|
||||
// avoid giving mktime() any hints about whether to consider daylight
|
||||
// saving time in effect. mktime() accepts values of tm_mon that are
|
||||
// outside of its normal range and behaves as expected: if tm_mon is -1,
|
||||
// it references December of the preceding year, and if it is 12, it
|
||||
// references January of the following year.
|
||||
tm probe_tm = {};
|
||||
probe_tm.tm_hour = 12;
|
||||
probe_tm.tm_mday = 15;
|
||||
probe_tm.tm_mon = local.tm_mon + kMonthDeltas[index];
|
||||
probe_tm.tm_year = local.tm_year;
|
||||
probe_tm.tm_isdst = -1;
|
||||
if (mktime(&probe_tm) != -1 && probe_tm.tm_isdst != local.tm_isdst) {
|
||||
probe_gmtoff = probe_tm.tm_gmtoff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*daylight_name = tzname[1];
|
||||
if (!local.tm_isdst) {
|
||||
*dst_status = kObservingStandardTime;
|
||||
*standard_offset_seconds = local.tm_gmtoff;
|
||||
*daylight_offset_seconds = local.tm_gmtoff + kSecondsPerHour;
|
||||
*daylight_offset_seconds = probe_gmtoff;
|
||||
} else {
|
||||
*dst_status = kObservingDaylightSavingTime;
|
||||
*standard_offset_seconds = local.tm_gmtoff - kSecondsPerHour;
|
||||
*standard_offset_seconds = probe_gmtoff;
|
||||
*daylight_offset_seconds = local.tm_gmtoff;
|
||||
}
|
||||
} else {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "snapshot/system_snapshot_mac.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -86,7 +87,7 @@ TEST_F(SystemSnapshotMacTest, CPUVendor) {
|
||||
// Apple has only shipped Intel x86-family CPUs, but here’s a small nod to the
|
||||
// “Hackintosh” crowd.
|
||||
if (cpu_vendor != "GenuineIntel" && cpu_vendor != "AuthenticAMD") {
|
||||
FAIL() << cpu_vendor;
|
||||
FAIL() << "cpu_vendor " << cpu_vendor;
|
||||
}
|
||||
#else
|
||||
#error port to your architecture
|
||||
@ -127,4 +128,48 @@ TEST_F(SystemSnapshotMacTest, MachineDescription) {
|
||||
EXPECT_FALSE(system_snapshot().MachineDescription().empty());
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotMacTest, TimeZone) {
|
||||
SystemSnapshot::DaylightSavingTimeStatus dst_status;
|
||||
int standard_offset_seconds;
|
||||
int daylight_offset_seconds;
|
||||
std::string standard_name;
|
||||
std::string daylight_name;
|
||||
|
||||
system_snapshot().TimeZone(&dst_status,
|
||||
&standard_offset_seconds,
|
||||
&daylight_offset_seconds,
|
||||
&standard_name,
|
||||
&daylight_name);
|
||||
|
||||
// |standard_offset_seconds| gives seconds east of UTC, and |timezone| gives
|
||||
// seconds west of UTC.
|
||||
EXPECT_EQ(-timezone, standard_offset_seconds);
|
||||
|
||||
// In contemporary usage, most time zones have an integer hour offset from
|
||||
// UTC, although several are at a half-hour offset, and two are at 15-minute
|
||||
// offsets. Throughout history, other variations existed. See
|
||||
// http://www.timeanddate.com/time/time-zones-interesting.html.
|
||||
EXPECT_EQ(0, standard_offset_seconds % (15 * 60))
|
||||
<< "standard_offset_seconds " << standard_offset_seconds;
|
||||
|
||||
if (dst_status == SystemSnapshot::kDoesNotObserveDaylightSavingTime) {
|
||||
EXPECT_EQ(standard_offset_seconds, daylight_offset_seconds);
|
||||
EXPECT_EQ(standard_name, daylight_name);
|
||||
} else {
|
||||
EXPECT_EQ(0, daylight_offset_seconds % (15 * 60))
|
||||
<< "daylight_offset_seconds " << daylight_offset_seconds;
|
||||
|
||||
// In contemporary usage, dst_delta_seconds will almost always be one hour,
|
||||
// except for Lord Howe Island, Australia, which uses a 30-minute
|
||||
// delta. Throughout history, other variations existed. See
|
||||
// http://www.timeanddate.com/time/dst/#brief.
|
||||
int dst_delta_seconds = daylight_offset_seconds - standard_offset_seconds;
|
||||
if (dst_delta_seconds != 60 * 60 && dst_delta_seconds != 30 * 60) {
|
||||
FAIL() << "dst_delta_seconds " << dst_delta_seconds;
|
||||
}
|
||||
|
||||
EXPECT_NE(standard_name, daylight_name);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user