mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-09-18 02:08:09 +08:00
fix: consider timezone correctly
explicitly set tm.tm_isdst = 0 and use UTC offset
This commit is contained in:
@@ -470,37 +470,64 @@ struct offset_datetime
|
|||||||
: date(ld.date), time(ld.time), offset(get_local_offset())
|
: date(ld.date), time(ld.time), offset(get_local_offset())
|
||||||
{}
|
{}
|
||||||
explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
|
explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
|
||||||
: offset_datetime(local_datetime(tp))
|
: offset(0, 0) // use gmtime
|
||||||
{}
|
{
|
||||||
|
const auto timet = std::chrono::system_clock::to_time_t(tp);
|
||||||
|
const auto tm = detail::gmtime_s(&timet);
|
||||||
|
this->date = local_date(tm);
|
||||||
|
this->time = local_time(tm);
|
||||||
|
}
|
||||||
explicit offset_datetime(const std::time_t& t)
|
explicit offset_datetime(const std::time_t& t)
|
||||||
: offset_datetime(local_datetime(t))
|
: offset(0, 0) // use gmtime
|
||||||
{}
|
{
|
||||||
|
const auto tm = detail::gmtime_s(&t);
|
||||||
|
this->date = local_date(tm);
|
||||||
|
this->time = local_time(tm);
|
||||||
|
}
|
||||||
explicit offset_datetime(const std::tm& t)
|
explicit offset_datetime(const std::tm& t)
|
||||||
: offset_datetime(local_datetime(t))
|
: offset(0, 0) // assume gmtime
|
||||||
{}
|
{
|
||||||
|
this->date = local_date(t);
|
||||||
|
this->time = local_time(t);
|
||||||
|
}
|
||||||
|
|
||||||
operator std::chrono::system_clock::time_point() const
|
operator std::chrono::system_clock::time_point() const
|
||||||
{
|
{
|
||||||
// get date-time
|
// get date-time
|
||||||
using internal_duration =
|
using internal_duration =
|
||||||
typename std::chrono::system_clock::time_point::duration;
|
typename std::chrono::system_clock::time_point::duration;
|
||||||
|
|
||||||
|
// std::mktime returns date as **local** time zone.
|
||||||
|
std::tm t;
|
||||||
|
t.tm_sec = 0;
|
||||||
|
t.tm_min = 0;
|
||||||
|
t.tm_hour = 0;
|
||||||
|
t.tm_mday = static_cast<int>(this->date.day);
|
||||||
|
t.tm_mon = static_cast<int>(this->date.month);
|
||||||
|
t.tm_year = static_cast<int>(this->date.year) - 1900;
|
||||||
|
t.tm_wday = 0; // the value will be ignored
|
||||||
|
t.tm_yday = 0; // the value will be ignored
|
||||||
|
t.tm_isdst = 0; // do not consider DST; explicitly turn it off.
|
||||||
|
// all the offset info, including DST, should be in the offset part.
|
||||||
|
|
||||||
std::chrono::system_clock::time_point tp =
|
std::chrono::system_clock::time_point tp =
|
||||||
std::chrono::system_clock::time_point(this->date) +
|
std::chrono::system_clock::from_time_t(std::mktime(&t)) +
|
||||||
std::chrono::duration_cast<internal_duration>(
|
std::chrono::duration_cast<internal_duration>(
|
||||||
std::chrono::nanoseconds(this->time));
|
std::chrono::nanoseconds(this->time));
|
||||||
|
|
||||||
// get date-time in UTC. let's say we are in +09:00 (JPN).
|
// get date-time in UTC.
|
||||||
// writing 12:00:00 in +09:00 means 03:00:00Z. to represent
|
// Since mktime uses local time zone, it should be corrected.
|
||||||
// 12:00:00Z, first we need to add +09:00.
|
// `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if
|
||||||
|
// we are in `+09:00` timezone. To represent `12:00:00Z` there, we need
|
||||||
|
// to add `+09:00` to `03:00:00Z`.
|
||||||
const auto ofs = get_local_offset();
|
const auto ofs = get_local_offset();
|
||||||
tp += std::chrono::hours (ofs.hour);
|
tp += std::chrono::hours (ofs.hour);
|
||||||
tp += std::chrono::minutes(ofs.minute);
|
tp += std::chrono::minutes(ofs.minute);
|
||||||
|
|
||||||
// here, tp represents 12:00:00 in UTC but we have offset information.
|
// We got `12:00:00Z` by correcting local timezone applied by mktime.
|
||||||
// we need to subtract it. For example, let's say the input is
|
// Then we will apply the offset. Let's say `12:00:00-08:00` is given.
|
||||||
// 12:00:00-08:00. now we have tp = 12:00:00Z as a result of the above
|
// And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`.
|
||||||
// conversion. But the actual time we need to return is 20:00:00Z
|
// So we need to subtract the offset.
|
||||||
// because of -08:00.
|
|
||||||
tp -= std::chrono::minutes(this->offset);
|
tp -= std::chrono::minutes(this->offset);
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user