Commit af788260 by Abseil Team Committed by Derek Mauro

- fd5f3d7077270ffc5ea74cdb9e18bbae3b9b46aa Fix typo optional -> variant by…

  - fd5f3d7077270ffc5ea74cdb9e18bbae3b9b46aa Fix typo optional -> variant by Abseil Team <absl-team@google.com>
  - 9136c06dfa8dbfdde0a427ad3509e34763d607a6 Fix string_view_test and str_cat_test build under MSVC de... by Derek Mauro <dmauro@google.com>
  - a463820f9441888f4368aa87328599e3209f9b07 Removes constexpr optional<T>::operator->(). This was don... by Abseil Team <absl-team@google.com>
  - 3bf78a7f126daafff329f7815d507422f1ca378d Remove dependencies on external CCTZ project. by Shaindel Schwartz <shaindel@google.com>
  - a4ae574a11b1ddf6e88459af3d638cf79aea7ecd Internal change by Jon Cohen <cohenjon@google.com>

GitOrigin-RevId: fd5f3d7077270ffc5ea74cdb9e18bbae3b9b46aa
Change-Id: I6ab8ab99863716fe9b2745a12ef285f7a6da6d1e
parent 94ce52d4
......@@ -34,7 +34,7 @@ function(absl_library)
cmake_parse_arguments(ABSL_LIB
"DISABLE_INSTALL" # keep that in case we want to support installation one day
"TARGET;EXPORT_NAME"
"SOURCES;PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS;PUBLIC_INCLUDE_DIRS;PRIVATE_INCLUDE_DIRS"
"SOURCES;PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS"
${ARGN}
)
......
......@@ -19,10 +19,8 @@ googletest framework
### Step-by-Step Instructions
1. If you haven't done so already, integrate the Abseil dependency
[CCTZ](https://github.com/google/cctz) into your CMake project. Consequently, the
target 'cctz' needs to be declared in your CMake project **before** including Abseil.<br>
Note: If you want to build the Abseil tests, you'll also need [Google Test](https://github.com/google/googletest). To disable Abseil tests, you have to pass
1. If you want to build the Abseil tests, integrate the Abseil dependency
[Google Test](https://github.com/google/googletest) into your CMake project. To disable Abseil tests, you have to pass
`-DBUILD_TESTING=OFF` when configuring your project with CMake.
2. Download Abseil and copy it into a subdirectory in your CMake project or add
......@@ -31,8 +29,7 @@ CMake project.
3. You can then use the CMake command
[`add_subdirectory()`](https://cmake.org/cmake/help/latest/command/add_subdirectory.html)
to include Abseil directly in your CMake project. In addition, it's possible to
customize the name of the `cctz` target with the `-DABSL_CCTZ_TARGET=*my_cctz*` option.
to include Abseil directly in your CMake project.
4. Add the **absl::** target you wish to use to the
[`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
......
......@@ -65,15 +65,9 @@ set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
## pthread
find_package(Threads REQUIRED)
if(NOT ABSL_CCTZ_TARGET)
set(ABSL_CCTZ_TARGET cctz)
endif()
# commented: used only for standalone test
# Don't remove these or else CMake CI will break
#add_subdirectory(cctz)
#add_subdirectory(googletest)
check_target(${ABSL_CCTZ_TARGET})
## check targets
if(BUILD_TESTING)
......
......@@ -17,13 +17,6 @@ http_archive(
strip_prefix = "googletest-master",
)
# CCTZ (Time-zone framework).
http_archive(
name = "com_googlesource_code_cctz",
urls = ["https://github.com/google/cctz/archive/master.zip"],
strip_prefix = "cctz-master",
)
# RE2 regular-expression framework. Used by some unit-tests.
http_archive(
name = "com_googlesource_code_re2",
......
......@@ -384,7 +384,7 @@
// ABSL_HAVE_STD_VARIANT
//
// Checks whether C++17 std::optional is available.
// Checks whether C++17 std::variant is available.
#ifdef ABSL_HAVE_STD_VARIANT
#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
#endif
......
......@@ -206,6 +206,8 @@ struct Mallocator {
typedef Mallocator<U> other;
};
Mallocator() = default;
template <class U>
Mallocator(const Mallocator<U>&) {} // NOLINT(runtime/explicit)
T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); }
void deallocate(T* p, size_t) { std::free(p); }
......
......@@ -50,6 +50,8 @@ struct Mallocator {
typedef Mallocator<U> other;
};
Mallocator() = default;
template <class U>
Mallocator(const Mallocator<U>&) {} // NOLINT(runtime/explicit)
T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); }
void deallocate(T* p, size_t) { std::free(p); }
......
......@@ -44,8 +44,8 @@ cc_library(
"//absl/base",
"//absl/base:core_headers",
"//absl/numeric:int128",
"@com_googlesource_code_cctz//:civil_time",
"@com_googlesource_code_cctz//:time_zone",
"//absl/time/internal/cctz:civil_time",
"//absl/time/internal/cctz:time_zone",
],
)
......@@ -63,7 +63,7 @@ cc_library(
deps = [
":time",
"//absl/base",
"@com_googlesource_code_cctz//:time_zone",
"//absl/time/internal/cctz:time_zone",
],
)
......@@ -91,7 +91,7 @@ cc_test(
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/time/internal/cctz:time_zone",
"@com_google_googletest//:gtest_main",
"@com_googlesource_code_cctz//:time_zone",
],
)
......@@ -22,6 +22,10 @@ list(APPEND TIME_PUBLIC_HEADERS
list(APPEND TIME_INTERNAL_HEADERS
"internal/test_util.h"
"internal/cctz/include/cctz/civil_time.h"
"internal/cctz/include/cctz/civil_time_detail.h"
"internal/cctz/include/cctz/time_zone.h"
"internal/cctz/include/cctz/zone_info_source.h"
)
list(APPEND TIME_SRC
......@@ -29,10 +33,27 @@ list(APPEND TIME_SRC
"clock.cc"
"duration.cc"
"format.cc"
"internal/cctz/src/civil_time_detail.cc"
"internal/cctz/src/time_zone_fixed.cc"
"internal/cctz/src/time_zone_fixed.h"
"internal/cctz/src/time_zone_format.cc"
"internal/cctz/src/time_zone_if.cc"
"internal/cctz/src/time_zone_if.h"
"internal/cctz/src/time_zone_impl.cc"
"internal/cctz/src/time_zone_impl.h"
"internal/cctz/src/time_zone_info.cc"
"internal/cctz/src/time_zone_info.h"
"internal/cctz/src/time_zone_libc.cc"
"internal/cctz/src/time_zone_libc.h"
"internal/cctz/src/time_zone_lookup.cc"
"internal/cctz/src/time_zone_posix.cc"
"internal/cctz/src/time_zone_posix.h"
"internal/cctz/src/tzfile.h"
"internal/cctz/src/zone_info_source.cc"
${TIME_PUBLIC_HEADERS}
${TIME_INTERNAL_HEADERS}
)
set(TIME_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::int128 ${ABSL_CCTZ_TARGET})
set(TIME_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::int128)
absl_library(
TARGET
......@@ -41,8 +62,6 @@ absl_library(
${TIME_SRC}
PUBLIC_LIBRARIES
${TIME_PUBLIC_LIBRARIES}
PUBLIC_INCLUDE_DIRS
${CCTZ_INCLUDE_DIRS}
EXPORT_NAME
time
)
......
......@@ -16,8 +16,10 @@
#include <cctype>
#include <cstdint>
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#include "absl/time/time.h"
#include "cctz/time_zone.h"
namespace cctz = absl::time_internal::cctz;
namespace absl {
......
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
licenses(["notice"]) # Apache License
### libraries
cc_library(
name = "includes",
textual_hdrs = [
"include/cctz/civil_time.h",
"include/cctz/civil_time_detail.h",
"include/cctz/time_zone.h",
],
visibility = ["//absl/time:__pkg__"],
)
cc_library(
name = "civil_time",
srcs = ["src/civil_time_detail.cc"],
hdrs = [
"include/cctz/civil_time.h",
],
textual_hdrs = ["include/cctz/civil_time_detail.h"],
visibility = ["//visibility:public"],
)
cc_library(
name = "time_zone",
srcs = [
"src/time_zone_fixed.cc",
"src/time_zone_fixed.h",
"src/time_zone_format.cc",
"src/time_zone_if.cc",
"src/time_zone_if.h",
"src/time_zone_impl.cc",
"src/time_zone_impl.h",
"src/time_zone_info.cc",
"src/time_zone_info.h",
"src/time_zone_libc.cc",
"src/time_zone_libc.h",
"src/time_zone_lookup.cc",
"src/time_zone_posix.cc",
"src/time_zone_posix.h",
"src/tzfile.h",
"src/zone_info_source.cc",
],
hdrs = [
"include/cctz/time_zone.h",
"include/cctz/zone_info_source.h",
],
visibility = ["//visibility:public"],
deps = [":civil_time"],
)
### tests
cc_test(
name = "civil_time_test",
size = "small",
srcs = ["src/civil_time_test.cc"],
deps = [
":civil_time",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "time_zone_format_test",
size = "small",
srcs = ["src/time_zone_format_test.cc"],
deps = [
":civil_time",
":time_zone",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "time_zone_lookup_test",
size = "small",
srcs = ["src/time_zone_lookup_test.cc"],
deps = [
":civil_time",
":time_zone",
"@com_google_googletest//:gtest_main",
],
)
### benchmarks
### examples
### binaries
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
#define ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
#include <cstddef>
#include <functional>
#include <memory>
#include <string>
namespace absl {
namespace time_internal {
namespace cctz {
// A stdio-like interface for providing zoneinfo data for a particular zone.
class ZoneInfoSource {
public:
virtual ~ZoneInfoSource();
virtual std::size_t Read(void* ptr, std::size_t size) = 0; // like fread()
virtual int Skip(std::size_t offset) = 0; // like fseek()
};
} // namespace cctz
} // namespace time_internal
} // namespace absl
namespace absl {
namespace time_internal {
namespace cctz_extension {
// A function-pointer type for a factory that returns a ZoneInfoSource
// given the name of a time zone and a fallback factory. Returns null
// when the data for the named zone cannot be found.
using ZoneInfoSourceFactory =
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> (*)(
const std::string&,
const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
const std::string&)>&);
// The user can control the mapping of zone names to zoneinfo data by
// providing a definition for cctz_extension::zone_info_source_factory.
// For example, given functions my_factory() and my_other_factory() that
// can return a ZoneInfoSource for a named zone, we could inject them into
// cctz::load_time_zone() with:
//
// namespace cctz_extension {
// namespace {
// std::unique_ptr<cctz::ZoneInfoSource> CustomFactory(
// const std::string& name,
// const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
// const std::string& name)>& fallback_factory) {
// if (auto zip = my_factory(name)) return zip;
// if (auto zip = fallback_factory(name)) return zip;
// if (auto zip = my_other_factory(name)) return zip;
// return nullptr;
// }
// } // namespace
// ZoneInfoSourceFactory zone_info_source_factory = CustomFactory;
// } // namespace cctz_extension
//
// This might be used, say, to use zoneinfo data embedded in the program,
// or read from a (possibly compressed) file archive, or both.
//
// cctz_extension::zone_info_source_factory() will be called:
// (1) from the same thread as the cctz::load_time_zone() call,
// (2) only once for any zone name, and
// (3) serially (i.e., no concurrent execution).
//
// The fallback factory obtains zoneinfo data by reading files in ${TZDIR},
// and it is used automatically when no zone_info_source_factory definition
// is linked into the program.
extern ZoneInfoSourceFactory zone_info_source_factory;
} // namespace cctz_extension
} // namespace time_internal
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
#include <iomanip>
#include <ostream>
#include <sstream>
namespace absl {
namespace time_internal {
namespace cctz {
namespace detail {
// Output stream operators output a format matching YYYY-MM-DDThh:mm:ss,
// while omitting fields inferior to the type's alignment. For example,
// civil_day is formatted only as YYYY-MM-DD.
std::ostream& operator<<(std::ostream& os, const civil_year& y) {
std::stringstream ss;
ss << y.year(); // No padding.
return os << ss.str();
}
std::ostream& operator<<(std::ostream& os, const civil_month& m) {
std::stringstream ss;
ss << civil_year(m) << '-';
ss << std::setfill('0') << std::setw(2) << m.month();
return os << ss.str();
}
std::ostream& operator<<(std::ostream& os, const civil_day& d) {
std::stringstream ss;
ss << civil_month(d) << '-';
ss << std::setfill('0') << std::setw(2) << d.day();
return os << ss.str();
}
std::ostream& operator<<(std::ostream& os, const civil_hour& h) {
std::stringstream ss;
ss << civil_day(h) << 'T';
ss << std::setfill('0') << std::setw(2) << h.hour();
return os << ss.str();
}
std::ostream& operator<<(std::ostream& os, const civil_minute& m) {
std::stringstream ss;
ss << civil_hour(m) << ':';
ss << std::setfill('0') << std::setw(2) << m.minute();
return os << ss.str();
}
std::ostream& operator<<(std::ostream& os, const civil_second& s) {
std::stringstream ss;
ss << civil_minute(s) << ':';
ss << std::setfill('0') << std::setw(2) << s.second();
return os << ss.str();
}
////////////////////////////////////////////////////////////////////////
std::ostream& operator<<(std::ostream& os, weekday wd) {
switch (wd) {
case weekday::monday:
return os << "Monday";
case weekday::tuesday:
return os << "Tuesday";
case weekday::wednesday:
return os << "Wednesday";
case weekday::thursday:
return os << "Thursday";
case weekday::friday:
return os << "Friday";
case weekday::saturday:
return os << "Saturday";
case weekday::sunday:
return os << "Sunday";
}
return os; // Should never get here, but -Wreturn-type may warn without this.
}
} // namespace detail
} // namespace cctz
} // namespace time_internal
} // namespace absl
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "time_zone_fixed.h"
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstring>
#include <string>
namespace absl {
namespace time_internal {
namespace cctz {
namespace {
// The prefix used for the internal names of fixed-offset zones.
const char kFixedOffsetPrefix[] = "Fixed/";
int Parse02d(const char* p) {
static const char kDigits[] = "0123456789";
if (const char* ap = std::strchr(kDigits, *p)) {
int v = static_cast<int>(ap - kDigits);
if (const char* bp = std::strchr(kDigits, *++p)) {
return (v * 10) + static_cast<int>(bp - kDigits);
}
}
return -1;
}
} // namespace
bool FixedOffsetFromName(const std::string& name, sys_seconds* offset) {
if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
*offset = sys_seconds::zero();
return true;
}
const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
const char* const ep = kFixedOffsetPrefix + prefix_len;
if (name.size() != prefix_len + 12) // "<prefix>UTC+99:99:99"
return false;
if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
return false;
const char* np = name.data() + prefix_len;
if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C')
return false;
if (np[0] != '+' && np[0] != '-')
return false;
if (np[3] != ':' || np[6] != ':') // see note below about large offsets
return false;
int hours = Parse02d(np + 1);
if (hours == -1) return false;
int mins = Parse02d(np + 4);
if (mins == -1) return false;
int secs = Parse02d(np + 7);
if (secs == -1) return false;
secs += ((hours * 60) + mins) * 60;
if (secs > 24 * 60 * 60) return false; // outside supported offset range
*offset = sys_seconds(secs * (np[0] == '-' ? -1 : 1)); // "-" means west
return true;
}
std::string FixedOffsetToName(const sys_seconds& offset) {
if (offset == sys_seconds::zero()) return "UTC";
if (offset < std::chrono::hours(-24) || offset > std::chrono::hours(24)) {
// We don't support fixed-offset zones more than 24 hours
// away from UTC to avoid complications in rendering such
// offsets and to (somewhat) limit the total number of zones.
return "UTC";
}
int seconds = static_cast<int>(offset.count());
const char sign = (seconds < 0 ? '-' : '+');
int minutes = seconds / 60;
seconds %= 60;
if (sign == '-') {
if (seconds > 0) {
seconds -= 60;
minutes += 1;
}
seconds = -seconds;
minutes = -minutes;
}
int hours = minutes / 60;
minutes %= 60;
char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-24:00:00")];
snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d",
kFixedOffsetPrefix, sign, hours, minutes, seconds);
return buf;
}
std::string FixedOffsetToAbbr(const sys_seconds& offset) {
std::string abbr = FixedOffsetToName(offset);
const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
const char* const ep = kFixedOffsetPrefix + prefix_len;
if (abbr.size() >= prefix_len) {
if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) {
abbr.erase(0, prefix_len);
if (abbr.size() == 12) { // UTC+99:99:99
abbr.erase(9, 1); // UTC+99:9999
abbr.erase(6, 1); // UTC+999999
if (abbr[8] == '0' && abbr[9] == '0') { // UTC+999900
abbr.erase(8, 2); // UTC+9999
if (abbr[6] == '0' && abbr[7] == '0') { // UTC+9900
abbr.erase(6, 2); // UTC+99
if (abbr[4] == '0') { // UTC+09
abbr.erase(4, 1); // UTC+9
}
}
}
}
}
}
return abbr;
}
} // namespace cctz
} // namespace time_internal
} // namespace absl
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
#include <string>
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
namespace time_internal {
namespace cctz {
// Helper functions for dealing with the names and abbreviations
// of time zones that are a fixed offset (seconds east) from UTC.
// FixedOffsetFromName() extracts the offset from a valid fixed-offset
// name, while FixedOffsetToName() and FixedOffsetToAbbr() generate
// the canonical zone name and abbreviation respectively for the given
// offset.
//
// A fixed-offset name looks like "Fixed/UTC<+-><hours>:<mins>:<secs>".
// Its abbreviation is of the form "UTC(<+->H?H(MM(SS)?)?)?" where the
// optional pieces are omitted when their values are zero. (Note that
// the sign is the opposite of that used in a POSIX TZ specification.)
//
// Note: FixedOffsetFromName() fails on syntax errors or when the parsed
// offset exceeds 24 hours. FixedOffsetToName() and FixedOffsetToAbbr()
// both produce "UTC" when the argument offset exceeds 24 hours.
bool FixedOffsetFromName(const std::string& name, sys_seconds* offset);
std::string FixedOffsetToName(const sys_seconds& offset);
std::string FixedOffsetToAbbr(const sys_seconds& offset);
} // namespace cctz
} // namespace time_internal
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "time_zone_if.h"
#include "time_zone_info.h"
#include "time_zone_libc.h"
namespace absl {
namespace time_internal {
namespace cctz {
std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
// Support "libc:localtime" and "libc:*" to access the legacy
// localtime and UTC support respectively from the C library.
if (name.compare(0, 5, "libc:") == 0) {
return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5)));
}
// Otherwise use the "zoneinfo" implementation by default.
std::unique_ptr<TimeZoneInfo> tz(new TimeZoneInfo);
if (!tz->Load(name)) tz.reset();
return std::unique_ptr<TimeZoneIf>(tz.release());
}
// Defined out-of-line to avoid emitting a weak vtable in all TUs.
TimeZoneIf::~TimeZoneIf() {}
} // namespace cctz
} // namespace time_internal
} // namespace absl
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
#include <chrono>
#include <cstdint>
#include <memory>
#include <string>
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
namespace time_internal {
namespace cctz {
// A simple interface used to hide time-zone complexities from time_zone::Impl.
// Subclasses implement the functions for civil-time conversions in the zone.
class TimeZoneIf {
public:
// A factory function for TimeZoneIf implementations.
static std::unique_ptr<TimeZoneIf> Load(const std::string& name);
virtual ~TimeZoneIf();
virtual time_zone::absolute_lookup BreakTime(
const time_point<sys_seconds>& tp) const = 0;
virtual time_zone::civil_lookup MakeTime(
const civil_second& cs) const = 0;
virtual std::string Description() const = 0;
virtual bool NextTransition(time_point<sys_seconds>* tp) const = 0;
virtual bool PrevTransition(time_point<sys_seconds>* tp) const = 0;
protected:
TimeZoneIf() {}
};
// Convert between time_point<sys_seconds> and a count of seconds since
// the Unix epoch. We assume that the std::chrono::system_clock and the
// Unix clock are second aligned, but not that they share an epoch.
inline std::int_fast64_t ToUnixSeconds(const time_point<sys_seconds>& tp) {
return (tp - std::chrono::time_point_cast<sys_seconds>(
std::chrono::system_clock::from_time_t(0)))
.count();
}
inline time_point<sys_seconds> FromUnixSeconds(std::int_fast64_t t) {
return std::chrono::time_point_cast<sys_seconds>(
std::chrono::system_clock::from_time_t(0)) +
sys_seconds(t);
}
} // namespace cctz
} // namespace time_internal
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "time_zone_impl.h"
#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include "time_zone_fixed.h"
namespace absl {
namespace time_internal {
namespace cctz {
namespace {
// time_zone::Impls are linked into a map to support fast lookup by name.
using TimeZoneImplByName =
std::unordered_map<std::string, const time_zone::Impl*>;
TimeZoneImplByName* time_zone_map = nullptr;
// Mutual exclusion for time_zone_map.
std::mutex time_zone_mutex;
} // namespace
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();
// First check for UTC (which is never a key in time_zone_map).
auto offset = sys_seconds::zero();
if (FixedOffsetFromName(name, &offset) && offset == sys_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.
{
std::lock_guard<std::mutex> lock(time_zone_mutex);
if (time_zone_map != nullptr) {
TimeZoneImplByName::const_iterator itr = time_zone_map->find(name);
if (itr != time_zone_map->end()) {
*tz = time_zone(itr->second);
return itr->second != utc_impl;
}
}
}
// Now check again, under an exclusive lock.
std::lock_guard<std::mutex> lock(time_zone_mutex);
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
}
}
*tz = time_zone(impl);
return impl != utc_impl;
}
const time_zone::Impl& time_zone::Impl::get(const time_zone& tz) {
if (tz.impl_ == nullptr) {
// Dereferencing an implicit-UTC time_zone is expected to be
// rare, so we don't mind paying a small synchronization cost.
return *UTCImpl();
}
return *tz.impl_;
}
void time_zone::Impl::ClearTimeZoneMapTestOnly() {
std::lock_guard<std::mutex> lock(time_zone_mutex);
if (time_zone_map != nullptr) {
// Existing time_zone::Impl* entries are in the wild, so we simply
// leak them. Future requests will result in reloading the data.
time_zone_map->clear();
}
}
time_zone::Impl::Impl(const std::string& name) : name_(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;
}();
return utc_impl;
}
} // namespace cctz
} // namespace time_internal
} // namespace absl
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
#include <memory>
#include <string>
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#include "time_zone_if.h"
#include "time_zone_info.h"
namespace absl {
namespace time_internal {
namespace cctz {
// time_zone::Impl is the internal object referenced by a cctz::time_zone.
class time_zone::Impl {
public:
// The UTC time zone. Also used for other time zones that fail to load.
static time_zone UTC();
// Load a named time zone. Returns false if the name is invalid, or if
// some other kind of error occurs. Note that loading "UTC" never fails.
static bool LoadTimeZone(const std::string& name, time_zone* tz);
// Dereferences the time_zone to obtain its Impl.
static const time_zone::Impl& get(const time_zone& tz);
// Clears the map of cached time zones. Primarily for use in benchmarks
// that gauge the performance of loading/parsing the time-zone data.
static void ClearTimeZoneMapTestOnly();
// The primary key is the time-zone ID (e.g., "America/New_York").
const std::string& name() const { return name_; }
// Breaks a time_point down to civil-time components in this time zone.
time_zone::absolute_lookup BreakTime(
const time_point<sys_seconds>& tp) const {
return zone_->BreakTime(tp);
}
// Converts the civil-time components in this time zone into a time_point.
// That is, the opposite of BreakTime(). The requested civil time may be
// ambiguous or illegal due to a change of UTC offset.
time_zone::civil_lookup MakeTime(const civil_second& cs) const {
return zone_->MakeTime(cs);
}
// Returns an implementation-specific description of this time zone.
std::string Description() const { return zone_->Description(); }
// Finds the time of the next/previous offset change in this time zone.
//
// By definition, NextTransition(&tp) returns false when tp has its
// maximum value, and PrevTransition(&tp) returns false when tp has its
// mimimum value. If the zone has no transitions, the result will also
// be false no matter what the argument.
//
// Otherwise, when tp has its mimimum value, NextTransition(&tp) returns
// true and sets tp to the first recorded transition. Chains of calls
// to NextTransition()/PrevTransition() will eventually return false,
// but it is unspecified exactly when NextTransition(&tp) jumps to false,
// or what time is set by PrevTransition(&tp) for a very distant tp.
bool NextTransition(time_point<sys_seconds>* tp) const {
return zone_->NextTransition(tp);
}
bool PrevTransition(time_point<sys_seconds>* tp) const {
return zone_->PrevTransition(tp);
}
private:
explicit Impl(const std::string& name);
static const Impl* UTCImpl();
const std::string name_;
std::unique_ptr<TimeZoneIf> zone_;
};
} // namespace cctz
} // namespace time_internal
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
#include "time_zone_if.h"
#include "tzfile.h"
namespace absl {
namespace time_internal {
namespace cctz {
// A transition to a new UTC offset.
struct Transition {
std::int_least64_t unix_time; // the instant of this transition
std::uint_least8_t type_index; // index of the transition type
civil_second civil_sec; // local civil time of transition
civil_second prev_civil_sec; // local civil time one second earlier
struct ByUnixTime {
inline bool operator()(const Transition& lhs, const Transition& rhs) const {
return lhs.unix_time < rhs.unix_time;
}
};
struct ByCivilTime {
inline bool operator()(const Transition& lhs, const Transition& rhs) const {
return lhs.civil_sec < rhs.civil_sec;
}
};
};
// The characteristics of a particular transition.
struct TransitionType {
std::int_least32_t utc_offset; // the new prevailing UTC offset
civil_second civil_max; // max convertible civil time for offset
civil_second civil_min; // min convertible civil time for offset
bool is_dst; // did we move into daylight-saving time
std::uint_least8_t abbr_index; // index of the new abbreviation
};
// A time zone backed by the IANA Time Zone Database (zoneinfo).
class TimeZoneInfo : public TimeZoneIf {
public:
TimeZoneInfo() = default;
TimeZoneInfo(const TimeZoneInfo&) = delete;
TimeZoneInfo& operator=(const TimeZoneInfo&) = delete;
// Loads the zoneinfo for the given name, returning true if successful.
bool Load(const std::string& name);
// TimeZoneIf implementations.
time_zone::absolute_lookup BreakTime(
const time_point<sys_seconds>& tp) const override;
time_zone::civil_lookup MakeTime(
const civil_second& cs) const override;
std::string Description() const override;
bool NextTransition(time_point<sys_seconds>* tp) const override;
bool PrevTransition(time_point<sys_seconds>* tp) const override;
private:
struct Header { // counts of:
std::size_t timecnt; // transition times
std::size_t typecnt; // transition types
std::size_t charcnt; // zone abbreviation characters
std::size_t leapcnt; // leap seconds (we expect none)
std::size_t ttisstdcnt; // UTC/local indicators (unused)
std::size_t ttisgmtcnt; // standard/wall indicators (unused)
bool Build(const tzhead& tzh);
std::size_t DataLength(std::size_t time_len) const;
};
void CheckTransition(const std::string& name, const TransitionType& tt,
std::int_fast32_t offset, bool is_dst,
const std::string& abbr) const;
bool EquivTransitions(std::uint_fast8_t tt1_index,
std::uint_fast8_t tt2_index) const;
void ExtendTransitions(const std::string& name, const Header& hdr);
bool ResetToBuiltinUTC(const sys_seconds& offset);
bool Load(const std::string& name, ZoneInfoSource* zip);
// Helpers for BreakTime() and MakeTime().
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
const TransitionType& tt) const;
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
const Transition& tr) const;
time_zone::civil_lookup TimeLocal(const civil_second& cs,
year_t c4_shift) const;
std::vector<Transition> transitions_; // ordered by unix_time and civil_sec
std::vector<TransitionType> transition_types_; // distinct transition types
std::uint_fast8_t default_transition_type_; // for before first transition
std::string abbreviations_; // all the NUL-terminated abbreviations
std::string future_spec_; // for after the last zic transition
bool extended_; // future_spec_ was used to generate transitions
year_t last_year_; // the final year of the generated transitions
// We remember the transitions found during the last BreakTime() and
// MakeTime() calls. If the next request is for the same transition we
// will avoid re-searching.
mutable std::atomic<std::size_t> local_time_hint_ = {}; // BreakTime() hint
mutable std::atomic<std::size_t> time_local_hint_ = {}; // MakeTime() hint
};
} // namespace cctz
} // namespace time_internal
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#if defined(_WIN32) || defined(_WIN64)
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include "time_zone_libc.h"
#include <chrono>
#include <ctime>
#include <tuple>
#include <utility>
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
namespace time_internal {
namespace cctz {
namespace {
// .first is seconds east of UTC; .second is the time-zone abbreviation.
using OffsetAbbr = std::pair<int, const char*>;
// Defines a function that can be called as follows:
//
// std::tm tm = ...;
// OffsetAbbr off_abbr = get_offset_abbr(tm);
//
#if defined(_WIN32) || defined(_WIN64)
// Uses the globals: '_timezone', '_dstbias' and '_tzname'.
OffsetAbbr get_offset_abbr(const std::tm& tm) {
const bool is_dst = tm.tm_isdst > 0;
const int off = _timezone + (is_dst ? _dstbias : 0);
const char* abbr = _tzname[is_dst];
return {off, abbr};
}
#elif defined(__sun)
// Uses the globals: 'timezone', 'altzone' and 'tzname'.
OffsetAbbr get_offset_abbr(const std::tm& tm) {
const bool is_dst = tm.tm_isdst > 0;
const int off = is_dst ? altzone : timezone;
const char* abbr = tzname[is_dst];
return {off, abbr};
}
#elif defined(__native_client__) || defined(__myriad2__) || \
defined(__EMSCRIPTEN__)
// Uses the globals: 'timezone' and 'tzname'.
OffsetAbbr get_offset_abbr(const std::tm& tm) {
const bool is_dst = tm.tm_isdst > 0;
const int off = _timezone + (is_dst ? 60 * 60 : 0);
const char* abbr = tzname[is_dst];
return {off, abbr};
}
#else
//
// Returns an OffsetAbbr using std::tm fields with various spellings.
//
#if !defined(tm_gmtoff) && !defined(tm_zone)
template <typename T>
OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::tm_gmtoff) = nullptr,
decltype(&T::tm_zone) = nullptr) {
return {tm.tm_gmtoff, tm.tm_zone};
}
#endif // !defined(tm_gmtoff) && !defined(tm_zone)
#if !defined(__tm_gmtoff) && !defined(__tm_zone)
template <typename T>
OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr,
decltype(&T::__tm_zone) = nullptr) {
return {tm.__tm_gmtoff, tm.__tm_zone};
}
#endif // !defined(__tm_gmtoff) && !defined(__tm_zone)
#endif
} // namespace
TimeZoneLibC::TimeZoneLibC(const std::string& name)
: local_(name == "localtime") {}
time_zone::absolute_lookup TimeZoneLibC::BreakTime(
const time_point<sys_seconds>& tp) const {
time_zone::absolute_lookup al;
std::time_t t = ToUnixSeconds(tp);
std::tm tm;
if (local_) {
#if defined(_WIN32) || defined(_WIN64)
localtime_s(&tm, &t);
#else
localtime_r(&t, &tm);
#endif
std::tie(al.offset, al.abbr) = get_offset_abbr(tm);
} else {
#if defined(_WIN32) || defined(_WIN64)
gmtime_s(&tm, &t);
#else
gmtime_r(&t, &tm);
#endif
al.offset = 0;
al.abbr = "UTC";
}
al.cs = civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
al.is_dst = tm.tm_isdst > 0;
return al;
}
time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
time_zone::civil_lookup cl;
std::time_t t;
if (local_) {
// Does not handle SKIPPED/AMBIGUOUS or huge years.
std::tm tm;
tm.tm_year = static_cast<int>(cs.year() - 1900);
tm.tm_mon = cs.month() - 1;
tm.tm_mday = cs.day();
tm.tm_hour = cs.hour();
tm.tm_min = cs.minute();
tm.tm_sec = cs.second();
tm.tm_isdst = -1;
t = std::mktime(&tm);
} else {
t = cs - civil_second();
}
cl.kind = time_zone::civil_lookup::UNIQUE;
cl.pre = cl.trans = cl.post = FromUnixSeconds(t);
return cl;
}
std::string TimeZoneLibC::Description() const {
return local_ ? "localtime" : "UTC";
}
bool TimeZoneLibC::NextTransition(time_point<sys_seconds>* tp) const {
return false;
}
bool TimeZoneLibC::PrevTransition(time_point<sys_seconds>* tp) const {
return false;
}
} // namespace cctz
} // namespace time_internal
} // namespace absl
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
#include <string>
#include "time_zone_if.h"
namespace absl {
namespace time_internal {
namespace cctz {
// A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3),
// and which therefore only supports UTC and the local time zone.
// TODO: Add support for fixed offsets from UTC.
class TimeZoneLibC : public TimeZoneIf {
public:
explicit TimeZoneLibC(const std::string& name);
// TimeZoneIf implementations.
time_zone::absolute_lookup BreakTime(
const time_point<sys_seconds>& tp) const override;
time_zone::civil_lookup MakeTime(
const civil_second& cs) const override;
std::string Description() const override;
bool NextTransition(time_point<sys_seconds>* tp) const override;
bool PrevTransition(time_point<sys_seconds>* tp) const override;
private:
const bool local_; // localtime or UTC
};
} // namespace cctz
} // namespace time_internal
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#if defined(__ANDROID__)
#include <sys/system_properties.h>
#if __ANDROID_API__ >= 21
#include <dlfcn.h>
#endif
#endif
#include <cstdlib>
#include <cstring>
#include <string>
#include "time_zone_fixed.h"
#include "time_zone_impl.h"
namespace absl {
namespace time_internal {
namespace cctz {
#if defined(__ANDROID__) && __ANDROID_API__ >= 21
namespace {
// Android 'L' removes __system_property_get() from the NDK, however
// it is still a hidden symbol in libc so we use dlsym() to access it.
// See Chromium's base/sys_info_android.cc for a similar example.
using property_get_func = int (*)(const char*, char*);
property_get_func LoadSystemPropertyGet() {
int flag = RTLD_LAZY | RTLD_GLOBAL;
#if defined(RTLD_NOLOAD)
flag |= RTLD_NOLOAD; // libc.so should already be resident
#endif
if (void* handle = dlopen("libc.so", flag)) {
void* sym = dlsym(handle, "__system_property_get");
dlclose(handle);
return reinterpret_cast<property_get_func>(sym);
}
return nullptr;
}
int __system_property_get(const char* name, char* value) {
static property_get_func system_property_get = LoadSystemPropertyGet();
return system_property_get ? system_property_get(name, value) : -1;
}
} // namespace
#endif
std::string time_zone::name() const {
return time_zone::Impl::get(*this).name();
}
time_zone::absolute_lookup time_zone::lookup(
const time_point<sys_seconds>& tp) const {
return time_zone::Impl::get(*this).BreakTime(tp);
}
time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const {
return time_zone::Impl::get(*this).MakeTime(cs);
}
bool operator==(time_zone lhs, time_zone rhs) {
return &time_zone::Impl::get(lhs) == &time_zone::Impl::get(rhs);
}
bool load_time_zone(const std::string& name, time_zone* tz) {
return time_zone::Impl::LoadTimeZone(name, tz);
}
time_zone utc_time_zone() {
return time_zone::Impl::UTC(); // avoid name lookup
}
time_zone fixed_time_zone(const sys_seconds& offset) {
time_zone tz;
load_time_zone(FixedOffsetToName(offset), &tz);
return tz;
}
time_zone local_time_zone() {
const char* zone = ":localtime";
// Allow ${TZ} to override to default zone.
char* tz_env = nullptr;
#if defined(_MSC_VER)
_dupenv_s(&tz_env, nullptr, "TZ");
#else
tz_env = std::getenv("TZ");
#endif
#if defined(__ANDROID__)
char sysprop[PROP_VALUE_MAX];
if (tz_env == nullptr)
if (__system_property_get("persist.sys.timezone", sysprop) > 0)
tz_env = sysprop;
#endif
if (tz_env) zone = tz_env;
// We only support the "[:]<zone-name>" form.
if (*zone == ':') ++zone;
// Map "localtime" to a system-specific name, but
// allow ${LOCALTIME} to override the default name.
char* localtime_env = nullptr;
if (strcmp(zone, "localtime") == 0) {
#if defined(_MSC_VER)
// System-specific default is just "localtime".
_dupenv_s(&localtime_env, nullptr, "LOCALTIME");
#else
zone = "/etc/localtime"; // System-specific default.
localtime_env = std::getenv("LOCALTIME");
#endif
if (localtime_env) zone = localtime_env;
}
const std::string name = zone;
#if defined(_MSC_VER)
free(localtime_env);
free(tz_env);
#endif
time_zone tz;
load_time_zone(name, &tz); // Falls back to UTC.
return tz;
}
} // namespace cctz
} // namespace time_internal
} // namespace absl
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "time_zone_posix.h"
#include <cstddef>
#include <cstring>
#include <limits>
#include <string>
namespace absl {
namespace time_internal {
namespace cctz {
namespace {
const char kDigits[] = "0123456789";
const char* ParseInt(const char* p, int min, int max, int* vp) {
int value = 0;
const char* op = p;
const int kMaxInt = std::numeric_limits<int>::max();
for (; const char* dp = strchr(kDigits, *p); ++p) {
int d = static_cast<int>(dp - kDigits);
if (d >= 10) break; // '\0'
if (value > kMaxInt / 10) return nullptr;
value *= 10;
if (value > kMaxInt - d) return nullptr;
value += d;
}
if (p == op || value < min || value > max) return nullptr;
*vp = value;
return p;
}
// abbr = <.*?> | [^-+,\d]{3,}
const char* ParseAbbr(const char* p, std::string* abbr) {
const char* op = p;
if (*p == '<') { // special zoneinfo <...> form
while (*++p != '>') {
if (*p == '\0') return nullptr;
}
abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1);
return ++p;
}
while (*p != '\0') {
if (strchr("-+,", *p)) break;
if (strchr(kDigits, *p)) break;
++p;
}
if (p - op < 3) return nullptr;
abbr->assign(op, static_cast<std::size_t>(p - op));
return p;
}
// offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value)
const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign,
std::int_fast32_t* offset) {
if (p == nullptr) return nullptr;
if (*p == '+' || *p == '-') {
if (*p++ == '-') sign = -sign;
}
int hours = 0;
int minutes = 0;
int seconds = 0;
p = ParseInt(p, min_hour, max_hour, &hours);
if (p == nullptr) return nullptr;
if (*p == ':') {
p = ParseInt(p + 1, 0, 59, &minutes);
if (p == nullptr) return nullptr;
if (*p == ':') {
p = ParseInt(p + 1, 0, 59, &seconds);
if (p == nullptr) return nullptr;
}
}
*offset = sign * ((((hours * 60) + minutes) * 60) + seconds);
return p;
}
// datetime = ( Jn | n | Mm.w.d ) [ / offset ]
const char* ParseDateTime(const char* p, PosixTransition* res) {
if (p != nullptr && *p == ',') {
if (*++p == 'M') {
int month = 0;
if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
int week = 0;
if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
int weekday = 0;
if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
res->date.fmt = PosixTransition::M;
res->date.m.month = static_cast<int_fast8_t>(month);
res->date.m.week = static_cast<int_fast8_t>(week);
res->date.m.weekday = static_cast<int_fast8_t>(weekday);
}
}
}
} else if (*p == 'J') {
int day = 0;
if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
res->date.fmt = PosixTransition::J;
res->date.j.day = static_cast<int_fast16_t>(day);
}
} else {
int day = 0;
if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
res->date.fmt = PosixTransition::N;
res->date.j.day = static_cast<int_fast16_t>(day);
}
}
}
if (p != nullptr) {
res->time.offset = 2 * 60 * 60; // default offset is 02:00:00
if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
}
return p;
}
} // namespace
// spec = std offset [ dst [ offset ] , datetime , datetime ]
bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
const char* p = spec.c_str();
if (*p == ':') return false;
p = ParseAbbr(p, &res->std_abbr);
p = ParseOffset(p, 0, 24, -1, &res->std_offset);
if (p == nullptr) return false;
if (*p == '\0') return true;
p = ParseAbbr(p, &res->dst_abbr);
if (p == nullptr) return false;
res->dst_offset = res->std_offset + (60 * 60); // default
if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset);
p = ParseDateTime(p, &res->dst_start);
p = ParseDateTime(p, &res->dst_end);
return p != nullptr && *p == '\0';
}
} // namespace cctz
} // namespace time_internal
} // namespace absl
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Parsing of a POSIX zone spec as described in the TZ part of section 8.3 in
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html.
//
// The current POSIX spec for America/Los_Angeles is "PST8PDT,M3.2.0,M11.1.0",
// which would be broken down as ...
//
// PosixTimeZone {
// std_abbr = "PST"
// std_offset = -28800
// dst_abbr = "PDT"
// dst_offset = -25200
// dst_start = PosixTransition {
// date {
// m {
// month = 3
// week = 2
// weekday = 0
// }
// }
// time {
// offset = 7200
// }
// }
// dst_end = PosixTransition {
// date {
// m {
// month = 11
// week = 1
// weekday = 0
// }
// }
// time {
// offset = 7200
// }
// }
// }
#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
#include <cstdint>
#include <string>
namespace absl {
namespace time_internal {
namespace cctz {
// The date/time of the transition. The date is specified as either:
// (J) the Nth day of the year (1 <= N <= 365), excluding leap days, or
// (N) the Nth day of the year (0 <= N <= 365), including leap days, or
// (M) the Nth weekday of a month (e.g., the 2nd Sunday in March).
// The time, specified as a day offset, identifies the particular moment
// of the transition, and may be negative or >= 24h, and in which case
// it would take us to another day, and perhaps week, or even month.
struct PosixTransition {
enum DateFormat { J, N, M };
struct {
DateFormat fmt;
union {
struct {
std::int_fast16_t day; // day of non-leap year [1:365]
} j;
struct {
std::int_fast16_t day; // day of year [0:365]
} n;
struct {
std::int_fast8_t month; // month of year [1:12]
std::int_fast8_t week; // week of month [1:5] (5==last)
std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat
} m;
};
} date;
struct {
std::int_fast32_t offset; // seconds before/after 00:00:00
} time;
};
// The entirety of a POSIX-std::string specified time-zone rule. The standard
// abbreviation and offset are always given. If the time zone includes
// daylight saving, then the daylight abbrevation is non-empty and the
// remaining fields are also valid. Note that the start/end transitions
// are not ordered---in the southern hemisphere the transition to end
// daylight time occurs first in any particular year.
struct PosixTimeZone {
std::string std_abbr;
std::int_fast32_t std_offset;
std::string dst_abbr;
std::int_fast32_t dst_offset;
PosixTransition dst_start;
PosixTransition dst_end;
};
// Breaks down a POSIX time-zone specification into its constituent pieces,
// filling in any missing values (DST offset, or start/end transition times)
// with the standard-defined defaults. Returns false if the specification
// could not be parsed (although some fields of *res may have been altered).
bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res);
} // namespace cctz
} // namespace time_internal
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
#ifndef TZFILE_H
#define TZFILE_H
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
*/
/*
** This header is for use ONLY with the time conversion code.
** There is no guarantee that it will remain unchanged,
** or that it will remain at all.
** Do NOT copy it to any system include directory.
** Thank you!
*/
/*
** Information about time zone files.
*/
#ifndef TZDIR
#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
#endif /* !defined TZDIR */
#ifndef TZDEFAULT
#define TZDEFAULT "/etc/localtime"
#endif /* !defined TZDEFAULT */
#ifndef TZDEFRULES
#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
/*
** Each file begins with. . .
*/
#define TZ_MAGIC "TZif"
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
char tzh_reserved[15]; /* reserved; must be zero */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */
char tzh_typecnt[4]; /* coded number of local time types */
char tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*
** . . .followed by. . .
**
** tzh_timecnt (char [4])s coded transition times a la time(2)
** tzh_timecnt (unsigned char)s types of local time starting at above
** tzh_typecnt repetitions of
** one (char [4]) coded UT offset in seconds
** one (unsigned char) used to set tm_isdst
** one (unsigned char) that's an abbreviation list index
** tzh_charcnt (char)s '\0'-terminated zone abbreviations
** tzh_leapcnt repetitions of
** one (char [4]) coded leap second transition times
** one (char [4]) total correction after above
** tzh_ttisstdcnt (char)s indexed by type; if 1, transition
** time is standard time, if 0,
** transition time is wall clock time
** if absent, transition times are
** assumed to be wall clock time
** tzh_ttisgmtcnt (char)s indexed by type; if 1, transition
** time is UT, if 0,
** transition time is local time
** if absent, transition times are
** assumed to be local time
*/
/*
** If tzh_version is '2' or greater, the above is followed by a second instance
** of tzhead and a second instance of the data in which each coded transition
** time uses 8 rather than 4 chars,
** then a POSIX-TZ-environment-variable-style std::string for use in handling
** instants after the last transition time stored in the file
** (with nothing between the newlines if there is no POSIX representation for
** such instants).
**
** If tz_version is '3' or greater, the above is extended as follows.
** First, the POSIX TZ std::string's hour offset may range from -167
** through 167 as compared to the POSIX-required 0 through 24.
** Second, its DST start time may be January 1 at 00:00 and its stop
** time December 31 at 24:00 plus the difference between DST and
** standard time, indicating DST all year.
*/
/*
** In the current implementation, "tzset()" refuses to deal with files that
** exceed any of the limits below.
*/
#ifndef TZ_MAX_TIMES
#define TZ_MAX_TIMES 2000
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
#endif /* !defined TZ_MAX_TYPES */
#ifndef TZ_MAX_CHARS
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
/* (limited by what unsigned chars can hold) */
#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
#endif /* !defined TZ_MAX_LEAPS */
#endif /* !defined TZFILE_H */
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
namespace absl {
namespace time_internal {
namespace cctz {
// Defined out-of-line to avoid emitting a weak vtable in all TUs.
ZoneInfoSource::~ZoneInfoSource() {}
} // namespace cctz
} // namespace time_internal
} // namespace absl
namespace absl {
namespace time_internal {
namespace cctz_extension {
namespace {
// A default for cctz_extension::zone_info_source_factory, which simply
// defers to the fallback factory.
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
const std::string& name,
const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
const std::string& name)>& fallback_factory) {
return fallback_factory(name);
}
} // namespace
// A "weak" definition for cctz_extension::zone_info_source_factory.
// The user may override this with their own "strong" definition (see
// zone_info_source.h).
#if defined(_MSC_VER)
extern ZoneInfoSourceFactory zone_info_source_factory;
extern ZoneInfoSourceFactory default_factory;
ZoneInfoSourceFactory default_factory = DefaultFactory;
#if defined(_M_IX86)
#pragma comment( \
linker, \
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA")
#elif defined(_M_IA_64) || defined(_M_AMD64)
#pragma comment( \
linker, \
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA")
#else
#error Unsupported MSVC platform
#endif
#else
ZoneInfoSourceFactory zone_info_source_factory
__attribute__((weak)) = DefaultFactory;
#endif // _MSC_VER
} // namespace cctz_extension
} // namespace time_internal
} // namespace absl
testdata/zoneinfo contains time-zone data files that may be used with CCTZ.
Install them in a location referenced by the ${TZDIR} environment variable.
Symbolic and hard links have been eliminated for portability.
On Linux systems the distribution's versions of these files can probably
already be found in the default ${TZDIR} location, /usr/share/zoneinfo.
New versions can be generated using the following shell script.
#!/bin/sh -
set -e
DESTDIR=$(mktemp -d)
trap "rm -fr ${DESTDIR}" 0 2 15
(
cd ${DESTDIR}
git clone https://github.com/eggert/tz.git
make --directory=tz \
install DESTDIR=${DESTDIR} \
DATAFORM=vanguard \
TZDIR=/zoneinfo \
REDO=posix_only \
LOCALTIME=Factory \
TZDATA_TEXT= \
ZONETABLES=zone1970.tab
tar --create --dereference --hard-dereference --file tzfile.tar \
--directory=tz tzfile.h
tar --create --dereference --hard-dereference --file zoneinfo.tar \
--exclude=zoneinfo/posixrules zoneinfo \
--directory=tz version
)
tar --extract --directory src --file ${DESTDIR}/tzfile.tar
tar --extract --directory testdata --file ${DESTDIR}/zoneinfo.tar
exit 0
To run the CCTZ tests using the testdata/zoneinfo files, execute:
bazel test --test_env=TZDIR=${PWD}/testdata/zoneinfo ...
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment