Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -2215,8 +2215,49 @@ namespace chrono {
return hours{_Ret};
}

// [time.zone.info]

// STRUCT sys_info
struct sys_info {
sys_seconds begin;
sys_seconds end;
seconds offset;
minutes save;
string abbrev;
};

// STRUCT local_info
struct local_info {
static constexpr int unique = 0;
static constexpr int nonexistent = 1;
static constexpr int ambiguous = 2;

int result;
sys_info first;
sys_info second;
};

// CLASS nonexistent_local_time
class nonexistent_local_time : public runtime_error {
public:
template <class _Duration>
nonexistent_local_time(const local_time<_Duration>&, const local_info&)
: runtime_error("TRANSITION: work in progress") {}
};

// CLASS ambiguous_local_time
class ambiguous_local_time : public runtime_error {
public:
template <class _Duration>
ambiguous_local_time(const local_time<_Duration>&, const local_info&)
: runtime_error("TRANSITION: work in progress") {}
};

// [time.zone.timezone]

// ENUM CLASS choose
enum class choose { earliest, latest };

// CLASS time_zone
class time_zone {
public:
Expand All @@ -2229,7 +2270,143 @@ namespace chrono {
return _Name;
}

template <class _Duration>
_NODISCARD sys_info get_info(const sys_time<_Duration>& _Sys) const {
return _Get_info(_Sys.time_since_epoch());
}

template <class _Duration>
_NODISCARD local_info get_info(const local_time<_Duration>& _Local) const {
local_info _Info{};
_Info.first = _Get_info(_Local.time_since_epoch());

const sys_seconds _Local_sys{_CHRONO duration_cast<sys_seconds::duration>(_Local.time_since_epoch())};
const auto _Curr_sys = _Local_sys - _Info.first.offset;
if (_Info.first.begin != _Min_seconds && _Curr_sys < _Info.first.begin + days{1}) {
// get previous transition information
_Info.second = get_info(_Info.first.begin - seconds{1});

const auto _Transition = _Info.first.begin;
const auto _Prev_sys = _Local_sys - _Info.second.offset;
if (_Curr_sys >= _Transition) {
if (_Prev_sys < _Transition) {
_Info.result = local_info::ambiguous;
_STD swap(_Info.first, _Info.second);
} else {
_Info.result = local_info::unique;
_Info.second = {};
}
} else {
if (_Prev_sys >= _Transition) {
_Info.result = local_info::nonexistent;
_STD swap(_Info.first, _Info.second);
} else {
_Info.result = local_info::unique;
_Info.first = _STD move(_Info.second);
_Info.second = {};
}
}
} else if (_Info.first.end != _Max_seconds && _Curr_sys > _Info.first.end - days{1}) {
// get next transition information
_Info.second = get_info(_Info.first.end + seconds{1});

const auto _Transition = _Info.first.end;
const auto _Next_sys = _Local_sys - _Info.second.offset;
if (_Curr_sys < _Transition) {
if (_Next_sys >= _Transition) {
_Info.result = local_info::ambiguous;
} else {
_Info.result = local_info::unique;
_Info.second = {};
}
} else {
if (_Next_sys < _Transition) {
_Info.result = local_info::nonexistent;
} else {
_Info.result = local_info::unique;
_Info.first = _STD move(_Info.second);
_Info.second = {};
}
}
} else {
// local time is contained inside of first transition boundaries by at least 1 day
_Info.result = local_info::unique;
_Info.second = {};
}

return _Info;
}

template <class _Duration>
_NODISCARD sys_time<common_type_t<_Duration, seconds>> to_sys(const local_time<_Duration>& _Local) const {
const auto _Info = get_info(_Local);
if (_Info.result == local_info::nonexistent) {
_THROW(nonexistent_local_time(_Local, _Info));
} else if (_Info.result == local_info::ambiguous) {
_THROW(ambiguous_local_time(_Local, _Info));
}

return sys_time<common_type_t<_Duration, seconds>>{_Local.time_since_epoch() - _Info.first.offset};
}

template <class _Duration>
_NODISCARD sys_time<common_type_t<_Duration, seconds>> to_sys(
const local_time<_Duration>& _Local, const choose _Choose) const {
const auto _Info = get_info(_Local);
if (_Info.result == local_info::nonexistent) {
return _Info.first.end;
}

const auto _Offset = (_Info.result == local_info::unique || _Choose == choose::earliest)
? _Info.first.offset
: _Info.second.offset;
return sys_time<common_type_t<_Duration, seconds>>{_Local.time_since_epoch() - _Offset};
}

template <class _Duration>
_NODISCARD local_time<common_type_t<_Duration, seconds>> to_local(const sys_time<_Duration>& _Sys) const {
const auto _Info = get_info(_Sys);
return local_time<common_type_t<_Duration, seconds>>{_Sys.time_since_epoch() + _Info.offset};
}

static constexpr sys_seconds _Min_seconds{sys_days{(year::min)() / January / 1}};
static constexpr sys_seconds _Max_seconds{sys_seconds{sys_days{(year::max)() / December / 32}} - seconds{1}};

private:
template <class _Duration>
_NODISCARD sys_info _Get_info(const _Duration& _Dur) const {
using _Internal_duration = duration<__std_tzdb_epoch_milli, milli>;
const auto _Internal_dur = _CHRONO duration_cast<_Internal_duration>(_Dur);
const unique_ptr<__std_tzdb_sys_info, decltype(&__std_tzdb_delete_sys_info)> _Info{
__std_tzdb_get_sys_info(_Name.c_str(), _Name.length(), _Internal_dur.count()),
&__std_tzdb_delete_sys_info};
if (_Info == nullptr) {
_Xbad_alloc();
} else if (_Info->_Err == __std_tzdb_error::_Win_error) {
_XGetLastError();
} else if (_Info->_Err == __std_tzdb_error::_Icu_error) {
_Xruntime_error("Internal error loading IANA database information");
}

constexpr auto _Min_internal =
_CHRONO duration_cast<_Internal_duration>(_Min_seconds.time_since_epoch()).count();
constexpr auto _Max_internal =
_CHRONO duration_cast<_Internal_duration>(_Max_seconds.time_since_epoch()).count();
const auto _Begin =
_Info->_Begin <= _Min_internal
? _Min_seconds
: sys_seconds{_CHRONO duration_cast<sys_seconds::duration>(_Internal_duration{_Info->_Begin})};
const auto _End =
_Info->_End >= _Max_internal
? _Max_seconds
: sys_seconds{_CHRONO duration_cast<sys_seconds::duration>(_Internal_duration{_Info->_End})};
return {.begin = _Begin,
.end = _End,
.offset = _CHRONO duration_cast<seconds>(_Internal_duration{_Info->_Offset}),
.save = _CHRONO duration_cast<minutes>(_Internal_duration{_Info->_Save}),
.abbrev = _Info->_Abbrev};
}

string _Name;
};

Expand Down
15 changes: 15 additions & 0 deletions stl/inc/xtzdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ _STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

using __std_tzdb_epoch_milli = double;

struct __std_tzdb_registry_leap_info {
uint16_t _Year;
uint16_t _Month;
Expand Down Expand Up @@ -53,6 +55,15 @@ struct __std_tzdb_current_zone_info {
const char* _Tz_name;
};

struct __std_tzdb_sys_info {
__std_tzdb_error _Err;
__std_tzdb_epoch_milli _Begin;
__std_tzdb_epoch_milli _End;
int32_t _Offset;
int32_t _Save;
const char* _Abbrev;
};

_EXTERN_C

_NODISCARD __std_tzdb_time_zones_info* __stdcall __std_tzdb_get_time_zones() noexcept;
Expand All @@ -61,6 +72,10 @@ void __stdcall __std_tzdb_delete_time_zones(__std_tzdb_time_zones_info* _Info) n
_NODISCARD __std_tzdb_current_zone_info* __stdcall __std_tzdb_get_current_zone() noexcept;
void __stdcall __std_tzdb_delete_current_zone(__std_tzdb_current_zone_info* _Info) noexcept;

_NODISCARD __std_tzdb_sys_info* __stdcall __std_tzdb_get_sys_info(
const char* _Tz, size_t _Tz_len, __std_tzdb_epoch_milli _Local) noexcept;
void __stdcall __std_tzdb_delete_sys_info(__std_tzdb_sys_info* _Info) noexcept;

__std_tzdb_registry_leap_info* __stdcall __std_tzdb_get_reg_leap_seconds(
size_t _Prev_reg_ls_size, size_t* _Current_reg_ls_size) noexcept;

Expand Down
4 changes: 3 additions & 1 deletion stl/src/msvcp_atomic_wait.src
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,18 @@ EXPORTS
__std_calloc_crt
__std_close_threadpool_work
__std_create_threadpool_work
__std_tzdb_delete_reg_leap_seconds
__std_execution_wait_on_uchar
__std_execution_wake_by_address_all
__std_free_crt
__std_parallel_algorithms_hw_threads
__std_release_shared_mutex_for_instance
__std_submit_threadpool_work
__std_tzdb_delete_current_zone
__std_tzdb_delete_reg_leap_seconds
__std_tzdb_delete_sys_info
__std_tzdb_delete_time_zones
__std_tzdb_get_current_zone
__std_tzdb_get_reg_leap_seconds
__std_tzdb_get_sys_info
__std_tzdb_get_time_zones
__std_wait_for_threadpool_work_callbacks
Loading