Ubuntu 下 nginx-1.24.0 源码分析 - ngx_localtime 函数

news2025/2/14 5:15:40

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_r

localtime_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_gmtimengx_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_gmtimengx_localtime,Nginx 能够在不同场景下正确处理时间,避免因时区差异导致的错误或混淆。例如:

  • 如果所有时间都使用本地时间,可能会导致跨时区部署的系统出现不一致。
  • 如果所有时间都使用 UTC 时间,可能会让管理员难以理解日志中的时间信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2297723.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

公然上线传销项目,Web3 的底线已经被无限突破

作者:Techub 热点速递 撰文:Yangz,Techub News 今天早些时候,OKX 将上线 PI 的消息在圈内引起轩然大波,对于上线被板上钉钉为传销盘子的「项目」 ,Techub News 联系了 OKX 公关,但对方拒绝置评…

C语言第18节:自定义类型——联合和枚举

1. 联合体 C语言中的联合体(Union)是一种数据结构,它允许在同一内存位置存储不同类型的数据。不同于结构体(struct),结构体的成员各自占有独立的内存空间,而联合体的所有成员共享同一块内存区域…

解锁网络安全:穿越数字世界的防护密码

个人主页:java之路-CSDN博客(期待您的关注) 目录 网络安全:数字时代的基石 网络安全面面观 (一)定义与范畴 (二)发展历程 网络安全面临的威胁 (一)恶意软件肆虐 (二…

python爬虫解决无限debugger问题

方法一 关闭定时任务 关闭断点执行代码打开断点 # 无限debugger产生原因 # 1. web开发者工具打开 # 2. js代码中有debugger # 3. js有定时处理[推荐] for(let i0;i<99999;i){window.clearInterval(i)}方法二 关闭breakpoint 方法三 修改JS代码 使用fiddler&#xff0c;抓…

C# 两种方案实现调用 DeepSeek API

目录 序 开发运行环境 访问API的一个通用方法 原生官网实现 申请 API key 调用实现 调用示例 腾讯云知识引擎原子调用 申请 API key 调用示例 小结 序 DeepSeek&#xff08;深度求索&#xff09; 最近可谓火爆的一塌糊涂&#xff0c;具体的介绍这里不再赘述&#x…

Linux下的进程切换与调度

目录 1.进程的优先级 优先级是什么 Linux下优先级的具体做法 优先级的调整为什么要受限 2.Linux下的进程切换 3.Linux下进程的调度 1.进程的优先级 我们在使用计算机的时候&#xff0c;通常会启动多个程序&#xff0c;这些程序最后都会变成进程&#xff0c;但是我们的硬…

anolis os 8.9安装jenkins

一、系统版本 # cat /etc/anolis-release Anolis OS release 8.9 二、安装 # dnf install -y epel-release # wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo # rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.…

Java基础知识总结(四十八)--TCP传输、TCP客户端、TCP服务端

**TCP传输&#xff1a;**两个端点的建立连接后会有一个传输数据的通道&#xff0c;这通道称为流&#xff0c;而且是建立在网络基础上的流&#xff0c;称之为socket流。该流中既有读取&#xff0c;也有写入。 **tcp的两个端点&#xff1a;**一个是客户端&#xff0c;一个是服务…

【python】http.server内置库构建临时文件服务

需要从linux开发机上下载一个文件到本地&#xff0c;约700M比较大&#xff0c;通过sz命令下载较慢且传输过程不稳定连续失败&#xff0c;后采用下面方式解决。 cd到一个目录下执行python -m http.server port&#xff0c;port为服务的端口号&#xff1a; 启动后浏览器中访问…

网络安全ids是什么意思

1、 简述IPS和IDS的异同点&#xff1b; 入侵检测系统&#xff08;IDS&#xff09; IDS&#xff08;Intrusion Detection Systems&#xff0c;入侵检测系统&#xff09;&#xff0c;专业上讲就是依照一定的安全策略&#xff0c;对网络、系统、运行状况进行监视&#xff0c;尽可能…

优选驾考小程序

第2章 系统分析 2.1系统使用相关技术分析 2.1.1Java语言介绍 Java语言是一种分布式的简单的 开发语言&#xff0c;有很好的特征&#xff0c;在安全方面、性能方面等。非常适合在Internet环境中使用&#xff0c;也是目前企业级运用中最常用的一个编程语言&#xff0c;具有很大…

42.水果销售系统(springbootvue的Java项目[含微信小程序])

目录 1.系统的受众说明 2.开发环境与技术 2.1 MYSQL数据库 2.2 Java语言 2.3 微信小程序技术 2.4 SpringBoot框架 2.5 B/S架构 2.6 Tomcat 介绍 2.7 HTML简介 2.8 MyEclipse开发工具 3.系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2 经济可行性 3.1.3 操作…

ffmpeg所有版本下载地址

地址如下&#xff1a;Index of /releaseshttps://ffmpeg.org/releases/

记PasteSpider部署工具的Windows.IIS版本开发过程之草稿-效果展示(4)

如果有人给你一串JSON数据,你需要编辑他,对于有开发基础的人来说,可能会好处理下,而对于没有开发基础的人来说,那就是灾难了! 那么有没有一个东西,可以让这个编辑更顺畅呢? 贴代码案例中的DynamicForm你值得拥有!本次展示作者在本机上操作IIS的示例,如下 IIS展示 先…

3D文档控件Aspose.3D实用教程: 在 Java 中创建 FBX 文件并无缝将圆柱体转换为网格

概述 创建FBX文件并将圆柱体转换为网格是 3D 建模和动画中的基本任务。这些过程在游戏、电影和建筑等行业中至关重要。通过使用Aspose.3D for Java &#xff0c;开发人员可以高效地管理 3D 场景和对象。这个强大的 Java 3D API 简化了 3D 模型的创建和操作。它的易用性和灵活性…

软考高级《系统架构设计师》知识点(一)

计算机硬件 校验码 码距&#xff1a;就单个编码A:00而言&#xff0c;其码距为1&#xff0c;因为其只需要改变一位就变成另一个编码。在两个编码中&#xff0c;从A码到B码转换所需要改变的位数称为码距&#xff0c;如A:00要转换为B:11&#xff0c;码距为2。一般来说&#xff0c;…

HTML 学习记录

HTML 学习记录 html是超文本标记语言&#xff0c;是一种标记语言 超文本&#xff1a;链接 标记&#xff1a;也叫标签&#xff0c;带尖括号的文本 标签语法 1.标签成对出现&#xff0c;中间包裹内容 2.<>里面放英文字母 3.结束标签比开始标签多一个 / 例如 <s…

Mac之JDK安装

Mac之JDK安装 一.安装 jdk 打开终端输入命令:java -version 查看是否已安装 JDK Oracle 官方下载地址 根据自己Mac 系统安装 查看 Mac 系统&#xff0c;打开中断命令&#xff0c;输入: uname -a Compressed Archive 是压缩文档&#xff0c;下载的是一个 .tar.gz 压缩包 D…

centos 10 离线安装dnf 和 设置dnf镜像源

离线安装dnf可用kimi搜索, centos 使用curl 下载dnf 的rpm包 mkdir ~/dnf_packages cd ~/dnf_packages# CentOS 7 示例 curl -O http://springdale.math.ias.edu/data/puias/unsupported/7/x86_64/dnf-0.6.4-2.sdl7.noarch.rpm curl -O http://springdale.math.ias.edu/data/pu…

【cocos creator】拖拽排序列表

DEMO下载 GameCtrl.ts import ItemCtrl from "./ItemCtrl";const { ccclass, property } cc._decorator;ccclass export default class GameCtrl extends cc.Component {property(cc.Node)content: cc.Node null;property(cc.Node)prefab: cc.Node null;arr []…