mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Report time zones with no DST transition within a year as not observing
In locations where daylight saving time was once observed or is expected to be observed in the future, but where no transitions to or from daylight saving time occurred or will occur within a year of the current date, act as though DST is not being observed at all. Set TZ=America/Phoenix to test for this bug. BUG=crashpad:130 TEST=crashpad_snapshot_test SystemSnapshotMacTest.TimeZone Change-Id: Ie466b5906eab3c0cf2e51b962a171acb5b16210b Reviewed-on: https://chromium-review.googlesource.com/438004 Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
parent
594eb43b58
commit
b638163e72
@ -19,6 +19,8 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "build/build_config.h"
|
||||
@ -349,34 +351,44 @@ void SystemSnapshotMac::TimeZone(DaylightSavingTimeStatus* dst_status,
|
||||
PCHECK(localtime_r(&snapshot_time_->tv_sec, &local)) << "localtime_r";
|
||||
|
||||
*standard_name = tzname[0];
|
||||
|
||||
bool found_transition = false;
|
||||
long probe_gmtoff = local.tm_gmtoff;
|
||||
if (daylight) {
|
||||
// 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;
|
||||
|
||||
// |local|. It’s possible that no such instance will be found even with
|
||||
// |daylight| set. This can happen in locations where daylight saving time
|
||||
// was once observed or is expected to be observed in the future, but where
|
||||
// no transitions to or from daylight saving time occurred or will occur
|
||||
// within a year of the current date. Arizona, which last observed daylight
|
||||
// saving time in 1967, is an example.
|
||||
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
|
||||
for (size_t index = 0;
|
||||
index < arraysize(kMonthDeltas) && !found_transition;
|
||||
++index) {
|
||||
// Look at a 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_mday = std::min(local.tm_mday, 28);
|
||||
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) {
|
||||
found_transition = true;
|
||||
probe_gmtoff = probe_tm.tm_gmtoff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found_transition) {
|
||||
*daylight_name = tzname[1];
|
||||
if (!local.tm_isdst) {
|
||||
*dst_status = kObservingStandardTime;
|
||||
|
@ -14,11 +14,13 @@
|
||||
|
||||
#include "snapshot/mac/system_snapshot_mac.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/mac/process_reader.h"
|
||||
@ -127,6 +129,39 @@ TEST_F(SystemSnapshotMacTest, MachineDescription) {
|
||||
EXPECT_FALSE(system_snapshot().MachineDescription().empty());
|
||||
}
|
||||
|
||||
class ScopedSetTZ {
|
||||
public:
|
||||
ScopedSetTZ(const std::string& tz) {
|
||||
const char* old_tz = getenv(kTZ);
|
||||
old_tz_set_ = old_tz;
|
||||
if (old_tz_set_) {
|
||||
old_tz_.assign(old_tz);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, setenv(kTZ, tz.c_str(), 1)) << ErrnoMessage("setenv");
|
||||
tzset();
|
||||
}
|
||||
|
||||
~ScopedSetTZ() {
|
||||
if (old_tz_set_) {
|
||||
EXPECT_EQ(0, setenv(kTZ, old_tz_.c_str(), 1)) << ErrnoMessage("setenv");
|
||||
} else {
|
||||
EXPECT_EQ(0, unsetenv(kTZ)) << ErrnoMessage("unsetenv");
|
||||
}
|
||||
tzset();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string old_tz_;
|
||||
bool old_tz_set_;
|
||||
|
||||
static constexpr char kTZ[] = "TZ";
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedSetTZ);
|
||||
};
|
||||
|
||||
constexpr char ScopedSetTZ::kTZ[];
|
||||
|
||||
TEST_F(SystemSnapshotMacTest, TimeZone) {
|
||||
SystemSnapshot::DaylightSavingTimeStatus dst_status;
|
||||
int standard_offset_seconds;
|
||||
@ -169,6 +204,68 @@ TEST_F(SystemSnapshotMacTest, TimeZone) {
|
||||
|
||||
EXPECT_NE(standard_name, daylight_name);
|
||||
}
|
||||
|
||||
// Test a variety of time zones. Some of these observe daylight saving time,
|
||||
// some don’t. Some used to but no longer do. Some have uncommon UTC offsets.
|
||||
const struct {
|
||||
const char* tz;
|
||||
bool observes_dst;
|
||||
float standard_offset_hours;
|
||||
float daylight_offset_hours;
|
||||
const char* standard_name;
|
||||
const char* daylight_name;
|
||||
} kTestTimeZones[] = {
|
||||
{"America/Anchorage", true, -9, -8, "AKST", "AKDT"},
|
||||
{"America/Chicago", true, -6, -5, "CST", "CDT"},
|
||||
{"America/Denver", true, -7, -6, "MST", "MDT"},
|
||||
{"America/Halifax", true, -4, -3, "AST", "ADT"},
|
||||
{"America/Los_Angeles", true, -8, -7, "PST", "PDT"},
|
||||
{"America/New_York", true, -5, -4, "EST", "EDT"},
|
||||
{"America/Phoenix", false, -7, -7, "MST", "MST"},
|
||||
{"Asia/Karachi", false, 5, 5, "PKT", "PKT"},
|
||||
{"Asia/Kolkata", false, 5.5, 5.5, "IST", "IST"},
|
||||
{"Asia/Shanghai", false, 8, 8, "CST", "CST"},
|
||||
{"Asia/Tokyo", false, 9, 9, "JST", "JST"},
|
||||
{"Australia/Adelaide", true, 9.5, 10.5, "ACST", "ACDT"},
|
||||
{"Australia/Brisbane", false, 10, 10, "AEST", "AEST"},
|
||||
{"Australia/Darwin", false, 9.5, 9.5, "ACST", "ACST"},
|
||||
{"Australia/Eucla", false, 8.75, 8.75, "ACWST", "ACWST"},
|
||||
{"Australia/Lord_Howe", true, 10.5, 11, "LHST", "LHDT"},
|
||||
{"Australia/Perth", false, 8, 8, "AWST", "AWST"},
|
||||
{"Australia/Sydney", true, 10, 11, "AEST", "AEDT"},
|
||||
{"Europe/Bucharest", true, 2, 3, "EET", "EEST"},
|
||||
{"Europe/London", true, 0, 1, "GMT", "BST"},
|
||||
{"Europe/Moscow", false, 3, 3, "MSK", "MSK"},
|
||||
{"Europe/Paris", true, 1, 2, "CET", "CEST"},
|
||||
{"Europe/Reykjavik", false, 0, 0, "UTC", "UTC"},
|
||||
{"Pacific/Auckland", true, 12, 13, "NZST", "NZDT"},
|
||||
{"Pacific/Honolulu", false, -10, -10, "HST", "HST"},
|
||||
{"UTC", false, 0, 0, "UTC", "UTC"},
|
||||
};
|
||||
|
||||
for (size_t index = 0; index < arraysize(kTestTimeZones); ++index) {
|
||||
const auto& test_time_zone = kTestTimeZones[index];
|
||||
const char* tz = test_time_zone.tz;
|
||||
SCOPED_TRACE(base::StringPrintf("index %zu, tz %s", index, tz));
|
||||
|
||||
{
|
||||
ScopedSetTZ set_tz(tz);
|
||||
system_snapshot().TimeZone(&dst_status,
|
||||
&standard_offset_seconds,
|
||||
&daylight_offset_seconds,
|
||||
&standard_name,
|
||||
&daylight_name);
|
||||
}
|
||||
|
||||
EXPECT_EQ(test_time_zone.observes_dst,
|
||||
dst_status != SystemSnapshot::kDoesNotObserveDaylightSavingTime);
|
||||
EXPECT_EQ(test_time_zone.standard_offset_hours * 60 * 60,
|
||||
standard_offset_seconds);
|
||||
EXPECT_EQ(test_time_zone.daylight_offset_hours * 60 * 60,
|
||||
daylight_offset_seconds);
|
||||
EXPECT_EQ(test_time_zone.standard_name, standard_name);
|
||||
EXPECT_EQ(test_time_zone.daylight_name, daylight_name);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user