mirror of
https://github.com/HowardHinnant/date.git
synced 2024-12-27 00:14:07 +08:00
Add support for the zic-compiled OS-supplied time zone DB:
* Avoids the need to download the IANA database. * Heavily based on contributions by Aaron Bishop. * Turn on with -DUSE_OS_TZDB, off by default. * Not supported on Windows. * Disables HAS_REMOTE_API. * get_tzdb().version only supported on Apple. This string has the value "unknown" elsewhere. * Leap second support is missing on Apple, and may not be on your platform either (please report). Leap second support is enabled, disabled with -DMISSING_LEAP_SECONDS. Without leap second support, utc_time, tai_time, and gps_time (and those clocks) are not available. * On Apple, time zone transitions are only supported in the range: 1901-12-13 20:45:52 to 2038-01-19 03:14:07 * On Linux, time zone transitions are only as far in the future as the OS-provided transitions go. There is no support for POSIX- style transitions.
This commit is contained in:
parent
5132385454
commit
a610f087c1
@ -89,12 +89,18 @@ tzmain()
|
||||
using namespace std::chrono;
|
||||
auto& db = get_tzdb();
|
||||
std::vector<std::string> names;
|
||||
#if USE_OS_TZDB
|
||||
names.reserve(db.zones.size());
|
||||
for (auto& zone : db.zones)
|
||||
names.push_back(zone.name());
|
||||
#else // !USE_OS_TZDB
|
||||
names.reserve(db.zones.size() + db.links.size());
|
||||
for (auto& zone : db.zones)
|
||||
names.push_back(zone.name());
|
||||
for (auto& link : db.links)
|
||||
names.push_back(link.name());
|
||||
std::sort(names.begin(), names.end());
|
||||
#endif // !USE_OS_TZDB
|
||||
std::cout << db.version << "\n\n";
|
||||
for (auto const& name : names)
|
||||
{
|
||||
|
121
tz.h
121
tz.h
@ -5,6 +5,7 @@
|
||||
//
|
||||
// Copyright (c) 2015, 2016, 2017 Howard Hinnant
|
||||
// Copyright (c) 2017 Jiangang Zhuang
|
||||
// Copyright (c) 2017 Aaron Bishop
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@ -41,14 +42,25 @@
|
||||
// required. On Windows, the names are never "Standard" so mapping is always required.
|
||||
// Technically any OS may use the mapping process but currently only Windows does use it.
|
||||
|
||||
#ifndef USE_OS_TZDB
|
||||
# define USE_OS_TZDB 0
|
||||
#endif
|
||||
|
||||
#ifndef HAS_REMOTE_API
|
||||
# ifdef _WIN32
|
||||
# if USE_OS_TZDB == 0
|
||||
# ifdef _WIN32
|
||||
# define HAS_REMOTE_API 0
|
||||
# else
|
||||
# define HAS_REMOTE_API 1
|
||||
# endif
|
||||
# else // HAS_REMOTE_API makes no since when using the OS timezone database
|
||||
# define HAS_REMOTE_API 0
|
||||
# else
|
||||
# define HAS_REMOTE_API 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static_assert(!(USE_OS_TZDB && HAS_REMOTE_API),
|
||||
"USE_OS_TZDB and HAS_REMOTE_API can not be used together");
|
||||
|
||||
#ifndef AUTO_DOWNLOAD
|
||||
# define AUTO_DOWNLOAD HAS_REMOTE_API
|
||||
#endif
|
||||
@ -60,6 +72,19 @@ static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true,
|
||||
# define USE_SHELL_API 1
|
||||
#endif
|
||||
|
||||
#if USE_OS_TZDB
|
||||
# ifdef _WIN32
|
||||
# error "USE_OS_TZDB can not be used on Windows"
|
||||
# endif
|
||||
# ifndef MISSING_LEAP_SECONDS
|
||||
# ifdef __APPLE__
|
||||
# define MISSING_LEAP_SECONDS 1
|
||||
# else
|
||||
# define MISSING_LEAP_SECONDS 0
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "date.h"
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||
@ -198,8 +223,6 @@ ambiguous_local_time::make_msg(local_time<Duration> tp,
|
||||
return os.str();
|
||||
}
|
||||
|
||||
namespace detail { class Rule; }
|
||||
|
||||
struct sys_info
|
||||
{
|
||||
sys_seconds begin;
|
||||
@ -331,16 +354,31 @@ operator!=(const zoned_time<Duration1>& x, const zoned_time<Duration2>& y)
|
||||
}
|
||||
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||
namespace detail { struct zonelet; }
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
# if USE_OS_TZDB
|
||||
struct transition;
|
||||
struct expanded_ttinfo;
|
||||
# else // !USE_OS_TZDB
|
||||
struct zonelet;
|
||||
class Rule;
|
||||
# endif // !USE_OS_TZDB
|
||||
}
|
||||
|
||||
#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||
|
||||
class time_zone
|
||||
{
|
||||
private:
|
||||
|
||||
std::string name_;
|
||||
std::vector<detail::zonelet> zonelets_;
|
||||
std::unique_ptr<std::once_flag> adjusted_;
|
||||
std::string name_;
|
||||
#if USE_OS_TZDB
|
||||
std::vector<detail::transition> transitions_;
|
||||
std::vector<detail::expanded_ttinfo> ttinfos_;
|
||||
#else // !USE_OS_TZDB
|
||||
std::vector<detail::zonelet> zonelets_;
|
||||
#endif // !USE_OS_TZDB
|
||||
std::unique_ptr<std::once_flag> adjusted_;
|
||||
|
||||
public:
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||
@ -374,15 +412,13 @@ public:
|
||||
friend bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT;
|
||||
friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone& z);
|
||||
|
||||
#if !USE_OS_TZDB
|
||||
DATE_API void add(const std::string& s);
|
||||
DATE_API void adjust_infos(const std::vector<detail::Rule>& rules);
|
||||
#endif // !USE_OS_TZDB
|
||||
|
||||
private:
|
||||
DATE_API sys_info get_info_impl(sys_seconds tp) const;
|
||||
DATE_API local_info get_info_impl(local_seconds tp) const;
|
||||
DATE_API sys_info get_info_impl(sys_seconds tp, int timezone) const;
|
||||
|
||||
void parse_info(std::istream& in);
|
||||
|
||||
template <class Duration>
|
||||
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
||||
@ -390,6 +426,22 @@ private:
|
||||
template <class Duration>
|
||||
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
||||
to_sys_impl(local_time<Duration> tp, choose, std::true_type) const;
|
||||
|
||||
#if USE_OS_TZDB
|
||||
DATE_API void init() const;
|
||||
DATE_API void init_impl();
|
||||
DATE_API sys_info
|
||||
load_sys_info(std::vector<detail::transition>::const_iterator i) const;
|
||||
|
||||
template <class TimeType>
|
||||
DATE_API void
|
||||
load_data(std::istream& inf, std::int32_t tzh_leapcnt, std::int32_t tzh_timecnt,
|
||||
std::int32_t tzh_typecnt, std::int32_t tzh_charcnt);
|
||||
#else // !USE_OS_TZDB
|
||||
DATE_API sys_info get_info_impl(sys_seconds tp, int timezone) const;
|
||||
DATE_API void adjust_infos(const std::vector<detail::Rule>& rules);
|
||||
DATE_API void parse_info(std::istream& in);
|
||||
#endif // !USE_OS_TZDB
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||
@ -515,6 +567,8 @@ time_zone::to_sys_impl(local_time<Duration> tp, choose, std::true_type) const
|
||||
return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
|
||||
}
|
||||
|
||||
#if !USE_OS_TZDB
|
||||
|
||||
class link
|
||||
{
|
||||
private:
|
||||
@ -537,13 +591,21 @@ inline bool operator> (const link& x, const link& y) {return y < x;}
|
||||
inline bool operator<=(const link& x, const link& y) {return !(y < x);}
|
||||
inline bool operator>=(const link& x, const link& y) {return !(x < y);}
|
||||
|
||||
#endif // !USE_OS_TZDB
|
||||
|
||||
#if !MISSING_LEAP_SECONDS
|
||||
|
||||
class leap
|
||||
{
|
||||
private:
|
||||
sys_seconds date_;
|
||||
|
||||
public:
|
||||
#if USE_OS_TZDB
|
||||
DATE_API explicit leap(const sys_seconds& s, detail::undocumented);
|
||||
#else
|
||||
DATE_API explicit leap(const std::string& s, detail::undocumented);
|
||||
#endif
|
||||
|
||||
sys_seconds date() const {return date_;}
|
||||
|
||||
@ -654,6 +716,8 @@ operator>=(const sys_time<Duration>& x, const leap& y)
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
#endif // !MISSING_LEAP_SECONDS
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace detail
|
||||
@ -694,11 +758,17 @@ struct timezone_mapping
|
||||
|
||||
struct TZ_DB
|
||||
{
|
||||
std::string version;
|
||||
std::string version = "unknown";
|
||||
std::vector<time_zone> zones;
|
||||
#if !USE_OS_TZDB
|
||||
std::vector<link> links;
|
||||
#endif
|
||||
#if !MISSING_LEAP_SECONDS
|
||||
std::vector<leap> leaps;
|
||||
#endif
|
||||
#if !USE_OS_TZDB
|
||||
std::vector<detail::Rule> rules;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
std::vector<detail::timezone_mapping> mappings;
|
||||
#endif
|
||||
@ -707,16 +777,14 @@ struct TZ_DB
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||
TZ_DB(TZ_DB&&) = default;
|
||||
TZ_DB& operator=(TZ_DB&&) = default;
|
||||
#else // defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||
#else // defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||
TZ_DB(TZ_DB&& src)
|
||||
: version(std::move(src.version))
|
||||
, zones(std::move(src.zones))
|
||||
, links(std::move(src.links))
|
||||
, leaps(std::move(src.leaps))
|
||||
, rules(std::move(src.rules))
|
||||
#ifdef _WIN32
|
||||
, mappings(std::move(src.mappings))
|
||||
#endif
|
||||
{}
|
||||
|
||||
TZ_DB& operator=(TZ_DB&& src)
|
||||
@ -726,25 +794,30 @@ struct TZ_DB
|
||||
links = std::move(src.links);
|
||||
leaps = std::move(src.leaps);
|
||||
rules = std::move(src.rules);
|
||||
#ifdef _WIN32
|
||||
mappings = std::move(src.mappings);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||
};
|
||||
|
||||
DATE_API std::ostream&
|
||||
operator<<(std::ostream& os, const TZ_DB& db);
|
||||
|
||||
DATE_API const TZ_DB& get_tzdb();
|
||||
|
||||
#if !USE_OS_TZDB
|
||||
|
||||
DATE_API const TZ_DB& reload_tzdb();
|
||||
DATE_API void set_install(const std::string& install);
|
||||
|
||||
#endif // !USE_OS_TZDB
|
||||
|
||||
#if HAS_REMOTE_API
|
||||
|
||||
DATE_API std::string remote_version();
|
||||
DATE_API bool remote_download(const std::string& version);
|
||||
DATE_API bool remote_install(const std::string& version);
|
||||
|
||||
#endif
|
||||
|
||||
DATE_API const time_zone* locate_zone(const std::string& tz_name);
|
||||
@ -1050,6 +1123,8 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const zoned_time<Duration>& t)
|
||||
return os;
|
||||
}
|
||||
|
||||
#if !MISSING_LEAP_SECONDS
|
||||
|
||||
class utc_clock
|
||||
{
|
||||
public:
|
||||
@ -1441,6 +1516,8 @@ to_gps_time(const tai_time<Duration>& t) NOEXCEPT
|
||||
(sys_days(year{1980}/jan/sun[1]) - sys_days(year{1958}/jan/1) + seconds{19});
|
||||
}
|
||||
|
||||
#endif // !MISSING_LEAP_SECONDS
|
||||
|
||||
} // namespace date
|
||||
|
||||
#endif // TZ_H
|
||||
|
52
tz_private.h
52
tz_private.h
@ -40,6 +40,8 @@ namespace date
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if !USE_OS_TZDB
|
||||
|
||||
enum class tz {utc, local, standard};
|
||||
|
||||
//forward declare to avoid warnings in gcc 6.2
|
||||
@ -254,6 +256,56 @@ struct zonelet
|
||||
zonelet& operator=(const zonelet&) = delete;
|
||||
};
|
||||
|
||||
#else // USE_OS_TZDB
|
||||
|
||||
struct ttinfo
|
||||
{
|
||||
std::int32_t tt_gmtoff;
|
||||
unsigned char tt_isdst;
|
||||
unsigned char tt_abbrind;
|
||||
unsigned char pad[2];
|
||||
};
|
||||
|
||||
static_assert(sizeof(ttinfo) == 8, "");
|
||||
|
||||
struct expanded_ttinfo
|
||||
{
|
||||
std::chrono::seconds offset;
|
||||
std::string abbrev;
|
||||
bool is_dst;
|
||||
};
|
||||
|
||||
struct transition
|
||||
{
|
||||
sys_seconds timepoint;
|
||||
const expanded_ttinfo* info;
|
||||
|
||||
transition(sys_seconds tp, const expanded_ttinfo* i = nullptr)
|
||||
: timepoint(tp)
|
||||
, info(i)
|
||||
{}
|
||||
|
||||
friend
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const transition& t)
|
||||
{
|
||||
using namespace date;
|
||||
using namespace std::chrono;
|
||||
os << t.timepoint << "Z ";
|
||||
if (t.info->offset >= seconds{0})
|
||||
os << '+';
|
||||
os << make_time(t.info->offset);
|
||||
if (t.info->is_dst > 0)
|
||||
os << " daylight ";
|
||||
else
|
||||
os << " standard ";
|
||||
os << t.info->abbrev;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // USE_OS_TZDB
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace date
|
||||
|
Loading…
x
Reference in New Issue
Block a user