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

  时间是指从某个时间点开始到另一个时间点经过的“长度”,是“纵向”距离,一般在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. TF-IDF 算法原理以及源码实现

    TF-IDF(Term Frequency-Inverse Document Frequency),是用来衡量一个词在文档中的重要性,下面看一下TDF-IDF的公式: 首先是TF,也就是词频,用来衡量 ...

  2. 资产管理平台去除zabbix字样

    1.主机可用性 修改/usr/share/zabbix/include/html.inc.php,文件没有改动过的话在602行,将zbx改成我们需要的即可 2.修改系统信息 修改/usr/share/ ...

  3. 使用 Nuxt 的 showError 显示全屏错误页面

    title: 使用 Nuxt 的 showError 显示全屏错误页面 date: 2024/8/26 updated: 2024/8/26 author: cmdragon excerpt: 摘要: ...

  4. .net core下使用事件总线

            随着微服务的火热,DDD(领域驱动设计模式)思想风起云涌,冲击着整个软件生态系统.其中,事件总线那是必须知道的了,于是我便抱着一个学习DDD的心态搭建了一个博客网站,目前该网站正在建设 ...

  5. Ubuntu 设置远程桌面(RDP)

    安装桌面环境 如果你的 Ubuntu 还没有安装桌面环境,可以选择以下之一安装: GNOME GNOME 是 Ubuntu Desktop 原生桌面环境. # 安装基本的 GNOME 桌面环境 sud ...

  6. LaTeX 几种中文字体的比较

    根据自己的喜好给常见的几个中文字体的打分: 字体选项 字体名 得分 adobe Adobe 宋体 Std 5 fandol FandolSong 0 founder 方正书宋_GBK 10 hanyi ...

  7. ComfyUI 基础教程(三) —— 应用 Controlnet 精准控制图像生成

    一.前言 你是否有见过下面类似这样的图片: 看起来平平无奇,当你站远点看,或者把眼睛眯成一条缝了看,你会发现,这个图中藏有一些特别的元素.这就是利用了 Ai 绘画中的 ControlNet,实现对图片 ...

  8. Openstack-dashboard默认配额

    创建实例不超过10个 方法一 修改配置文件 在使用openstack的过程中,默认创建的实例最多10个,这是因为配额默认实例就是10 所以我们需要修改配置文件/etc/nova/nova.conf中的 ...

  9. @Primary ,@Qualifier ,@Autowired ,@Resource作用与区别

    首先阐述 @Autowired 和 @Resource 的区别 @Resource 是JDK自带的注解 可以按名称注入也可以按类型注入,默认是按名称注入,没有显式指定名称时,在spring容器中匹配与 ...

  10. 安装mysql5.7报错启动失败(3534)的处理

    一 ,在官网下载好了mysql5.7之后,解压到对应的文件的夹下 二, 在cmd中进入到mysql下单bin目录下,一定要是管理员权限,执行mysqld --initialize 命令,会看到根目录下 ...