linux下时区的记录

1 日历编写时遇到的时间未随时区修改而更新的问题记录

1.1 原程序逻辑

#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main() {
    while (1) {
        struct timespec t;
        char timeString[30];
        struct tm localTime;
        clock_gettime( CLOCK_REALTIME, &t );
        tzset();
        localtime_r(&(t.tv_sec), &localTime);
        snprintf(timeString, 30, "%04d-%02d-%02d %02d:%02d:%02d",
localTime.tm_year + 1900, localTime.tm_mon + 1, localTime.tm_mday,
localTime.tm_hour, localTime.tm_min, localTime.tm_sec);
        printf("now time : %s\n", timeString);
        sleep(5);
    }
    return 0;
}

该程序一直运行在后台时,利用echo xx > /etc/TZ。可以观察到date中的数据被修改了,时间为我们新设置好的时区下的时间。但是程序打印结果仍然是修改前的时间。

原因考虑为:程序在启动时会缓存初始的时区信息,而不会在运行过程中重新读取环境变量的更改。这可能导致即使修改了环境变量 TZ,程序仍然使用先前的时区信息。

1.2 新程序逻辑

由于包含该日志的程序需要一直在后台运行,所以无法通过重启来实现时间的更新。故修改为手动读取/etc/TZ的值,一旦发现有修改,便手动在程序中再次设置新时区,并做时区更新和时间校准。

#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include <fcntl.h>

char prevTZ[256] = "";  // 用于存储上一次记录的时区值

void checkAndHandleTZChange() {
    int fd;
    char currentTZ[256];
    fd = open( "/etc/TZ", O_RDONLY );

    if ( fd < 0 ) {
        return;
    }

    if ( read( fd, currentTZ, sizeof ( currentTZ ) ) <= 0 ) {
        close( fd );
        return;
    }

    if (currentTZ != NULL && strcmp(currentTZ, prevTZ) != 0) {
        printf("Detected TZ change: %s\n", currentTZ);
        // 在这里执行响应的操作,例如更新时区设置或进行其他处理
        strncpy(prevTZ, currentTZ, sizeof(prevTZ));  // 更新记录的时区值
        setenv("TZ", currentTZ, 1);
        tzset();
    }
    close( fd );
}

int main() {
    while (1) {
        struct timespec t;
        char timeString[30];
        struct tm localTime;
        checkAndHandleTZChange();
        clock_gettime( CLOCK_REALTIME, &t );
        localtime_r(&(t.tv_sec), &localTime);
        snprintf(timeString, 30, "%04d-%02d-%02d %02d:%02d:%02d",
                     localTime.tm_year + 1900, localTime.tm_mon + 1, localTime.tm_mday,
                     localTime.tm_hour, localTime.tm_min, localTime.tm_sec);
        printf("now time : %s\n", timeString);
        sleep(5);
    }
    return 0;
}

1.3 其他问题

Q:同一台设备,用串口和telnet连接,为什么date打印出来的时间不一样?(/etc/TZ是一样的)

A:时区设置不同:串口和 Telnet 连接可以使用不同的用户配置文件或会话环境。这可能导致每个连接的默认时区设置不同,从而导致 date 命令显示不同的时间。你可以尝试在两个连接中分别执行 date 命令后,再用 echo $TZ 命令来检查每个连接的时区设置。串口和 Telnet 连接通常会创建不同的登录会话。每个会话可能具有自己的环境变量、运行的进程和系统设置,这可能会导致 date 命令的输出不同。

解决方法:打开串口连接的终端,重新设定TZ值,使两边的echo $TZ 命令打印出的信息一致。

export TZ=TZY-8

2 硬件时钟和系统时钟说明

在时间同步领域,步进(Step)是指对系统时钟进行一次较大的调整,以使其与参考时间源的时间相一致。当系统时钟与参考时间源的时间差距较大时,执行步进操作可以迅速地将系统时钟调整到正确的时间。

步进操作通常发生在启动时或者在时间同步过程中发现系统时钟与参考时间源的差距较大时。它与调整(Adjustment)操作不同,调整操作是对系统时钟进行微小的调整,以逐渐减小时钟的偏差。

在代码中,当满足一定条件时,clock_adjust函数会判断是否需要执行步进操作。具体判断的逻辑可能涉及服务器的偏移量与阈值的比较,以决定是否执行步进操作。

步进操作对于快速调整系统时钟以实现准确的时间同步非常重要,但也可能导致系统时间的不连续性,因此在使用步进操作时需要谨慎考虑,并确保其适用于特定的应用场景。

硬件时钟:主板上的定时器时钟

系统时钟:系统的内核时钟

两者互不影响!

2.1 硬件时钟

也可称为:实时时钟,RTC,BIOS时钟,CMOS时钟

独立运行于任何控制程序,运行在CPU中,当机器关闭时也运行。一个非常低功耗的I2C和SPI时钟芯片可以与备用电池一起作为硬件时钟,以初始化一个功能更好的集成实时时钟,用于大多数用途。

2.2 系统时钟

Linux内核内的时钟保持的时间,由计时器中断驱动。它只有在linux在机器上运行时才有意义。它是从1970年世界协调时间1月1日00:00开始的秒数。

在Linux启动时,系统时间从硬件时钟初始化,然后不再使用硬件时钟。系统运行时可以用date来进行时间设置,期间可以对系统时钟做任何事,但是下一次linux启动时,它将使用硬件时钟的调整时间进行设置。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值