今天这篇文章来讨论下时间的概念,及计算机如何计算和表达时间的。

1、早期的世界标准时间-格林威治时间
在农业时代,人们依靠观察太阳来确定一天的时辰。中国古代将早上太阳初升定为卯时,中午太阳当空定为午时,傍晚太阳落山定为酉时,半夜定为子时。
西方在工业革命前,也依赖“地方太阳时”——每个城市根据太阳位置定义正午(例如伦敦的正午与巴黎的正午相差约9分钟)。但19世纪铁路与航海的发展催生了对“统一时间”的需求:
1847年英国铁路首次采用“ 格林威治标准时间”(GMT),以伦敦格林威治天文台的子午线为基准。
1884年举办的国际子午线会议中,25国代表确立格林威治天文台子午线为“本初子午线”(即0°经线),“ 格林威治时间”成为全球通用的“标准时间”,时区制度也由此诞生。全球划分为24个时区,每区相差1小时。
早期的“ 格林威治时间”基于地球自转(太阳时),通过天文观测确定,但地球自转存在微小不规则性(如潮汐摩擦导致自转减速),导致“ 格林威治时间”的精度有限(误差约每年0.1秒)。
2、现在的世界标准时间-UTC(世界协调时)
20世纪50年代,原子钟的发明彻底改变了时间测量的方式。
1955年,英国国家物理实验室研制出第一台铯原子钟,首次实现“原子时间”测量,其精度达到300年误差不超过1秒。1967年,第13届国际计量大会(CGPM)正式对“秒”进行了原子时的定义,即:铯-133原子基态两个超精细能级跃迁频率的9,192,631,770个周期所持续的时间。
随着原子钟普及,1972年国际天文学联合会(IAU)和BIPM联合推出世界协调时间(UTC),取代“ 格林威治时间”成为新的全球时间标准。
世界协调时间(UTC),也称为“协调世界时”、"世界标准时间”、“国际协调时”等等,是国际民用时间的标准。其法语名称及缩写为“Temps Universel Coordonné,TUC”,英语名称及缩写为“Coordinated Universal Time,CUT”,最终缩写折中为“UTC”。
UTC的核心价值在于“统一性”与“高精度”,具体表现为:
①全球唯一标准:无论身处哪个时区,UTC时间只有一个数值(例如“UTC 12:00:00”在全球各地含义完全相同),避免了“本地时间”的混乱。
②高精度基准:基于原子钟的稳定频率,UTC的误差可控制在亿年不超过1秒,远超人类历史上任何时间标准。
③兼顾自然规律:虽然依赖原子钟,但UTC会通过“闰秒”(leap second)调整,确保与地球自转(太阳时)的偏差不超过0.9秒,避免脱离人类对“昼夜交替”的感知。
3、本地时间
1884年确立了时区的概念,不同时区的本地时间是在世界协调时间的基础上加上时区偏移量。例如我国采用的北京时间的时区偏移量为+8。假设当前世界协调时间是 2026-09-11 00:00:00 UTC,那么北京(UTC+8)的本地时间 为 2026-09-11 08:00:00
4、计算机对时间的记录
计算机对时间的记录是计算某个固定起点到现在所经过的秒数,称为“Unix时间戳(Unix timestamp)”。
Unix时间戳(或称Unix时间、POSIX时间),是计算机表达时间的一种方式,其定义为从世界协调时间(UTC)1970年01月01日00时00分00秒起至现在所经历的总秒数。
时间戳的数据类型为time_t。
①在32位系统下,time_t被定义为有符号整数,占用4字节(32位),比如:typedef long time_t;
当使用32位有符号整数表示时间时,系统的Unix时间戳最多可以使用到世界协调时(UTC)2038年01月19日03时14分07秒(二进制:01111111 11111111 11111111 11111111),其最后一秒,二进制数字会变为 10000000 00000000 00000000 00000000 发生溢出错误,这很可能造成软件故障和系统瘫痪;
②在64位系统下,time_t也是有符号整数,但是占用8字节(64位),比如:typedef long long time_t;
使用64位有符号整数表示时间时,最多可以使用到世界标准时间(UTC)292,277,026,596年12月04日15时30分08秒。这基本不会遇到溢出问题,即使出现溢出以前,到时也会出现新的机器替代现有的计算机;
Unix时间戳不仅被使用在Unix系统、类Unix系统中,也在许多其它操作系统中被广告采用。
5、计算机中与时间有关的函数
5.1、time函数
在C语言中,time函数用于获取当前的Unix时间戳秒的部分(从1970-01-01 00:00:00 UTC到当前时刻的秒数)。这个函数定义在<time.h>头文件中,并返回一个time_t类型的值,函数原型如下:
time_t time(time_t * tloc);
参数:tloc是指向time_t类型变量的指针。如果非空,函数也会将同一个值写入该变量;如果传入NULL,则只通过返回值返回。
返回值:成功时返回当前时间戳,失败时返回 (time_t)-1。
5.2、localtime 函数
将 time_t 时间戳转换为本地时间,即根据系统设置的时区和夏令时规则,把绝对时刻换算成当地钟表显示的时间,结果放入 struct tm 结构体中。函数原型如下:
struct tm * localtime(const time_t *timep);
返回值:指向静态 struct tm 结构体的指针。
注意:该结构体是静态分配的,每次调用 localtime 都会覆盖之前的内容。如果需要可重入,应使用 localtime_r(Linux/Unix 下)或 localtime_s(Windows 下)。
5.3、gmtime 函数
gmtime 与 localtime 类似,但它将时间戳转换为 UTC 时间,不进行时区转换,原型如下:
struct tm * gmtime(const time_t *timep);
5.4、strftime 函数
C标准库 <time.h> 中用于将时间格式化为字符串的函数,功能强大且跨平台。原型如下:
size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr);
参数说明:
str:输出字符串的缓冲区。
maxsize:缓冲区最大字符数,防止越界。
format:格式控制字符串,由普通字符和格式说明符组成。
timeptr:指向 struct tm 的指针,通常由 localtime、gmtime 或 mktime 得到。
返回值:
成功时返回写入 str 的字符总数(不含结尾的 \0)。
如果结果超过了 maxsize,返回 0,且缓冲区内内容不确定。
strftime 会受当前 locale 影响:调用 setlocale(LC_TIME, "") 后,星期、月份等会显示本地语言。
5.5、GetSystemTimeAsFileTime函数
Windows下用来获取日期和时间的函数,原型如下:
VOID GetSystemTimeAsFileTime( [out] LPFILETIME lpSystemTimeAsFileTime);
参数:[out] lpSystemTimeAsFileTime,指向FILETIME结构的指针,用于接收 UTC 格式的当前系统日期和时间。
FILETIME结构体的定义如下:
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
该结构体占用8个字节(由两个4字节的双整数组成),表示自1601年1月1日 (UTC) 以来的100纳秒间隔数。
其中:
①dwLowDateTime:文件时间的低序部分
②dwHighDateTime:文件时间的高阶部分
如果追求更高的时间精度,可以使用GetSystemTimePreciseAsFileTime函数。该函数以最高精度 (<1us) 检索当前系统日期和时间。 检索到的信息采用协调世界时 (UTC) 格式。
说明:本文部分内容参考https://timewiki.org
北岛夜话



发表评论