Ubuntu下nginx-1.24.0源码分析-ngx_localtime函数
- 互联网
- 2025-09-06 17:09:01

ngx_localtime 函数 声明
在 src\os\unix\ngx_time.h 中:
void ngx_localtime(time_t s, ngx_tm_t *tm); 定义在 src/os/unix/ngx_time.c 中
void ngx_localtime(time_t s, ngx_tm_t *tm) { #if (NGX_HAVE_LOCALTIME_R) (void) localtime_r(&s, tm); #else ngx_tm_t *t; t = localtime(&s); *tm = *t; #endif tm->ngx_tm_mon++; tm->ngx_tm_year += 1900; }ngx_localtime 函数的主要作用是
将时间戳 time_t 转换为本地时间结构体 ngx_tm_t 的函数实现。它的主要作用是将一个 Unix 时间戳(自 1970 年 1 月 1 日以来的秒数)转换为本地时间,并对结果进行一些调整,使其更符合人类可读的时间格式
将传入的 time_t 类型的时间戳 s 转换为本地时间。
将转换后的本地时间存储到 ngx_tm_t 类型的结构体 tm 中。
对转换后的月份和年份字段进行调整,以符合常见的日期表示方式。
#if (NGX_HAVE_LOCALTIME_R) (void) localtime_r(&s, tm); #else ngx_tm_t *t; t = localtime(&s); *tm = *t; #endif条件编译判断系统是否支持 localtime_r 函数
通过宏 NGX_HAVE_LOCALTIME_R 判断当前系统是否支持线程安全的 localtime_r 函数。
如果支持 localtime_r:直接调用 localtime_r 函数将 time_t 类型的时间戳 s 转换为本地时间,并将结果存储在 ngx_tm_t 结构体 tm 中。(void) 强制类型转换用于避免编译器产生未使用返回值的警告。
如果不支持 localtime_r:使用非线程安全的 localtime 函数进行时间转换。
localtime 返回一个指向静态内存的指针,因此在多线程环境中可能会引发竞争问题。
为了确保线程安全,这里将返回的结果复制到用户提供的 tm 结构体中,避免直接依赖静态内存。
objs/ngx_auto_config.h:282:#define NGX_HAVE_LOCALTIME_R 1
在 objs/ngx_auto_config.h 中:
#ifndef NGX_HAVE_LOCALTIME_R #define NGX_HAVE_LOCALTIME_R 1 #endif所以
#if (NGX_HAVE_LOCALTIME_R) (void) localtime_r(&s, tm);这部分成立,使用 localtime_r
可用 gcc -E 将宏展开来确认
gcc -E src/os/unix/ngx_time.c \ -I src/core \ -I src/event \ -I src/event/modules \ -I src/os/unix \ -I objs \ > ngx_time_preprocessed.c在输出文件 ngx_time_preprocessed.c 中找到 ngx_localtime 函数
void ngx_localtime(time_t s, ngx_tm_t *tm) { (void) localtime_r(&s, tm); # 70 "src/os/unix/ngx_time.c" tm->tm_mon++; tm->tm_year += 1900; }的确使用的是 localtime_r
调整月份和年份
tm->ngx_tm_mon++; tm->ngx_tm_year += 1900; 调整月份:struct tm 结构体中的 tm_mon 成员表示月份,其取值范围是 0 - 11(0 表示 1 月,11 表示 12 月)。为了符合常规的月份表示方式(1 - 12),将 ngx_tm_mon 加 1。年份调整 :返回的年份是从 1900 年开始的偏移量(例如,2023 年对应的是 123)。为了得到完整的年份,需要加上 1900。 localtime_rlocaltime_r 是一个线程安全的函数,用于将时间戳(time_t 类型)转换为本地时间,并将结果存储到用户提供的 struct tm 结构体中。它是 POSIX 标准定义的函数之一,广泛用于多线程环境下的时间处理
函数原型 struct tm *localtime_r(const time_t *timep, struct tm *result); timep:指向一个 time_t 类型的时间戳,表示自 1970 年 1 月 1 日(UTC 时间)以来的秒数。result:指向一个用户提供的 struct tm 结构体,用于存储转换后的本地时间。返回值 :
成功时,返回 result 的指针(即输入的第二个参数)。失败时,返回 NULL,通常是因为输入的时间戳无效或系统资源不足 与 localtime 函数的区别localtime 函数也用于将 time_t 时间戳转换为本地时间,但它是非线程安全的。localtime 函数内部使用一个静态分配的 struct tm 结构体来存储转换结果,这意味着在多线程环境下,如果多个线程同时调用 localtime 函数,它们可能会覆盖彼此的结果,从而导致数据竞争和不一致的问题。
而 localtime_r 函数是线程安全的,因为它需要用户传入一个 struct tm 结构体的指针,函数会将转换结果直接填充到这个用户提供的结构体中,不同线程可以使用不同的 struct tm 结构体实例,避免了数据竞争的问题。
转换后的本地时间会被分解并填充到 struct tm 的各个字段中,例如年、月、日、小时、分钟等
localtime_r函数转换后的月份字段
它的取值范围是 0 到 11
这里 0 代表 1 月,1 代表 2 月,以此类推,11 代表 12 月
这种表示方式是为了与数组索引的习惯保持一致,因为在很多计算中,从 0 开始计数更方便。
localtime_r函数转换后的年份字段
它的值是从 1900 年开始的偏移量 。
例如:
tm_year = 123 表示 2023 年 (因为 1900 + 123 = 2023)。
tm_year = 0 表示 1900 年 。
ngx_gmtime 和 ngx_localtime 这两个函数虽然表面上看起来作用相似(都是将时间戳转换为时间结构体),但它们的实际用途和行为是有区别的
ngx_gmtime:格林威治标准时间(GMT)功能:将时间戳转换为 GMT 时间(UTC+0),与时区无关
使用场景:生成 HTTP 响应头中的时间(如 Date 字段),需遵循 GMT 标准
ngx_localtime:本地时间
功能:将时间戳转换为本地时间(依赖系统时区或配置)
表示的是 服务器所在时区的本地时间 。
使用场景:用于日志记录、调试信息等需要显示本地时间的场景
关键区别 函数时区处理主要用途ngx_gmtime固定为 GMT(UTC+0)HTTP 协议时间、跨时区一致性ngx_localtime依赖系统或配置的时区本地日志、用户可见时间 为什么需要两个函数? (1) HTTP 协议的要求
HTTP 协议中某些头部字段(如 Date)明确要求使用 UTC 时间。
例如:
Date: Sun, 01 Oct 2023 12:00:00 GMT
在这种情况下,必须使用 ngx_gmtime 来生成符合标准的时间字符串。
(2) 日志记录的需求Nginx 的日志文件通常需要记录事件发生的本地时间,以便管理员更容易理解日志内容。
例如:
2023/10/01 20:00:00 [error] ...
在这种情况下,使用 ngx_localtime 更加合适,因为它可以反映服务器所在时区的时间。
(3) 避免时区混淆通过区分 ngx_gmtime 和 ngx_localtime,Nginx 能够在不同场景下正确处理时间,避免因时区差异导致的错误或混淆。例如:
如果所有时间都使用本地时间,可能会导致跨时区部署的系统出现不一致。如果所有时间都使用 UTC 时间,可能会让管理员难以理解日志中的时间信息。Ubuntu下nginx-1.24.0源码分析-ngx_localtime函数由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Ubuntu下nginx-1.24.0源码分析-ngx_localtime函数”