如何用C++20 Chrono将含闰秒的UTC时间转本地时间并正确打印
闰秒时间转换为带时区的本地时间并保留闰秒显示
背景与问题
时间点2016-Dec-31 23:59:60是因闰秒插入产生的有效UTC时间,对应的std::chrono::utc_clock::time_point距离1970-Jan-1 epoch为1483228826秒。
需求是将该UTC时间转换为任意时区(如Europe/Berlin)的本地时间,并保留:60的闰秒显示。但标准库中zoned_time仅接受忽略闰秒的sys_time,直接转换会丢失闰秒信息,输出变为23:59:59。
解决方案
核心思路是手动拆分UTC时间的日历信息(含闰秒),结合时区偏移计算本地时间,最后自定义格式化输出以保留闰秒:
步骤说明
- 从
utc_clock::time_point提取包含闰秒的UTC日历和时分秒信息 - 基于不含闰秒的
sys_time计算目标时区的偏移量(时区偏移与闰秒无关) - 将UTC时分秒与时区偏移相加,处理日期进位得到本地时间的日历信息
- 格式化时判断原UTC时间是否为闰秒,若为闰秒则输出
:60
代码示例
#include <chrono> #include <format> #include <iostream> #include <string> int main() { using namespace std::chrono; // 初始化带闰秒的UTC时间点 utc_clock::time_point then{}; then += seconds(1483228826); // 提取UTC的日历与时分秒信息(保留闰秒) auto utc_date = floor<days>(then); auto utc_hms = hh_mm_ss{then - utc_date}; auto utc_ymd = year_month_day{utc_date}; // 计算目标时区相对于UTC的偏移量(基于sys_time) auto sys_tp = clock_cast<system_clock>(then); zoned_time zt{"Europe/Berlin", sys_tp}; auto tz_offset = zt.get_info().offset; // 计算本地时间的时分秒,处理日期进位 auto local_duration = utc_hms.to_duration() + tz_offset; days date_adjust{0}; if (local_duration > 24h) { date_adjust = days{1}; local_duration -= 24h; } else if (local_duration < 0s) { date_adjust = days{-1}; local_duration += 24h; } auto local_ymd = utc_ymd + date_adjust; auto local_hms = hh_mm_ss{local_duration}; // 自定义格式化输出,保留闰秒 std::cout << std::format("{0:%Y-%m-%d} {1:%H}:{1:%M}:{2}", local_ymd, local_hms, utc_hms.seconds().count() == 60 ? 60 : local_hms.seconds().count()) << std::endl; return 0; }
代码关键点
utc_clock支持闰秒,提取的hh_mm_ss会保留:60的秒数- 时区偏移通过
zoned_time基于sys_time计算,确保偏移量正确(闰秒不影响时区规则) - 手动处理日期进位,保证本地时间的日期部分准确
- 格式化时复用UTC的闰秒标记,确保本地时间显示
:60
内容的提问来源于stack exchange,提问作者Hajo Kirchhoff
相关产品推荐
相关产品推荐

