C语言 mktime() gmtime()实现——亲测正确性

2023-11-18

前言

写此文章是因为有的嵌入式设备编程时不支持<time.h>,所以有些时间转换的函数必须自己实现。

关于<time.h>的使用,可以参考我的另一篇博客C语言常用时间相关函数

为了区别标准库函数,我们自定义的函数会加上self。

自定义的函数肯定会有人担心正确性,文末有验证测试代码。

在看代码之前,必须熟悉struct tm结构体

struct tm 
{
    int tm_sec;         /* 秒 – 取值区间为[0,59] */
    int tm_min;         /* 分 - 取值区间为[0,59] */
    int tm_hour;        /* 时 - 取值区间为[0,23] */
    int tm_mday;        /* 一个月中的日期 - 取值区间为[1,31] */
    int tm_mon;         /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
    int tm_year;        /* 年份,其值等于实际年份减去1900 */
    int tm_wday;        /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一 */
    int tm_yday;        /* 从每年1月1日开始的天数– 取值区间[0,365],其中0代表1月1日 */
    int tm_isdst;       /* 夏令时标识符,夏令时tm_isdst为正;不实行夏令时tm_isdst为0 */    
};

self_mktime()

unsigned int self_mktime(struct tm tm_now)
{
    const unsigned int year0 = tm_now.tm_year+1900;
    const unsigned int mon0 = tm_now.tm_mon+1;
    const unsigned int day = tm_now.tm_mday;
    const unsigned int hour = tm_now.tm_hour;
    const unsigned int min = tm_now.tm_min;
    const unsigned int sec = tm_now.tm_sec;
	unsigned int mon = mon0, year = year0;
 
	/* 1..12 -> 11,12,1..10 */
	if (0 >= (int) (mon -= 2)) {
		mon += 12;	/* Puts Feb last since it has leap day */
		year -= 1;
	}
 
	return ((((unsigned int)
		  (year/4 - year/100 + year/400 + 367*mon/12 + day) +
		  year*365 - 719499
	    )*24 + hour /* now have hours */
	  )*60 + min /* now have minutes */
	)*60 + sec; /* finally seconds */
}

self_gmtime()

void self_gmtime(struct tm *tm_time, unsigned int timestamp)
{
    unsigned int four_year_num;      // 有多少个四年
    unsigned int one_year_hours;     // 一年的小时数

    const static unsigned char Days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const static unsigned int ONE_YEAR_HOURS = 8760;        // 8760 = 365 * 24 (一年的小时数 非闰年)
    const static unsigned int FOUR_YEAR_HOURS = 35064;      // 35064 = (365 * 3 + 366) * 24 (四年的小时数)

    if (timestamp > 0x7FFFFFFF)
    {
        return;
    }
        
    tm_time->tm_isdst = 0;

    tm_time->tm_sec = (int)(timestamp % 60);                // 计算秒
    timestamp /= 60;
   
    tm_time->tm_min = (int)(timestamp % 60);                // 计算分
    timestamp /= 60;
   
    tm_time->tm_wday = (int)(timestamp/24 + 4) % 7;         // 计算星期 1970年1月1日星期四
   
    four_year_num = timestamp / FOUR_YEAR_HOURS;    
   
    tm_time->tm_year=(four_year_num << 2) + 70;             // 计算年
   
    timestamp %= FOUR_YEAR_HOURS;                           // 不足四年的小时数
   
    while (1)
    {
        one_year_hours = ONE_YEAR_HOURS;
       
        if ((tm_time->tm_year & 3) == 0)                    // 判断闰年
        {
            one_year_hours += 24;
        }

        if (timestamp < one_year_hours)
        {
            break;
        }

        tm_time->tm_year++;
        timestamp -= one_year_hours;
    }

    tm_time->tm_hour=(int)(timestamp % 24);                 // 计算时

    timestamp /= 24;                                        // 一年中剩下的天数
    timestamp++;
  
    tm_time->tm_yday = timestamp-1;                         // 计算天

    if ((tm_time->tm_year & 3) == 0)                        // 闰年处理
    {
        if (timestamp > 60)
        {
            timestamp--;                                    // 因为有1月29日的存在
        }
        else if (timestamp == 60)
        {
            tm_time->tm_mon = 1;                            // 计算月
            tm_time->tm_mday = 29;                          // 计算日
            return;
        }
    }

    // 计算日月
    for (tm_time->tm_mon = 0; Days[tm_time->tm_mon] < timestamp; tm_time->tm_mon++)
    {
        timestamp -= Days[tm_time->tm_mon];
    }

    tm_time->tm_mday = (int)(timestamp);
}

测试代码

平台:Windows10
CPU:i5-7400
GCC: 8.1.0
耗时:246.441秒
结果:输出passed,通过!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int main()
{
    time_t i;
    struct tm test_time1, *test_time2;
    unsigned int test_timestamp;

    for (i = 0; i <= 0x7FFFFFFF; i++)
    {
        self_gmtime(&test_time1, i);
        test_time2 = gmtime(&i);

        if (test_time1.tm_year != test_time2->tm_year ||\
            test_time1.tm_mon != test_time2->tm_mon ||
            test_time1.tm_mday != test_time2->tm_mday ||
            test_time1.tm_hour != test_time2->tm_hour ||
            test_time1.tm_min != test_time2->tm_min ||
            test_time1.tm_sec != test_time2->tm_sec ||
            test_time1.tm_wday != test_time2->tm_wday ||
            test_time1.tm_yday != test_time2->tm_yday)
        {
            printf("gmtime not passed i = %ld\r\n", i);
            break;
        }

        test_timestamp = self_mktime(test_time1);

        if (test_timestamp != i)
        {
            printf("mktime not passed i = %ld\r\n", i);
            break;
        }
    }

    if (i > 0x7FFFFFFF)
    {
        printf("passed\r\n");
    }
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言 mktime() gmtime()实现——亲测正确性 的相关文章

随机推荐

  • pyodbc操作Access数据库

    现在各种各样的数据库层出不穷 什么MySQL PostgreSQL MongoDB这些都是比较火的 还有一些稍微小众一点的数据库就更多了 相比之下 微软Office套件里面附带的Access数据库究落寞了很多 不过好歹Access数据库还是
  • 【图像处理】图像二值化----otsu(最大类间方差法、大津算法)

    转载 https blog csdn net abcjennifer article details 6671288 最大类间方差法是由日本学者大津于1979年提出的 是一种自适应的阈值确定的方法 又叫大津法 简称OTSU 它是按图像的灰度
  • Bicubic Interpolation (双三次插值)

    在Wikipedia http en wikipedia org wiki Bicubic interpolation 上找到了bicubic的描述 不过它只给出了知道导数情况下的公式 后来在CSDN上找到了C语言的算法描述 http to
  • k8s-node节点未找到flannel网络

    k8s node节点的flannel的IP地址不正确 问题描述 问题分析 1 检查node节点的cni和flannel网卡地址 2 检查master节点的flannel服务 如何重置flannel网络 1 删除node节点 master 2
  • unity中Input.Touch详解

    相关的api 1 Touch类 用来记录一个手指触摸在屏幕上的状态与位置的各种相关数据 这其它中只有两个属性是你要注意的 就是Touch fingerId和Touch tapCount Touch fingerId 一个Touch的标识 I
  • Linux常用压缩命令(tar,tgz,gzip,zip,rar)

    Linux常用于压缩和解压tar tgz gzip zip rar 一 tar 1 压缩命令 tar cvf examples tar files dir files dir表示要压缩文件或者目录 说明 c create create a
  • llama.cpp试用

    显存占用是真的低 13B vicuna int4量化 example chat 13B sh 正常问答交流 不到2G的占用 相比之下 vicuna7B原版int8量化 8G显卡下 cuda会OOM 原版不支持int4量化 chatglm6B
  • Android应用底部导航栏(选项卡)实例

    现在很多android的应用都采用底部导航栏的功能 这样可以使得用户在使用过程中随意切换不同的页面 现在我采用TabHost组件来自定义一个底部的导航栏的功能 我们先看下该demo实例的框架图 其中各个类的作用以及资源文件就不详细解释了 还
  • Denoising diffusion implicit models 阅读笔记

    Denoising diffusion probabilistic models DDPMs 从马尔科夫链中采样生成样本 需要迭代多次 速度较慢 Denoising diffusion implicit models DDIMs 的提出是为
  • 其他需要整理

    1 Kinect OpenNI学习笔记之6 获取人体骨架并在Qt中显示 http www cnblogs com tornadomeet archive 2012 10 03 2710737 html
  • 人脸识别产品相关知识整理

    引言 这个文章是我18年初整理的一个基础人脸识别产品知识 人脸识别规范 标准和白皮书 我在工标网站上找到了公安部的 GA T 1093 2013 出入口控制人脸识别系统技术要求 和 GA T 1126 2013 近红外人脸识别设备技术要求
  • 理解Java的IO 流

    按照流的流向来分 可以分为输入流和输出流 输入流 只能从中读取数据 而不能向其中写数据 输出流 只能向其写出数据 而不能从中读取数据 对于上面的左图来说 数据从内存到硬盘 通常我们称为输出流 也就是说 这里的输出 都是从程序运行所在的内存角
  • hive中如何取到每个顾客最新交易

    hive e use db select t advertId t exposureNum from select advertId exposureNum ROW NUMBER OVER PARTITION BY advertId ORD
  • 《计算机网络》——第四章知识点

    第四章思维导图如下 网络层向上只提供灵活的 无连接的 尽最大努力交付的数据报服务 主要任务是把分组 IP数据报 从通过路由选择与转发从源端传到目的端 为分组交换网上的不同主机提供通信服务 互联网可以由多种异构网络互连组成 IP数据包格式 I
  • 【突变检验方法二】MATLAB实现贝叶斯突变检测

    MATLAB实现贝叶斯突变检测 1 贝叶斯突变检测 2 原理 3 MATLAB相关代码 3 1 调用函数 3 2 案例 参考 另 其它语言实现贝叶斯突变检测 1 贝叶斯突变检测 贝叶斯突变检测属于概率突变检测方法 其特点是能给出突变点的概率
  • json数据如何存入到cookie中,如何获取

    1 引入相对应的cookie js插件如下 例如 button click function var username input name username val var password input name password val
  • scrapy爬虫爬取多网页内容

    摘要 此案例是爬取目标网站 https tipdm com 的新闻中心板块的公司新闻中所有新闻的标题 发布时间 访问量和新闻的文本内容 1 创建scrapy项目 我使用的是 Anaconda prompt 我们使用如下命令创建scrapy项
  • 视线估计、凝视目标估计相关评价指标

    1 TP TN FP FN qquad T F表示待分类目标的GT值 qquad P N表示预测到目标的正反例 在目标检测类任务中 qquad TP 表示正确检测到待检测目标
  • vcruntime140_1.dll丢失怎么办?vcruntime140_1.dll丢失最新解决方法

    如果您在使用某些软件或游戏时遇到了 vcruntime140 1 dll丢失 的错误提示 那么您需要采取一些措施来解决这个问题 以下三种解决方案都能解决vcruntime140 1 dll丢失问题 第一种解决方法 直接使用dll修复程序进行
  • C语言 mktime() gmtime()实现——亲测正确性

    前言 写此文章是因为有的嵌入式设备编程时不支持