mirror of
https://github.com/HowardHinnant/date.git
synced 2024-12-27 08:31:03 +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;
|
using namespace std::chrono;
|
||||||
auto& db = get_tzdb();
|
auto& db = get_tzdb();
|
||||||
std::vector<std::string> names;
|
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());
|
names.reserve(db.zones.size() + db.links.size());
|
||||||
for (auto& zone : db.zones)
|
for (auto& zone : db.zones)
|
||||||
names.push_back(zone.name());
|
names.push_back(zone.name());
|
||||||
for (auto& link : db.links)
|
for (auto& link : db.links)
|
||||||
names.push_back(link.name());
|
names.push_back(link.name());
|
||||||
std::sort(names.begin(), names.end());
|
std::sort(names.begin(), names.end());
|
||||||
|
#endif // !USE_OS_TZDB
|
||||||
std::cout << db.version << "\n\n";
|
std::cout << db.version << "\n\n";
|
||||||
for (auto const& name : names)
|
for (auto const& name : names)
|
||||||
{
|
{
|
||||||
|
121
tz.h
121
tz.h
@ -5,6 +5,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) 2015, 2016, 2017 Howard Hinnant
|
// Copyright (c) 2015, 2016, 2017 Howard Hinnant
|
||||||
// Copyright (c) 2017 Jiangang Zhuang
|
// Copyright (c) 2017 Jiangang Zhuang
|
||||||
|
// Copyright (c) 2017 Aaron Bishop
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// 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.
|
// 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.
|
// 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
|
#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
|
# define HAS_REMOTE_API 0
|
||||||
# else
|
|
||||||
# define HAS_REMOTE_API 1
|
|
||||||
# endif
|
# endif
|
||||||
#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
|
#ifndef AUTO_DOWNLOAD
|
||||||
# define AUTO_DOWNLOAD HAS_REMOTE_API
|
# define AUTO_DOWNLOAD HAS_REMOTE_API
|
||||||
#endif
|
#endif
|
||||||
@ -60,6 +72,19 @@ static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true,
|
|||||||
# define USE_SHELL_API 1
|
# define USE_SHELL_API 1
|
||||||
#endif
|
#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"
|
#include "date.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||||
@ -198,8 +223,6 @@ ambiguous_local_time::make_msg(local_time<Duration> tp,
|
|||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail { class Rule; }
|
|
||||||
|
|
||||||
struct sys_info
|
struct sys_info
|
||||||
{
|
{
|
||||||
sys_seconds begin;
|
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)
|
#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
|
class time_zone
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
std::string name_;
|
||||||
std::string name_;
|
#if USE_OS_TZDB
|
||||||
std::vector<detail::zonelet> zonelets_;
|
std::vector<detail::transition> transitions_;
|
||||||
std::unique_ptr<std::once_flag> adjusted_;
|
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:
|
public:
|
||||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
#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 bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT;
|
||||||
friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone& z);
|
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 add(const std::string& s);
|
||||||
DATE_API void adjust_infos(const std::vector<detail::Rule>& rules);
|
#endif // !USE_OS_TZDB
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DATE_API sys_info get_info_impl(sys_seconds tp) const;
|
DATE_API sys_info get_info_impl(sys_seconds tp) const;
|
||||||
DATE_API local_info get_info_impl(local_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>
|
template <class Duration>
|
||||||
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
||||||
@ -390,6 +426,22 @@ private:
|
|||||||
template <class Duration>
|
template <class Duration>
|
||||||
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
||||||
to_sys_impl(local_time<Duration> tp, choose, std::true_type) const;
|
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)
|
#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;
|
return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !USE_OS_TZDB
|
||||||
|
|
||||||
class link
|
class link
|
||||||
{
|
{
|
||||||
private:
|
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 !(y < x);}
|
||||||
inline bool operator>=(const link& x, const link& y) {return !(x < y);}
|
inline bool operator>=(const link& x, const link& y) {return !(x < y);}
|
||||||
|
|
||||||
|
#endif // !USE_OS_TZDB
|
||||||
|
|
||||||
|
#if !MISSING_LEAP_SECONDS
|
||||||
|
|
||||||
class leap
|
class leap
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
sys_seconds date_;
|
sys_seconds date_;
|
||||||
|
|
||||||
public:
|
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);
|
DATE_API explicit leap(const std::string& s, detail::undocumented);
|
||||||
|
#endif
|
||||||
|
|
||||||
sys_seconds date() const {return date_;}
|
sys_seconds date() const {return date_;}
|
||||||
|
|
||||||
@ -654,6 +716,8 @@ operator>=(const sys_time<Duration>& x, const leap& y)
|
|||||||
return !(x < y);
|
return !(x < y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !MISSING_LEAP_SECONDS
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
@ -694,11 +758,17 @@ struct timezone_mapping
|
|||||||
|
|
||||||
struct TZ_DB
|
struct TZ_DB
|
||||||
{
|
{
|
||||||
std::string version;
|
std::string version = "unknown";
|
||||||
std::vector<time_zone> zones;
|
std::vector<time_zone> zones;
|
||||||
|
#if !USE_OS_TZDB
|
||||||
std::vector<link> links;
|
std::vector<link> links;
|
||||||
|
#endif
|
||||||
|
#if !MISSING_LEAP_SECONDS
|
||||||
std::vector<leap> leaps;
|
std::vector<leap> leaps;
|
||||||
|
#endif
|
||||||
|
#if !USE_OS_TZDB
|
||||||
std::vector<detail::Rule> rules;
|
std::vector<detail::Rule> rules;
|
||||||
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::vector<detail::timezone_mapping> mappings;
|
std::vector<detail::timezone_mapping> mappings;
|
||||||
#endif
|
#endif
|
||||||
@ -707,16 +777,14 @@ struct TZ_DB
|
|||||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
||||||
TZ_DB(TZ_DB&&) = default;
|
TZ_DB(TZ_DB&&) = default;
|
||||||
TZ_DB& operator=(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)
|
TZ_DB(TZ_DB&& src)
|
||||||
: version(std::move(src.version))
|
: version(std::move(src.version))
|
||||||
, zones(std::move(src.zones))
|
, zones(std::move(src.zones))
|
||||||
, links(std::move(src.links))
|
, links(std::move(src.links))
|
||||||
, leaps(std::move(src.leaps))
|
, leaps(std::move(src.leaps))
|
||||||
, rules(std::move(src.rules))
|
, rules(std::move(src.rules))
|
||||||
#ifdef _WIN32
|
|
||||||
, mappings(std::move(src.mappings))
|
, mappings(std::move(src.mappings))
|
||||||
#endif
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TZ_DB& operator=(TZ_DB&& src)
|
TZ_DB& operator=(TZ_DB&& src)
|
||||||
@ -726,25 +794,30 @@ struct TZ_DB
|
|||||||
links = std::move(src.links);
|
links = std::move(src.links);
|
||||||
leaps = std::move(src.leaps);
|
leaps = std::move(src.leaps);
|
||||||
rules = std::move(src.rules);
|
rules = std::move(src.rules);
|
||||||
#ifdef _WIN32
|
|
||||||
mappings = std::move(src.mappings);
|
mappings = std::move(src.mappings);
|
||||||
#endif
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
#endif // defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||||
};
|
};
|
||||||
|
|
||||||
DATE_API std::ostream&
|
DATE_API std::ostream&
|
||||||
operator<<(std::ostream& os, const TZ_DB& db);
|
operator<<(std::ostream& os, const TZ_DB& db);
|
||||||
|
|
||||||
DATE_API const TZ_DB& get_tzdb();
|
DATE_API const TZ_DB& get_tzdb();
|
||||||
|
|
||||||
|
#if !USE_OS_TZDB
|
||||||
|
|
||||||
DATE_API const TZ_DB& reload_tzdb();
|
DATE_API const TZ_DB& reload_tzdb();
|
||||||
DATE_API void set_install(const std::string& install);
|
DATE_API void set_install(const std::string& install);
|
||||||
|
|
||||||
|
#endif // !USE_OS_TZDB
|
||||||
|
|
||||||
#if HAS_REMOTE_API
|
#if HAS_REMOTE_API
|
||||||
|
|
||||||
DATE_API std::string remote_version();
|
DATE_API std::string remote_version();
|
||||||
DATE_API bool remote_download(const std::string& version);
|
DATE_API bool remote_download(const std::string& version);
|
||||||
DATE_API bool remote_install(const std::string& version);
|
DATE_API bool remote_install(const std::string& version);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DATE_API const time_zone* locate_zone(const std::string& tz_name);
|
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;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !MISSING_LEAP_SECONDS
|
||||||
|
|
||||||
class utc_clock
|
class utc_clock
|
||||||
{
|
{
|
||||||
public:
|
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});
|
(sys_days(year{1980}/jan/sun[1]) - sys_days(year{1958}/jan/1) + seconds{19});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !MISSING_LEAP_SECONDS
|
||||||
|
|
||||||
} // namespace date
|
} // namespace date
|
||||||
|
|
||||||
#endif // TZ_H
|
#endif // TZ_H
|
||||||
|
52
tz_private.h
52
tz_private.h
@ -40,6 +40,8 @@ namespace date
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if !USE_OS_TZDB
|
||||||
|
|
||||||
enum class tz {utc, local, standard};
|
enum class tz {utc, local, standard};
|
||||||
|
|
||||||
//forward declare to avoid warnings in gcc 6.2
|
//forward declare to avoid warnings in gcc 6.2
|
||||||
@ -254,6 +256,56 @@ struct zonelet
|
|||||||
zonelet& operator=(const zonelet&) = delete;
|
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 detail
|
||||||
|
|
||||||
} // namespace date
|
} // namespace date
|
||||||
|
Loading…
x
Reference in New Issue
Block a user