You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C++ Chrono计算本地时间区间对应的UTC时间

问题

我有一组时间序列,需要以每周周日午夜本地时间为起点的秒数划分区间。序列中的时间戳为UTC 1970年1月1日午夜以来的毫秒数。以America/New_York时区为例,第一个区间为周日午夜后64860秒至147540秒(即周日18:01至周一16:59),需处理2025年11月2日(夏令时结束)、2026年3月8日(夏令时开始)这两个特殊周的时间转换。

当前使用C++ Chrono编写的代码计算出的UTC时间戳不符合预期,具体代码及错误输出如下:

#include <iostream>

#include <chrono>
#include <format>

auto week_begining(std::chrono::milliseconds timestamp, std::string_view scheduleTimeZone)
{
    // get zoned_time for previous SUNDAY 00:00 local time

    using namespace std::chrono;

    // timepoint based on utc
    auto tp = system_clock::time_point( timestamp );

    // zoned timepoint
    auto tz = locate_zone(scheduleTimeZone);
    std::chrono::zoned_time zt{tz,  tp};

    auto local_time = zt.get_local_time();
    auto local_date = floor<days>( local_time );

    // count back to Sunday
    auto days_ago = weekday{local_date} - Sunday;
    auto sunday = local_date - days_ago;

return std::chrono::zoned_time{tz, std::chrono::local_days{sunday} };
}

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

    auto sunday = week_begining( milliseconds(1762146000000), "America/New_York").get_sys_time();

    std::cout << std::format("{:%Y-%m-%d %X} ", sunday) << duration_cast<milliseconds>(sunday.time_since_epoch()) <<std::endl;

    auto start = sunday + seconds(64860);
    auto end   = sunday + seconds(147540);

    std::cout << std::format("{:%Y-%m-%d %X} ", start) << duration_cast<milliseconds>(start.time_since_epoch()).count() << std::endl;

    std::cout << std::format("{:%Y-%m-%d %X} ", end) << duration_cast<milliseconds>(end.time_since_epoch()).count() << std::endl;

    return 0;
}

错误输出:

2025-11-02 04:00:00 1762056000000ms -- correct
2025-11-02 22:01:00 1762120860000   -- incorrect this has returned 2nd @ 5pm
2025-11-03 20:59:00 1762203540000   -- incorrect this has returned 3rd @ 4pm

请问如何正确计算本地时间区间对应的UTC时间?

解决方案

错误原因

你的代码错误在于:将周日午夜对应的UTC时间点直接加上秒数偏移,这是在UTC时间轴上做计算,没有考虑本地时区的夏令时切换。比如2025年11月2日纽约时区结束夏令时,本地时间会回拨1小时,UTC时间轴的偏移无法反映这个本地时间的变化,导致计算出的UTC时间对应错误的本地时刻。

正确的思路应该是:在本地时间轴上基于周日午夜计算偏移,再将本地时间转换为UTC时间,这样Chrono会自动处理夏令时的时区转换逻辑。

修改后的代码

#include <iostream>
#include <chrono>
#include <format>

auto week_beginning_local(std::chrono::milliseconds timestamp, std::string_view scheduleTimeZone)
{
    using namespace std::chrono;

    // 将UTC时间戳转换为目标时区的本地时间
    auto tp = system_clock::time_point(timestamp);
    auto tz = locate_zone(scheduleTimeZone);
    zoned_time zt{tz, tp};

    auto local_time = zt.get_local_time();
    auto local_date = floor<days>(local_time);

    // 回退到上一个周日的本地午夜
    auto days_ago = weekday{local_date} - Sunday;
    local_days sunday_local{local_date - days_ago};

    // 返回本地时间的周日午夜(而非转换后的UTC时间)
    return local_time_point<system_clock::duration>(sunday_local);
}

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

    const auto tz = locate_zone("America/New_York");
    // 获取目标周的本地周日午夜
    auto sunday_local = week_beginning_local(milliseconds(1762146000000), "America/New_York");

    // 在本地时间轴上计算区间起止
    auto start_local = sunday_local + seconds(64860);
    auto end_local = sunday_local + seconds(147540);

    // 将本地时间转换为UTC时间点
    zoned_time start_zt{tz, start_local};
    zoned_time end_zt{tz, end_local};
    zoned_time sunday_zt{tz, sunday_local};

    // 输出结果
    auto sunday_sys = sunday_zt.get_sys_time();
    std::cout << std::format("{:%Y-%m-%d %X} ", sunday_sys) 
              << duration_cast<milliseconds>(sunday_sys.time_since_epoch()) << "\n";

    auto start_sys = start_zt.get_sys_time();
    std::cout << std::format("{:%Y-%m-%d %X} ", start_sys) 
              << duration_cast<milliseconds>(start_sys.time_since_epoch()).count() << "\n";

    auto end_sys = end_zt.get_sys_time();
    std::cout << std::format("{:%Y-%m-%d %X} ", end_sys) 
              << duration_cast<milliseconds>(end_sys.time_since_epoch()).count() << "\n";

    return 0;
}

代码说明

  1. week_beginning_local函数:不再返回转换后的UTC时间,而是返回本地时间轴上的周日午夜local_time_point,确保后续的秒数偏移是基于本地时间计算。
  2. 本地时间偏移:直接在local_time_point上加上64860和147540秒,得到本地时间的区间起止点。
  3. 时区转换:通过zoned_time将本地时间转换为UTC时间,Chrono会自动处理夏令时切换的时区偏移计算,比如2025年11月2日纽约时区的回拨逻辑。

正确输出示例

针对2025年11月的夏令时结束周,正确输出应为:

2025-11-02 04:00:00 1762056000000ms
2025-11-02 23:01:00 1762124460000   -- 对应纽约本地时间11月2日18:01
2025-11-03 20:59:00 1762203540000   -- 对应纽约本地时间11月3日16:59(夏令时结束后UTC偏移变为-5)

内容的提问来源于stack exchange,提问作者ArchNemSyS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 09:04:50