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

Ubuntu20下Boost1.71.0运行中时区变更后本地时间不更新的解决方法

问题:运行时修改系统时区后,Boost本地时间无法自动更新

环境信息

  • Boost版本:1.71.0
  • 操作系统:Ubuntu 20.04

测试代码

#include <iostream>
#include <boost/date_time/c_local_time_adjustor.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <thread>

int main(int argc, char const* argv[])
{
    while (true)
    {
        auto utc_now = boost::date_time::second_clock<boost::posix_time::ptime>::universal_time();
        auto now = boost::date_time::c_local_adjustor<boost::posix_time::ptime>::utc_to_local(utc_now);
        std::cout << "now: " << to_simple_string(now) << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }
    return 0;
}

现象描述

运行程序后,在另一终端执行timedatectl修改系统时区:

./program
now: 2024-Mar-12 12:30:09
# 另一终端执行:sudo timedatectl set-timezone <新时区>
now: 2024-Mar-12 12:30:19 # 本地时间无变化,仍与时区修改前一致

重启程序后,输出的本地时间会自动更新为新时区对应的时间:

./program
now: 2024-Mar-12 06:30:25 # 新时区对应的本地时间

请问如何让程序在运行状态下自动感知时区变化并更新本地时间?


解决方案

问题根源在于c_local_adjustor会在初次调用时缓存系统时区信息,后续不会主动重新读取。要实现运行时动态感知时区变化,可采用以下两种方案:

1. 每次转换前手动重置时区缓存

Boost.Date_Time底层依赖POSIX标准的tzset()函数,该函数会重新读取系统时区配置文件(Ubuntu下为/etc/localtime)并重置进程内的时区缓存。修改代码,在每次转换UTC到本地时间前调用该函数:

#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <thread>
#include <ctime>

int main(int argc, char const* argv[])
{
    while (true)
    {
        auto utc_now = boost::date_time::second_clock<boost::posix_time::ptime>::universal_time();
        
        // 重置时区缓存
        tzset();
        // 使用to_local_time替代c_local_adjustor,依赖更新后的时区信息转换
        auto now = boost::posix_time::to_local_time(utc_now);
        
        std::cout << "now: " << boost::posix_time::to_simple_string(now) << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }
    return 0;
}

2. 监听时区配置文件变化(高效方案)

Ubuntu修改时区会触发/etc/localtime软链接的更新,可通过inotify API监听该文件的变化,仅在实际时区变更时重置缓存,避免循环调用tzset()的开销:

#include <sys/inotify.h>
#include <unistd.h>
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <thread>
#include <ctime>

void watch_timezone_change() {
    int fd = inotify_init();
    if (fd == -1) {
        perror("inotify_init");
        return;
    }
    int wd = inotify_add_watch(fd, "/etc/localtime", IN_MODIFY | IN_ATTRIB | IN_DELETE_SELF);
    if (wd == -1) {
        perror("inotify_add_watch");
        close(fd);
        return;
    }
    char buf[4096];
    while (true) {
        int len = read(fd, buf, sizeof(buf));
        if (len == -1) {
            perror("read");
            break;
        }
        // 检测到时区文件变化,重置缓存
        tzset();
        std::cout << "时区已更新,缓存已重置" << std::endl;
    }
    inotify_rm_watch(fd, wd);
    close(fd);
}

int main(int argc, char const* argv[])
{
    // 启动单独线程监听时区变化
    std::thread timezone_watcher(watch_timezone_change);
    timezone_watcher.detach();

    while (true)
    {
        auto utc_now = boost::date_time::second_clock<boost::posix_time::ptime>::universal_time();
        auto now = boost::posix_time::to_local_time(utc_now);
        std::cout << "now: " << boost::posix_time::to_simple_string(now) << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }
    return 0;
}

编译时需链接pthread库:

g++ -o program program.cpp -lboost_date_time -lpthread

注意事项

  • tzset()是POSIX标准接口,仅在Linux/Unix系统有效,Windows需使用SetTimeZoneInformation等对应API。
  • Boost 1.71.0版本中c_local_adjustor的缓存无公开清除接口,因此使用to_local_time配合tzset()是更稳妥的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 03:15:03