首先我们要明白,“时间”和“时区”是两个东西。

  时间是指从某个时间点开始到另一个时间点经过的“长度”,是“纵向”距离,一般在linux系统内有两个主要的时间,一是始于1970年(unix元年)至今的距离,二是系统启动后至今的距离。前者一般是由不断电的硬件维护(RTC)或者其他专门服务器授时(NTP),可修改;后者只能前进无法后退,不能修改

  时区则是指世界范围内(国家/洲际之间)昼夜交替不同而导致的每天的相对时间不同造成的区域划分,是“横向”的“偏移”。比如北京会比纽约早12小时看到日出。时区一般以1小时划分,全球就有24个时区

  linux操作系统内核只有“时间”概念,没有“时区”概念。对于linux操作系统本身来说,启动后时间为0,表示当前就是1970年。我们通过读取RTC或NTP时间后,会通过系统调用更新这个时间,然后cpu会自动对时间进行累加。后面其他进程就可以获取正确的时间了。

  应用进程从系统内核读取到自1970年来经历过的时间后就会有一个问题,就是同样经过了一百年整,有些地区现处于旭日东升,另一些地区确黑夜蔽日。因此就要靠时区对这个时间进行一个“合理的描述”,比如在北京,现在就应该处于正午,日头正浓,而同样的时间点在纽约,大家就进入梦乡了。

  这样大家更加理解了时区概念,它并不存在,只是为了让全球在24小时的尺度内(由于地球自转)对于同样一个时间点发生的日照情况比较合理。

  

  接下来我们着重说说应用进程如何使用时间和时区。

  一般我们会将这个过程分为3步,第一步是从系统获取时间(1970年来秒数),第二步是从文件系统读取时区配置(对于现代操作系统,还可能是GPS定位或通过出口网络进行ISP运营商定位等)以获取偏移量(也即一个秒数,可能为负),第三步则是将两者相加并格式化输出。

  (这里还体现了我们程序编写中的一个数据和显示分离的思维,数据还是那个数据(1970年至今秒数),但展示是因人而异的)

  

  

  上面代码中的tzset十分重要,它一般会从环境变量或/etc/localtime文件中读取时区配置并设置到进程全局变量。然后localtime,strftime等函数则会参考全局变量来计算当前地区应该显示的时间。

  (tzset函数可以只调用一次,除非确定了配置更改,也可以不调用,因为strftime等函数内部有判定,如果进程对tzset函数调用次数为0,则会主动调用一次)

  我们具体讲讲linux下时间日期的格式化输出和其背后的运行逻辑。

  首先我们要认识一个前提:就是tzset为什么必须调用?

  其实道理很简单,因为c库没有自动运行的权利。它不会在你加载*c.so时就自动调用某个函数,甚至遑论读取文件系统的文件,这个操作具有一定的侵入性,也会造成一些不必要的浪费(万一你的程序不需要格式化时间日期呢)。

  我们根据一个实例来跟踪一下。

  我们一般在系统内查看当前时间是使用date命令,以下是一般用法。

  

  我们跟踪一下date命令的代码(以busybox为例)

  

  

  

  我们可以看到,其实重要的就是time/localtime/strftime几个函数。

  我们接着跟踪一下。

  

  

  可以发现,localtime调用了tzset_internal。而实际上,tzset也是调用的tzset_internal。

  

  tzset后,时区的偏移量就有了。后续就可以compute了

   

  综上所述,其实所谓的时区并不复杂,就是一个秒数偏移量,用于不同地域的格式化输出。

  我们再最后稍微深入分析一下tzset的内部实现。

  

  可以看到,tzset首先从环境变量/编译时宏定义/运行时系统文件等地方读取配置进行分析。

   

  当然,最终更新到的全局变量在外部也可访问

  

  从tzset代码也可以看出,一般我们配置时区还是以配置文件为主。配置文件一般在/etc/localtime。

  

  当然,这个配置文件是二进制的,并不容易编辑。

  

  如果只需要单独进程具有正确的时区,可以使用setenv("TZ", "CST-8", 1);tzset();来更新。

  setenv中还有一个坑,就是我们为什么设置的是CST-8(CST是什么意思我就不赘述了,大家百度一下即可,其实也没什么特别的意思,写ABC没区别,它只是你为当前地区取得别名),不是说中国在东8区吗,东为正,应该是+8啊!

  这里是一个思维误区,就是我们设置的是UTC时区,即是“计算出UTC零点的算法”。所以CST=UTC+(+8小时) 或 UTC=CST-(+8小时)。

  最后修改时间 2024-08-04 14:13:54

  ps:虽然linux设置和获取系统时间现在的函数settimeofday和gettimeofday可以传递时区,但我还是建议不使用这部分功能,还是只用获取的unix秒数部分以及/etc/localtime配置文件。

  毕竟官方已经建议settimeofday中的tz传递NULL

  

   

  最后修改时间 2024-08-05 11:47:06

  linux常用的时间日期函数如下:

  time :用于从操作系统获取Unix时间戳

  settimeofday : 设置unix时间戳到操作系统(stime已弃用)

  mktime : 从本地时间(加了偏移量)转为unix时间戳

  localtime : 从unix时间戳转为本地时间

  如果我们的进程需要负责设置系统时间,一般是两种办法,一是从服务器获取unix时间戳直接通过settimeofday设置;二是使用时区和本地时间,先将时区通过setenv或/etc/localtime方式保存,然后tszet,而后通过mktime将本地时间转为unix时间戳,再通过settimeofday设置。

  mktime/localtime都会在内部使用时区配置(tzset)。

  以下是一个设置系统时间的参考代码:

#include <unistd.h>
#include <sys/time.h> #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <chrono> int main() { setenv("TZ", "CST-8", 1);
tzset(); std::tm when = {0};
std::stringstream ss_when;
ss_when <<"2024-08-09 12:00:23";
ss_when >> std::get_time(&when, "%Y-%m-%d %H:%M:%S");
std::time_t t = mktime(&when);
timeval tv = {0};
tv.tv_sec = t;
::settimeofday(&tv, nullptr);
std::system("hwclock -wu"); return 0;
}

  (对于c++来说,从字符串转为tm要方便很多)

  注意:tm和time_t转换就涉及到时区

  最后修改时间 2024-08-09 22:23:48

linux下时间时区详解的更多相关文章

  1. Linux下ps命令详解 Linux下ps命令的详细使用方法

    http://www.jb51.net/LINUXjishu/56578.html Linux下的ps命令比较常用 Linux下ps命令详解Linux上进程有5种状态:1. 运行(正在运行或在运行队列 ...

  2. Linux下rar命令详解

    Linux下rar命令详解 用法: rar <命令> -<选项1> ….-<选项N> < 操作文档> <文件…> <@文件列表…> ...

  3. linux下tar命令详解

     linux下tar命令详解    tar是Linux环境下最常用的备份工具之一.tar(tap archive)原意为操作磁带文件,但基于Linux的文件操作机制,同样也可适用于普通的磁盘文件.ta ...

  4. Linux下top命令详解

    Linux下top命令详解 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.top是一个动态显示过程,即可以通过用户按键来不断刷 ...

  5. Linux下桥接模式详解一

    注册博客园已经好长时间,一直以来也没有在上面写过文章,都是随意的记录在了未知笔记上,今天开始本着分享和学习的精神想把之前总结的笔记逐步分享到博客园,和大家一起学习,一起进步吧! 2016-09-20  ...

  6. linux下IPTABLES配置详解 (防火墙命令)

    linux下IPTABLES配置详解 -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 24000 -j ACCEPT ...

  7. Linux下chkconfig命令详解(转)

    Linux下chkconfig命令详解 chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. ...

  8. Linux知识积累(4) Linux下chkconfig命令详解

    Linux下chkconfig命令详解 chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. ...

  9. 转载的 Linux下chkconfig命令详解

    Linux下chkconfig命令详解 chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. ...

  10. 转 linux下cat命令详解

    linux下cat命令详解 http://www.cnblogs.com/perfy/archive/2012/07/23/2605550.html 简略版: cat主要有三大功能:1.一次显示整个文 ...

随机推荐

  1. UDP协议实现音频传输

    目录 服务器端 客户端 服务器端 /********************************************************************************** ...

  2. 系统IO常用函数接口

    本文整理归纳了几种常用的系统IO的函数借口,以供读者查阅使用 目录 系统IO与标准IO的区别 打开文件:open 关闭文件:close 文件读取:read 文件写入:write 位置偏移:lseek ...

  3. awk批量提取序列

    在提取前需保证序列文件仅有一列! awk '{print$1}' input.fa > ouput.fa#就可将ID后面的其余注释信息去掉,仅保留ID 1 awk -F '>' 'NR=F ...

  4. 关于REACT范式的一些思考

    关于REACT范式的一些思考 REACT范式经过近一年的探索,让我们在很多领域有了非常广泛的应用,它确实提升了很多之前无法解决的问题,比如大模型虽然在语言理解和交互式决策方面在任务中表现出令人印象深刻 ...

  5. StartImage.DLL使用说明

    StartImage.DLL使用说明 一.库的引入 库包含以下物件,请按照要求将以下库映入到项目中 StartImage.dll StartImage.lib StartImage.h 二.注意事项 ...

  6. 处理一直显示npm WARN using –force Recommended protections disabled.的问题

    使用 npm config set force false 可以消除.

  7. macOS 磁盘设备文件命名规则

    macOS 系统使用不同于 Linux 的磁盘设备命名规则.在 macOS 中,磁盘设备和分区被命名并通过 /dev 目录访问,类似于 Linux 和 UNIX 系统.但是,macOS的命名规则遵循特 ...

  8. AI驱动的PlantUML:快速生成专业级UML类图和用例图

    承接前文关于如何运用 AI 工具生成时序图的内容[1],今天我们继续探讨 AI 驱动的 PlantUML:高效创建专业的 UML 类图与用例图. [1]: https://juejin.cn/post ...

  9. 【工程应用十二】Bayer图像格式中Hamilton-Adams及Zhang Wu 基于LMMSS算法的Demosaic过程优化。

    Demosaic,中文直接发翻译为去马赛克, 但是其本质上并不是去除马赛克,这让很多第一次接触这个名词或者概念的人总会想的更多.因此,一般传感器在采集信息时一个位置只采集RGB颜色中的一个通道,这样可 ...

  10. 利用水墨映客图床作为COS服务器

    目录 利用水墨映客作为COS服务器 利用picGo配合typora上传图片 安装PicGo(以Windows为例) 安装lankong插件 在SpringBoot中开发图片上传工具类 设置图片上传请求 ...