msvc std::chrono::time_zone::get_info 抛出异常:操作成功完成

问题描述 投票:0回答:2

我试图将从

std::chrono::system_clock
返回的 utc 时间转换为本地时间,然后使用
std::format
显示它,但我从
std::chrono::time_zone::to_local
得到了一个令人惊讶的异常,其消息内容如下:
The operation completed successfully.
太惊喜了!我研究了这个方法,它在传递的时间参数上调用了
std::chrono::time_zone::get_info
并做了一个简单的转换,所以我单独测试了
std::chrono::time_zone::get_info
,它是这个异常的根源。我不知道这是实现中的错误还是我的代码有错误?

这是一个引发此错误的简单代码:

            try
            {
                const std::chrono::time_zone* current_z = std::chrono::current_zone();
                std::cout << "current timezone name: " << current_z->name() << "\n";
                auto sys_time = std::chrono::system_clock::now();
                std::cout << "current system time: " << sys_time << "\n";
                auto sys_info = current_z->get_info(sys_time); // throws exception what(): The operation completed successfully.
                std::cout << "sys_info: offset: " << sys_info.offset << ", abbrev" << sys_info.abbrev << "\n";
                //auto local_time = current_z->to_local(sys_time); // throws exception since it calls get_info
                //std::cout << "current local time: " << local_time << "\n";
            }
            catch (const std::exception& ex)
            {
                std::cout << "caught exception: " << ex.what();
            }

编辑:查看

std::chrono::time_zone::get_info
源代码后,它将调用此方法:
std::chrono::time_zone::_Get_info
及其源代码

        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, _Tzdb_deleter<__std_tzdb_sys_info>> _Info{
                __std_tzdb_get_sys_info(_Name.c_str(), _Name.length(), _Internal_dur.count())};
            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};
        }

_Info
返回的
__std_tzdb_get_sys_info
指针不是
nullptr
,但它的
_Err
被设置为1,等于
__std_tzdb_error::_Win_error
,因此调用
_XGetLastError
来抛出异常,并带有来自
GetLastError
的错误代码,并且它将返回 0 表示没有错误代码,因此抛出异常表示没有发生错误!似乎是微软 stl 代码中的一个错误

c++ visual-c++ c++-chrono
2个回答
1
投票

https://learn.microsoft.com/en-us/cpp/standard-library/time-zone-class?view=msvc-170

看起来你应该首先使用 get_tzdb() 如

const auto& timeZoneDatabase = get_tzdb(); // initialize the time zone database
const auto& currentZone = timeZoneDatabase.current_zone();

0
投票

Windows 在内部使用时区“短名称”。 “America/New_York”时区的简称例如“UTF−5”。 但在“UTF”和“5”之间,不是“-”而是“−”(U+2212)

根据您的本地代码页,宽字符串到窄字符串的转换可能会失败。

我解决了强制应用程序代码页为 UTF-8 的问题。

setlocale(LC_ALL, ".utf8");

希望这会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.