gpt4 book ai didi

c++ - C++将time_t读入不同的时区,然后提取年/月…纳秒

转载 作者:行者123 更新时间:2023-12-02 09:59:53 24 4
gpt4 key购买 nike

我正在使用以下问题的答案,从自Epoch以来包含纳秒的源中提取年/月/日/小时/分钟/秒/纳秒。
Extract year/month/day etc. from std::chrono::time_point in C++
但是,我的输入是不同的时区。下面是我到目前为止的代码。

  • 如何将以下内容转换为其他时区的内容?
  • 在执行duration_cast之前需要转换吗?否则,小时/分钟/秒的数量可能是错误的?

  • 我正在使用C++ 17,Clang,Linux,并且更喜欢标准库。几个月后将过渡到C++ 20,我怀疑这将简化答案。
    using namespace std;
    using namespace std::chrono;
    using Clock = high_resolution_clock;
    using TimePoint = time_point<Clock>;

    const nanoseconds nanosecondsSinceEpoch(nanosecondsSinceEpochTS);
    const Clock::duration since_epoch = nanosecondsSinceEpoch;
    const TimePoint time_point_sinc_epoch(since_epoch);

    using days = duration<int, ratio_multiply<hours::period, ratio<24> >::type>;

    system_clock::time_point now = time_point_sinc_epoch; // Do I need to handle timezone here before duration_cast?
    system_clock::duration tp = now.time_since_epoch();
    days d = duration_cast<days>(tp);
    tp -= d;
    hours h = duration_cast<hours>(tp);
    tp -= h;
    minutes m = duration_cast<minutes>(tp);
    tp -= m;
    seconds s = duration_cast<seconds>(tp);
    tp -= s;

    const uint64_t nanosSinceMidnight = tp.count();

    time_t tt = system_clock::to_time_t(now);
    tm utc_tm = *gmtime(&tt); // Presumably this needs to change

    std::cout << utc_tm.tm_year + 1900 << '-';
    std::cout << utc_tm.tm_mon + 1 << '-';
    std::cout << utc_tm.tm_mday << ' ';
    std::cout << utc_tm.tm_hour << ':';
    std::cout << utc_tm.tm_min << ':';
    std::cout << utc_tm.tm_sec << '\n';

    最佳答案

    由于您的输入和输出在同一时区,因此时区本身变得无关紧要。随后,这使这个问题非常容易。只需将纳秒计数转换为所需的字段。我建议使用one short public domain helper function将天数转换为{y, m, d}数据结构。

    #include <chrono>
    #include <iostream>
    #include <tuple>

    // Returns year/month/day triple in civil calendar
    // Preconditions: z is number of days since 1970-01-01 and is in the range:
    // [numeric_limits<Int>::min(), numeric_limits<Int>::max()-719468].
    template <class Int>
    constexpr
    std::tuple<Int, unsigned, unsigned>
    civil_from_days(Int z) noexcept
    {
    static_assert(std::numeric_limits<unsigned>::digits >= 18,
    "This algorithm has not been ported to a 16 bit unsigned integer");
    static_assert(std::numeric_limits<Int>::digits >= 20,
    "This algorithm has not been ported to a 16 bit signed integer");
    z += 719468;
    const Int era = (z >= 0 ? z : z - 146096) / 146097;
    const unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]
    const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
    const Int y = static_cast<Int>(yoe) + era * 400;
    const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365]
    const unsigned mp = (5*doy + 2)/153; // [0, 11]
    const unsigned d = doy - (153*mp+2)/5 + 1; // [1, 31]
    const unsigned m = mp + (mp < 10 ? 3 : -9); // [1, 12]
    return std::tuple<Int, unsigned, unsigned>(y + (m <= 2), m, d);
    }

    int
    main()
    {
    using namespace std;
    using namespace std::chrono;

    auto nanosecondsSinceEpochTS = 1592130258959736008;
    using days = duration<int, ratio_multiply<hours::period, ratio<24> >>;

    nanoseconds ns(nanosecondsSinceEpochTS);
    auto D = floor<days>(ns);
    ns -= D;
    auto H = duration_cast<hours>(ns);
    ns -= H;
    auto M = duration_cast<minutes>(ns);
    ns -= M;
    auto S = duration_cast<seconds>(ns);
    ns -= S;
    auto [y, m, d] = civil_from_days(D.count());
    cout << "y = " << y << '\n';
    cout << "m = " << m << '\n';
    cout << "d = " << d << '\n';
    cout << "H = " << H.count() << '\n';
    cout << "M = " << M.count() << '\n';
    cout << "S = " << S.count() << '\n';
    cout << "NS = " << ns.count() << '\n';
    }
    输出:
    y = 2020
    m = 6
    d = 14
    H = 10
    M = 24
    S = 18
    NS = 959736008
    更新资料
    在下面的评论中进行讨论之后,我们发现 nanosecondsSinceEpochTS是UTC,而不是我想象的America / Chicago。这意味着,作为时区和纳秒计数的函数的UTC偏移必须作为第一步添加到计数中。然后按照上述指示进行操作以获取每个字段。
    找到正确的偏移量是一个不平凡的过程,我不会尝试显示其代码。一种技术是为所有有问题的输入年份预计算 {utc_timestamp, utc_offset}表,然后使用输入的 utc_timestamp查找正确的偏移量。
    在C++ 20中,可以简单地:
    zoned_time zt{"America/Chicago", sys_time{nanoseconds{nanosecondsSinceEpochTS}}};
    cout << zt << '\n';
    并获得输出:
    2020-06-14 05:24:18.959736008 CDT
    如果要积分字段:
    auto lt = zt.get_local_time();  // look up utc offset and add it to sys_time
    year_month_day ymd{floor<days>(lt)}; // run civil_from_days
    hh_mm_ss tod{lt - floor<days>(lt)}; // {H, M, S, NS} since local midnight

    // copy each underlying integral value
    auto y = int{ymd.year()};
    auto m = unsigned{ymd.month()};
    auto d = unsigned{ymd.day()};
    auto H = tod.hours().count();
    auto M = tod.minutes().count();
    auto S = tod.seconds().count();
    auto NS = tod.subseconds().count();
    免责声明:在撰写本文时,尚无供应商在交付C++ 20的此部分。
    POSIX时区更新
    如果您愿意使用此 free, open-source, header-only library,则可以使用POSIX时区,从而避免了IANA数据库安装问题。
    看起来像:
    #include "date/ptz.h"
    #include <iostream>

    int
    main()
    {
    using namespace date;
    using namespace std;
    using namespace std::chrono;

    auto nanosecondsSinceEpochTS = 1592130258959736008;
    zoned_time zt{Posix::time_zone{"CST6CDT,M3.2.0,M11.1.0"},
    sys_time<nanoseconds>{nanoseconds{nanosecondsSinceEpochTS}}};
    cout << zt << '\n';
    }
    输出:
    2020-06-14 05:24:18.959736008 CDT
    请注意,此模型仅可追溯到2007年的America / Chicago。在2007年之前,America / Chicago具有不同的夏令时规则。

    关于c++ - C++将time_t读入不同的时区,然后提取年/月…纳秒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63190872/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com