I am trying to find out if given date is equal to dst transition date or not (either dst is starting or ending on that day). My program is as below
#include "date/tz.h"
#include <chrono>
#include <iostream>
template <class Duration>
bool
is_dst(date::zoned_time<Duration> const& zt)
{
using namespace date;
using namespace std;
using namespace chrono;
auto info = zt.get_info();
std::cout << "TZ Range start: " << info.begin + info.offset << " range end " << info.end + info.offset << std::endl;
auto dst_hours = std::chrono::duration_cast<std::chrono::hours>(info.save);
auto dst_minutes = std::chrono::duration_cast<std::chrono::minutes>(info.save - dst_hours);
return info.save != minutes{0};
}
int
main(int argc, char *argv[])
{
using namespace date;
using namespace std;
using namespace chrono;
std::string tzname = argv[1];
int yy = std::atoi(argv[2]);
int mm = std::atoi(argv[3]);
int dd = std::atoi(argv[4]);
int h = std::atoi(argv[5]);
int m = std::atoi(argv[6]);
// Construct a local_time type from the broken-down time
local_seconds localTime = date::local_days{date::year{yy}/mm/dd} + std::chrono::hours{h} + std::chrono::minutes{m};
auto tz = locate_zone(tzname);
date::zoned_time<std::chrono::seconds> zt{tz, localTime, date::choose::latest};
auto dst_on_off = is_dst(zoned_time<std::chrono::seconds>{tz, zt, date::choose::latest});
cout << "input time :" << localTime << " latest=" << dst_on_off << '\n';
}
Now I have following questions if I execute in following way ./hh_get_utc_dst_offset "Australia/Sydney" 2025 10 05 01 00 TZ Range start: 2025-04-06 02:00:00 range end 2025-10-05 02:00:00 input time :2025-10-05 01:00:00 latest=0
./hh_get_utc_dst_offset "Australia/Sydney" 2025 10 05 03 00 TZ Range start: 2025-10-05 03:00:00 range end 2026-04-05 03:00:00 input time :2025-10-05 03:00:00 latest=1
So as per documentation of sys_info "The begin and end fields indicate that for the associated time_zone and time_point, the offset and abbrev are in effect in the range [begin, end)." What does this exactly mean ?
In first execution where dst is off its printing current range In second execution where dst is on its printing future range
Also if I want to convert info.begin into broken time how can I do it ? I want to compare date given on command line with date received from info.being and info.end.
So as per documentation of sys_info "The begin and end fields indicate that for the associated time_zone and time_point, the offset and abbrev are in effect in the range [begin, end)." What does this exactly mean ?
I believe this is the crux of the question.
The expression [begin, end)
refers to a "half-open" range. The range begins on and includes begin
. But the range does not include end
. The range stops the instant prior to end
.
And this means that the .offset
is not valid at end
and therefore this expression:
info.end + info.offset
is not valid.
A less error-prone way to convert [begin, end)
to local time would be:
auto tz = zt.get_time_zone();
std::cout << "TZ Range start: " << tz->to_local(info.begin)
<< " range end " << tz->to_local(info.end) << std::endl;
Also if I want to convert info.begin into broken time how can I do it ? I want to compare date given on command line with date received from info.being and info.end.
You can break a serial time_point into fields in either UTC fields, or local fields. To decide which, first obtain the serial time_point in either sys_time
or local_time
respectively.
Assuming you want local fields, and showing just for info.begin
:
// First convert the `sys_time` to `local_time`:
auto local_begin = tz->to_local(info.begin);
// local_begin is a datetime
// truncate it to just a date
auto local_begin_date = floor<days>(local_begin);
// Extract the local time of day from the datetime and date
auto local_tod = local_begin - local_begin_date;
// Convert local_begin_date to a {y, m, d} data structure
year_month_day local_ymd{local_begin_date};
// Convert local_tod to a {h, m, s} data structure
hh_mm_ss local_hms{local_tod};
year_month_day
has .year()
, .month()
and .day()
getters. These return strongly typed representations year
, month
and day
. These in turn can be explicitly cast to int
, unsigned
and unsigned
respectively.
hh_mm_ss
has .hours()
, .minutes()
and .seconds()
getters returning strongly typed representations hours
, minutes
and seconds
. Each of these can be converted to integral types with the .count()
member function.
At each stage, from local_begin
, all the way down to seconds
, each type can be streamed out like so:
cout << local_begin << '\n';
Finally, all of this was voted into C++20 and now lives in namespace std::chrono
and the header <chrono>
. It has been fully implemented in the latest versions of gcc and MSVC. LLVM implementation is underway.
I encourage porting to C++20 whenever possible.