merge(3p/abseil_cpp): Merge upstream at 'ccdbb5941'
Change-Id: I6e85fc7b5f76bba1f1eef15e600a8acb64e97ef5
This commit is contained in:
commit
543379ce45
97 changed files with 3546 additions and 2316 deletions
|
|
@ -97,8 +97,8 @@ void BM_PrevWeekday(benchmark::State& state) {
|
|||
}
|
||||
BENCHMARK(BM_PrevWeekday);
|
||||
|
||||
const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
|
||||
const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
|
||||
const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
|
||||
const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
|
||||
|
||||
const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
|
||||
const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
|
||||
|
|
@ -991,12 +991,12 @@ void BM_Time_FromCivilDay0_Libc(benchmark::State& state) {
|
|||
BENCHMARK(BM_Time_FromCivilDay0_Libc);
|
||||
|
||||
const char* const kFormats[] = {
|
||||
RFC1123_full, // 0
|
||||
RFC1123_no_wday, // 1
|
||||
RFC3339_full, // 2
|
||||
RFC3339_sec, // 3
|
||||
"%Y-%m-%dT%H:%M:%S", // 4
|
||||
"%Y-%m-%d", // 5
|
||||
RFC1123_full, // 0
|
||||
RFC1123_no_wday, // 1
|
||||
RFC3339_full, // 2
|
||||
RFC3339_sec, // 3
|
||||
"%Y-%m-%d%ET%H:%M:%S", // 4
|
||||
"%Y-%m-%d", // 5
|
||||
};
|
||||
const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,16 @@ TEST(CivilTime, Difference) {
|
|||
static_assert(diff == 365, "Difference");
|
||||
}
|
||||
|
||||
// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
|
||||
TEST(CivilTime, ConstructionWithHugeYear) {
|
||||
constexpr civil_hour h(-9223372036854775807, 1, 1, -1);
|
||||
static_assert(h.year() == -9223372036854775807 - 1,
|
||||
"ConstructionWithHugeYear");
|
||||
static_assert(h.month() == 12, "ConstructionWithHugeYear");
|
||||
static_assert(h.day() == 31, "ConstructionWithHugeYear");
|
||||
static_assert(h.hour() == 23, "ConstructionWithHugeYear");
|
||||
}
|
||||
|
||||
// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
|
||||
TEST(CivilTime, DifferenceWithHugeYear) {
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,6 +67,48 @@ char* strptime(const char* s, const char* fmt, std::tm* tm) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
|
||||
int ToTmWday(weekday wd) {
|
||||
switch (wd) {
|
||||
case weekday::sunday:
|
||||
return 0;
|
||||
case weekday::monday:
|
||||
return 1;
|
||||
case weekday::tuesday:
|
||||
return 2;
|
||||
case weekday::wednesday:
|
||||
return 3;
|
||||
case weekday::thursday:
|
||||
return 4;
|
||||
case weekday::friday:
|
||||
return 5;
|
||||
case weekday::saturday:
|
||||
return 6;
|
||||
}
|
||||
return 0; /*NOTREACHED*/
|
||||
}
|
||||
|
||||
// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
|
||||
weekday FromTmWday(int tm_wday) {
|
||||
switch (tm_wday) {
|
||||
case 0:
|
||||
return weekday::sunday;
|
||||
case 1:
|
||||
return weekday::monday;
|
||||
case 2:
|
||||
return weekday::tuesday;
|
||||
case 3:
|
||||
return weekday::wednesday;
|
||||
case 4:
|
||||
return weekday::thursday;
|
||||
case 5:
|
||||
return weekday::friday;
|
||||
case 6:
|
||||
return weekday::saturday;
|
||||
}
|
||||
return weekday::sunday; /*NOTREACHED*/
|
||||
}
|
||||
|
||||
std::tm ToTM(const time_zone::absolute_lookup& al) {
|
||||
std::tm tm{};
|
||||
tm.tm_sec = al.cs.second();
|
||||
|
|
@ -84,34 +126,19 @@ std::tm ToTM(const time_zone::absolute_lookup& al) {
|
|||
tm.tm_year = static_cast<int>(al.cs.year() - 1900);
|
||||
}
|
||||
|
||||
switch (get_weekday(al.cs)) {
|
||||
case weekday::sunday:
|
||||
tm.tm_wday = 0;
|
||||
break;
|
||||
case weekday::monday:
|
||||
tm.tm_wday = 1;
|
||||
break;
|
||||
case weekday::tuesday:
|
||||
tm.tm_wday = 2;
|
||||
break;
|
||||
case weekday::wednesday:
|
||||
tm.tm_wday = 3;
|
||||
break;
|
||||
case weekday::thursday:
|
||||
tm.tm_wday = 4;
|
||||
break;
|
||||
case weekday::friday:
|
||||
tm.tm_wday = 5;
|
||||
break;
|
||||
case weekday::saturday:
|
||||
tm.tm_wday = 6;
|
||||
break;
|
||||
}
|
||||
tm.tm_wday = ToTmWday(get_weekday(al.cs));
|
||||
tm.tm_yday = get_yearday(al.cs) - 1;
|
||||
tm.tm_isdst = al.is_dst ? 1 : 0;
|
||||
return tm;
|
||||
}
|
||||
|
||||
// Returns the week of the year [0:53] given a civil day and the day on
|
||||
// which weeks are defined to start.
|
||||
int ToWeek(const civil_day& cd, weekday week_start) {
|
||||
const civil_day d(cd.year() % 400, cd.month(), cd.day());
|
||||
return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
|
||||
}
|
||||
|
||||
const char kDigits[] = "0123456789";
|
||||
|
||||
// Formats a 64-bit integer in the given field width. Note that it is up
|
||||
|
|
@ -290,6 +317,7 @@ const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
|
|||
// - %E#S - Seconds with # digits of fractional precision
|
||||
// - %E*S - Seconds with full fractional precision (a literal '*')
|
||||
// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
|
||||
// - %ET - The RFC3339 "date-time" separator "T"
|
||||
//
|
||||
// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
|
||||
// handled internally for performance reasons. strftime(3) is slow due to
|
||||
|
|
@ -354,7 +382,7 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
|
|||
if (cur == end || (cur - percent) % 2 == 0) continue;
|
||||
|
||||
// Simple specifiers that we handle ourselves.
|
||||
if (strchr("YmdeHMSzZs%", *cur)) {
|
||||
if (strchr("YmdeUuWwHMSzZs%", *cur)) {
|
||||
if (cur - 1 != pending) {
|
||||
FormatTM(&result, std::string(pending, cur - 1), tm);
|
||||
}
|
||||
|
|
@ -375,6 +403,22 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
|
|||
if (*cur == 'e' && *bp == '0') *bp = ' '; // for Windows
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'U':
|
||||
bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'u':
|
||||
bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'W':
|
||||
bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'w':
|
||||
bp = Format64(ep, 0, tm.tm_wday);
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'H':
|
||||
bp = Format02d(ep, al.cs.hour());
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
|
|
@ -448,7 +492,14 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
|
|||
if (*cur != 'E' || ++cur == end) continue;
|
||||
|
||||
// Format our extensions.
|
||||
if (*cur == 'z') {
|
||||
if (*cur == 'T') {
|
||||
// Formats %ET.
|
||||
if (cur - 2 != pending) {
|
||||
FormatTM(&result, std::string(pending, cur - 2), tm);
|
||||
}
|
||||
result.append("T");
|
||||
pending = ++cur;
|
||||
} else if (*cur == 'z') {
|
||||
// Formats %Ez.
|
||||
if (cur - 2 != pending) {
|
||||
FormatTM(&result, std::string(pending, cur - 2), tm);
|
||||
|
|
@ -551,7 +602,7 @@ const char* ParseOffset(const char* dp, const char* mode, int* offset) {
|
|||
} else {
|
||||
dp = nullptr;
|
||||
}
|
||||
} else if (first == 'Z') { // Zulu
|
||||
} else if (first == 'Z' || first == 'z') { // Zulu
|
||||
*offset = 0;
|
||||
} else {
|
||||
dp = nullptr;
|
||||
|
|
@ -602,12 +653,23 @@ const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
|
|||
return dp;
|
||||
}
|
||||
|
||||
// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
|
||||
// and the day on which weeks are defined to start.
|
||||
void FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
|
||||
const civil_year y(*year % 400);
|
||||
civil_day cd = prev_weekday(y, week_start); // week 0
|
||||
cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
|
||||
*year += cd.year() - y.year();
|
||||
tm->tm_mon = cd.month() - 1;
|
||||
tm->tm_mday = cd.day();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Uses strptime(3) to parse the given input. Supports the same extended
|
||||
// format specifiers as format(), although %E#S and %E*S are treated
|
||||
// identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept
|
||||
// the same inputs.
|
||||
// the same inputs. %ET accepts either 'T' or 't'.
|
||||
//
|
||||
// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
|
||||
// handled internally so that we can normally avoid strptime() altogether
|
||||
|
|
@ -651,6 +713,8 @@ bool parse(const std::string& format, const std::string& input,
|
|||
const char* fmt = format.c_str(); // NUL terminated
|
||||
bool twelve_hour = false;
|
||||
bool afternoon = false;
|
||||
int week_num = -1;
|
||||
weekday week_start = weekday::sunday;
|
||||
|
||||
bool saw_percent_s = false;
|
||||
std::int_fast64_t percent_s = 0;
|
||||
|
|
@ -689,10 +753,27 @@ bool parse(const std::string& format, const std::string& input,
|
|||
case 'm':
|
||||
data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
|
||||
if (data != nullptr) tm.tm_mon -= 1;
|
||||
week_num = -1;
|
||||
continue;
|
||||
case 'd':
|
||||
case 'e':
|
||||
data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
|
||||
week_num = -1;
|
||||
continue;
|
||||
case 'U':
|
||||
data = ParseInt(data, 0, 0, 53, &week_num);
|
||||
week_start = weekday::sunday;
|
||||
continue;
|
||||
case 'W':
|
||||
data = ParseInt(data, 0, 0, 53, &week_num);
|
||||
week_start = weekday::monday;
|
||||
continue;
|
||||
case 'u':
|
||||
data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
|
||||
if (data != nullptr) tm.tm_wday %= 7;
|
||||
continue;
|
||||
case 'w':
|
||||
data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
|
||||
continue;
|
||||
case 'H':
|
||||
data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
|
||||
|
|
@ -742,6 +823,15 @@ bool parse(const std::string& format, const std::string& input,
|
|||
data = (*data == '%' ? data + 1 : nullptr);
|
||||
continue;
|
||||
case 'E':
|
||||
if (fmt[0] == 'T') {
|
||||
if (*data == 'T' || *data == 't') {
|
||||
++data;
|
||||
++fmt;
|
||||
} else {
|
||||
data = nullptr;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
|
||||
data = ParseOffset(data, ":", &offset);
|
||||
if (data != nullptr) saw_offset = true;
|
||||
|
|
@ -874,6 +964,9 @@ bool parse(const std::string& format, const std::string& input,
|
|||
year += 1900;
|
||||
}
|
||||
|
||||
// Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
|
||||
if (week_num != -1) FromWeek(week_num, week_start, &year, &tm);
|
||||
|
||||
const int month = tm.tm_mon + 1;
|
||||
civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ namespace {
|
|||
EXPECT_STREQ(zone, al.abbr); \
|
||||
} while (0)
|
||||
|
||||
const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
|
||||
const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
|
||||
const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
|
||||
const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
|
||||
|
||||
const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
|
||||
const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
|
||||
|
|
@ -679,6 +679,34 @@ TEST(Format, RFC1123Format) { // locale specific
|
|||
EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
|
||||
}
|
||||
|
||||
TEST(Format, Week) {
|
||||
const time_zone utc = utc_time_zone();
|
||||
|
||||
auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
|
||||
EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc));
|
||||
EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc));
|
||||
|
||||
tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
|
||||
EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc));
|
||||
EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc));
|
||||
|
||||
tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
|
||||
EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc));
|
||||
EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc));
|
||||
|
||||
tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
|
||||
EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc));
|
||||
EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc));
|
||||
|
||||
tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
|
||||
EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc));
|
||||
EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc));
|
||||
|
||||
tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
|
||||
EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc));
|
||||
EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc));
|
||||
}
|
||||
|
||||
//
|
||||
// Testing parse()
|
||||
//
|
||||
|
|
@ -1379,10 +1407,80 @@ TEST(Parse, RFC3339Format) {
|
|||
EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp));
|
||||
ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC");
|
||||
|
||||
// Check that %Ez also accepts "Z" as a synonym for "+00:00".
|
||||
// Check that %ET also accepts "t".
|
||||
time_point<chrono::nanoseconds> tp2;
|
||||
EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp2));
|
||||
EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2));
|
||||
EXPECT_EQ(tp, tp2);
|
||||
|
||||
// Check that %Ez also accepts "Z" as a synonym for "+00:00".
|
||||
time_point<chrono::nanoseconds> tp3;
|
||||
EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3));
|
||||
EXPECT_EQ(tp, tp3);
|
||||
|
||||
// Check that %Ez also accepts "z" as a synonym for "+00:00".
|
||||
time_point<chrono::nanoseconds> tp4;
|
||||
EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4));
|
||||
EXPECT_EQ(tp, tp4);
|
||||
}
|
||||
|
||||
TEST(Parse, Week) {
|
||||
const time_zone utc = utc_time_zone();
|
||||
time_point<absl::time_internal::cctz::seconds> tp;
|
||||
|
||||
auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
|
||||
EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
|
||||
exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
|
||||
EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
|
||||
exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
|
||||
EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
|
||||
exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
|
||||
EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
|
||||
exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
|
||||
EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
|
||||
exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
|
||||
EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
}
|
||||
|
||||
TEST(Parse, WeekYearShift) {
|
||||
// %U/%W conversions with week values in {0, 52, 53} can slip
|
||||
// into the previous/following calendar years.
|
||||
const time_zone utc = utc_time_zone();
|
||||
time_point<absl::time_internal::cctz::seconds> tp;
|
||||
|
||||
auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
|
||||
EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
|
||||
exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc);
|
||||
EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
}
|
||||
|
||||
TEST(Parse, MaxRange) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "time_zone_impl.h"
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
|
@ -48,17 +49,16 @@ std::mutex& TimeZoneMutex() {
|
|||
time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); }
|
||||
|
||||
bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
|
||||
const time_zone::Impl* const utc_impl = UTCImpl();
|
||||
const Impl* const utc_impl = UTCImpl();
|
||||
|
||||
// First check for UTC (which is never a key in time_zone_map).
|
||||
// Check for UTC (which is never a key in time_zone_map).
|
||||
auto offset = seconds::zero();
|
||||
if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
|
||||
*tz = time_zone(utc_impl);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Then check, under a shared lock, whether the time zone has already
|
||||
// been loaded. This is the common path. TODO: Move to shared_mutex.
|
||||
// Check whether the time zone has already been loaded.
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(TimeZoneMutex());
|
||||
if (time_zone_map != nullptr) {
|
||||
|
|
@ -70,20 +70,15 @@ bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
|
|||
}
|
||||
}
|
||||
|
||||
// Now check again, under an exclusive lock.
|
||||
// Load the new time zone (outside the lock).
|
||||
std::unique_ptr<const Impl> new_impl(new Impl(name));
|
||||
|
||||
// Add the new time zone to the map.
|
||||
std::lock_guard<std::mutex> lock(TimeZoneMutex());
|
||||
if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
|
||||
const Impl*& impl = (*time_zone_map)[name];
|
||||
if (impl == nullptr) {
|
||||
// The first thread in loads the new time zone.
|
||||
Impl* new_impl = new Impl(name);
|
||||
new_impl->zone_ = TimeZoneIf::Load(new_impl->name_);
|
||||
if (new_impl->zone_ == nullptr) {
|
||||
delete new_impl; // free the nascent Impl
|
||||
impl = utc_impl; // and fallback to UTC
|
||||
} else {
|
||||
impl = new_impl; // install new time zone
|
||||
}
|
||||
if (impl == nullptr) { // this thread won any load race
|
||||
impl = new_impl->zone_ ? new_impl.release() : utc_impl;
|
||||
}
|
||||
*tz = time_zone(impl);
|
||||
return impl != utc_impl;
|
||||
|
|
@ -104,14 +99,11 @@ void time_zone::Impl::ClearTimeZoneMapTestOnly() {
|
|||
}
|
||||
}
|
||||
|
||||
time_zone::Impl::Impl(const std::string& name) : name_(name) {}
|
||||
time_zone::Impl::Impl(const std::string& name)
|
||||
: name_(name), zone_(TimeZoneIf::Load(name_)) {}
|
||||
|
||||
const time_zone::Impl* time_zone::Impl::UTCImpl() {
|
||||
static Impl* utc_impl = [] {
|
||||
Impl* impl = new Impl("UTC");
|
||||
impl->zone_ = TimeZoneIf::Load(impl->name_); // never fails
|
||||
return impl;
|
||||
}();
|
||||
static const Impl* utc_impl = new Impl("UTC"); // never fails
|
||||
return utc_impl;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -933,7 +933,7 @@ TEST(MakeTime, Normalization) {
|
|||
|
||||
// NOTE: Run this with -ftrapv to detect overflow problems.
|
||||
TEST(MakeTime, SysSecondsLimits) {
|
||||
const char RFC3339[] = "%Y-%m-%dT%H:%M:%S%Ez";
|
||||
const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
|
||||
const time_zone utc = utc_time_zone();
|
||||
const time_zone east = fixed_time_zone(chrono::hours(14));
|
||||
const time_zone west = fixed_time_zone(-chrono::hours(14));
|
||||
|
|
|
|||
|
|
@ -83,7 +83,8 @@ ZoneInfoSourceFactory default_factory = DefaultFactory;
|
|||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@@ZA")
|
||||
#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
|
||||
#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM) || \
|
||||
defined(_M_ARM64)
|
||||
#pragma comment( \
|
||||
linker, \
|
||||
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue