当前位置: 首页 > article >正文

[底层原理] C/C++获取时间(将时间戳转换为年月日)?

前言

大家都知道,计算机中存储的时间是一个整数,在现在的编程语言中,可以很方便地将时间戳(整数)转换为字符串,但是如果没有这些我们该如何自己计算出呢?

刚好以前研究过Nginx的源代码,我以他的代码为例,说明其背后的数学原理。当然在工程实践中,没有必要花时间自己实现转换的函数,所以本文用作一些底层原理的研究,说明计算机的背后其实是数学的原理组成的。

我这里采用C语言,如果是其他语言,也是类似的转换方法。

 本文分为两个部分源代码和源代码解析。

环境:Visual Studio 2022,Win11

为了方便后面解析,说明我写代码当天时间是:2024年08月24日,周六

源代码

为了能够在一个单独的console环境中展示,那么我对源代码的命名放在了一起,以下是一个演示的完整代码:

#include <iostream>
#include <ctime>
using namespace std;
typedef struct tm             ngx_tm_t;
typedef intptr_t        ngx_int_t;
void
ngx_gmtime(time_t t, ngx_tm_t* tp)
{
    ngx_int_t  sec, min, hour, mday, mon, year, wday, yday, days;

    days = t / 86400;

    /* Jaunary 1, 1970 was Thursday */
    wday = (4 + days) % 7;

    t %= 86400;
    hour = t / 3600;
    t %= 3600;
    min = t / 60;
    sec = t % 60;

    /* the algorithm based on Gauss's formula */

    days = days - (31 + 28) + 719527;

    year = days * 400 / (365 * 400 + 100 - 4 + 1);
    yday = days - (365 * year + year / 4 - year / 100 + year / 400);

    mon = (yday + 31) * 12 / 367;
    mday = yday - (mon * 367 / 12 - 31);

    mon += 2;

    if (yday >= 306) {

        /*
         * there is no "yday" in Win32 SYSTEMTIME
         *
         * yday -= 306;
         */

        year++;
        mon -= 12;

        if (mday == 0) {
            /* Jaunary 31 */
            mon = 1;
            mday = 31;

        }
        else if (mon == 2) {

            if ((year % 4 == 0) && (year % 100 || (year % 400 == 0))) {
                if (mday > 29) {
                    mon = 3;
                    mday -= 29;
                }

            }
            else if (mday > 28) {
                mon = 3;
                mday -= 28;
            }
        }
        /*
         *  there is no "yday" in Win32 SYSTEMTIME
         *
         *  } else {
         *      yday += 31 + 28;
         *
         *      if ((year % 4 == 0) && (year % 100 || (year % 400 == 0))) {
         *          yday++;
         *      }
         */
    }

    tp->tm_sec = (int)sec;
    tp->tm_min = (int)min;
    tp->tm_hour = (int)hour;
    tp->tm_mday = (int)mday;
    tp->tm_mon = (int)mon;
    tp->tm_year = (int)year;
    tp->tm_wday = (int)wday;
}


int main()
{
    std::time_t now = std::time(nullptr);
 
    ngx_tm_t t;
    ngx_gmtime(now, &t);

    // 中国属于东八区,所以我在hour加了一个8
    std::cout << t.tm_year << "年" << t.tm_mon << "月" << t.tm_mday  << "日 " 
              << t.tm_hour + 8 << ":" << t.tm_min << ":" << t.tm_sec;

    getchar();

}

效果如下,和我的预期一致:

 

源代码解析

先看第11行如下,86400属于什么呢?我直接问gpt,说明是一天的秒数,经过计算确实如此。1 天 = 24 × 60 × 60 秒 = 86400秒。第一步nginx算出了当天到1970年的第一天差距了多少天,

days = t / 86400;

debug查看days的值为19959,也就是说2024年8月24日减去1970年1月1日为19959天:

14行:

wday代表今天是星期几,因为1970年的7月1日为星期四,所以使用上面得到的天数加上4然后余7,得到了wday为6。

wday = (4 + days) % 7;

 

16-17行,执行16行代码后,t 的值会被更新为 t 除以 86400 的余数。这实际上是将时间戳 t 转换为了从当天午夜(00:00:00)开始计算的秒数。换句话说,这行代码去除了时间戳中的日期部分,只保留了时间部分(以秒为单位)。

所以17行除一个小时的秒数,1600秒,得到今天是几点钟了,

t %= 86400;
hour = t / 3600;

debug发现是10点,因为计算机内部时间戳是UTC格式,中国属于东八区,所以其实是18点 ,我后续输出的时候对小时加了一个8。

18-20行,这个时候,t已经是当天过了多少秒了,分钟和秒数以此类推

t %= 3600; // 获取除开小时的秒数
min = t / 60; // 获取当前的分钟数
sec = t % 60; // 获取秒数

到这里已经获取了小时,分钟,秒数、星期几,接下来就是获取年、月、日。

24行

days = days - (31 + 28) + 719527;

经过查找资料才明白 719527 是从公元前1年3月1日到1970年3月1日的天数。所以这行代码是将days改为从公元当天开始到现在的天数。

后续的代码,我后面再继续研究,因为哪个公式看不看懂,也搜索不到。


http://www.kler.cn/news/282898.html

相关文章:

  • EmguCV学习笔记 VB.Net 7.2 特征点检测
  • Java之内部类
  • 浅谈Kafka(三)
  • 深度学习基础--深度学习网络
  • 服务器内存飙升分析小记
  • PostgreSQL遍历所有的表并设置id为自增主键(基于自建函数)
  • FineReport帆软报表:使用JAVA批量更新报表里的数据集连接名
  • 【python量化分析专题】最新整理的已经实测可用的各类免费股票数据接口之实时交易数据
  • 『大模型笔记』林纳斯·托瓦兹(Linux之父):谈论热议与人工智能的未来!
  • Linux 网络技术栈,看这篇就够了!!
  • 【ACM独立出版 | 厦大主办】第五届计算机科学与管理科技国际学术会议(ICCSMT 2024,10月18-20)
  • 基于web 在线影院系统网站设计与实现
  • 交通流量监测检测系统源码分享 # [一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]
  • Qt 调用执行 Python 函数
  • zookeeper服务器动态上下线监听案例
  • 【MySQL数据库管理问答题】第4章 配置 MySQL
  • SpringBoot应用打成ZIP部署包
  • 18.神经网络 - 非线性激活
  • 【机器学习】梯度下降算法
  • 源码编译并安装Squid的方法
  • BEVDet4D:多帧时序信息融合方法详解
  • 富格林:正规方式顺利盈利出金
  • 性能测试的基本概念
  • Pycharm安装报错:Cannot detect a launch configuration 解决办法
  • 吴恩达机器学习笔记 四十五 基于内容的过滤的tensorFlow实现
  • 怎么解决 hash 碰撞,用 C++ 实现 hashMap?
  • Nosql数据库redis集群配置详解
  • Nginx轮询负载均衡配置指南:实现高效请求分发
  • docker常用命令使用dockerfile构建镜像,推送到私有镜像仓库
  • 【AI绘画】Midjourney前置指令/describe、/shorten详解