C/C++ 实现时间戳和时间结构体的相互转换、格林威治与本地时间的转换

2023-10-29

C/C++ 实现时间戳和时间结构体的相互转换、格林威治与本地时间的转换


时间是具有周期性的,每间隔四年为一个闰年,时间戳是以1970/1/1 00:00:00开始到当前时间的秒数。

查看日历你会发现:

  • 1970年为平年
  • 1971年为平年
  • 1972年为闰年
  • 1973年为平年

四年加起来一共365*3+366=1461天。

这就是时间周期,后面写程序会用到。


时间结构与时间戳互转函数实现Demo如下:

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

/*
 * 一个自然周期为4年,包含3个平年一个闰年
 */
#define CYCLE_DAYS    (1461U)                       /* (365 * 4 + 1)                */
#define CYCLE_HOURS   (35064U)                      /* (365 * 4 + 1) * 24           */
#define CYCLE_MINUTES (2103840U)                    /* (365 * 4 + 1) * 24 * 60      */
#define CYCLE_SECPNDS (126230400U)                  /* (365 * 4 + 1) * 24 * 60 * 60 */

#define TIMEZONE      (28800UL)                      /* 8个小时的秒数。东八区快8个小时,东正西负   */

typedef struct
{
	int year;              /* 年,四位数年份 */
	int mon;               /* 月,范围1~12 */
	int mday;              /* 日,范围1~31 */
	int hour;              /* 时,范围1~24 */
	int min;               /* 分,范围1~59 */
	int sec;               /* 秒,范围1~59 */
	int wday;              /* 周几,范围0~6,0表示星期天 */
	int yday;              /* 一年中的第几天,范围1~366 */
}ctime_t;

/**
 * 根据传入的日期计算星期几,返回值范围0~6,0表示星期天
 */
uint8_t WeekDayNum(uint32_t nYear, uint8_t nMonth, uint8_t nDay)
{
  uint32_t weekday = 0U;

  if (nMonth < 3U)
  {
    /*D = { [(23 x month)/9] + day + 4 + year + [(year-1)/4] - [(year-1)/100] + [(year-1)/400] } mod 7*/
    weekday = (((23U * nMonth) / 9U) + nDay + 4U + nYear + ((nYear - 1U) / 4U) - ((nYear - 1U) / 100U) + ((nYear - 1U) / 400U)) % 7U;
  }
  else
  {
    /*D = { [(23 x month)/9] + day + 4 + year + [year/4] - [year/100] + [year/400] - 2 } mod 7*/
    weekday = (((23U * nMonth) / 9U) + nDay + 4U + nYear + (nYear / 4U) - (nYear / 100U) + (nYear / 400U) - 2U) % 7U;
  }

  return (uint8_t)weekday;
}

/**
 * 将时间戳转成ctime_t结构
 */
void timepack(uint32_t timestamp, ctime_t* t)
{
	uint32_t year,mon,mday,hour,min,sec,yday,wday,dayOfCycle,i,cycle,day=0;
	uint8_t days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

	sec = timestamp % 60;   /* 秒 */
	timestamp /= 60;

	min = timestamp % 60;  /* 分 */
	timestamp /= 60;

	hour = timestamp % 24;  /* 时 */
	timestamp /= 24;

	cycle      = timestamp / CYCLE_DAYS;  /* 自1970年到现在已经过去的周期数(一个周期为4年) */
	dayOfCycle = timestamp % CYCLE_DAYS;  /* 本周期内已过的天数 */

	if(dayOfCycle < 365)                                             /* 周期内的第一年为平年 */
	{
		year = 1970 + cycle * 4;  /* 年 */
		yday = dayOfCycle + 1;    /* 本年度的第几天 */
	}else if(dayOfCycle >= 365 && dayOfCycle < 730)                  /* 周期内的第二年为平年 */
	{
		year = 1970 + cycle * 4 + 1;
		yday = dayOfCycle - 365 + 1;
	}else if(dayOfCycle >= 760 && dayOfCycle < 1096)                 /* 周期内的第三年为闰年 */
	{
		year = 1970 + cycle * 4 + 2;
		yday = dayOfCycle - 760 + 1;
	}else                                                            /* 周期内的第四年为平年 */
	{
		year = 1970 + cycle * 4 + 3;
		yday = dayOfCycle - 1096 + 1;
	}

    if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))) /* 判断是否是闰年 */
        days[1] = 29;

	for(i = 0; i < 12; i++)
	{
		day += days[i];
		if(day >= yday)
		{
			mon  = i + 1;                               /* 月 */
			mday = days[i] - (day - yday);              /* 日 */
			break;
		}
	}

	wday = WeekDayNum(year, mon, mday);  /* 周几 */

	if(t != NULL)
	{
		t->year = year;
		t->mon  = mon;
		t->mday = mday;
		t->hour = hour;
		t->min  = min;
		t->sec  = sec;
		t->wday = wday;
		t->yday = yday;
	}
}

/**
 * 将ctime_t结构还原成时间戳
 */
uint32_t timeunpack(const ctime_t *t)
{
	uint32_t i = 0, days = 0, timestamp = 0;
    uint8_t mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	for(i = 1970; i < t->year; i++)
	{
		if((i % 400 == 0) || ((i % 4 == 0) && (i % 100 != 0)))  /* 判断是否是闰年 */
			days += 366;
		else
			days += 365;
	}
    if((t->year % 400 == 0) || ((t->year % 4 == 0) && (t->year % 100 != 0)))  /* 判断是否是闰年 */
    	mdays[1] = 29;
	for(i = 0; i < t->mon - 1; i++)
		days += mdays[i];
	days += (t->mday - 1);
	timestamp = days * 24 * 60 * 60;
	timestamp += t->hour * 60 * 60;
	timestamp += t->min * 60;
	timestamp += t->sec;
	return timestamp;
}

int main(void)
{
	ctime_t t;
	time_t timestamp;
	static const char* wday[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

	/* 获取时间戳,time函数返回的是自<1970/01/01 00:00:00>的秒数 */
	timestamp = time(NULL);

	printf("timestamp = %ld \n", timestamp);
	fflush(stdout);

	/* 北京时间为东八区,比UTC时间快了正好8小时,所以需要加上8个小时的秒数 */
	timestamp += TIMEZONE;

	/* 时间戳转成时间结构 */
	timepack(timestamp, &t);

    printf("%04d/%02d/%02d %02d:%02d:%02d %s \n",
    		t.year,
    		t.mon,
			t.mday,
			t.hour,
			t.min,
			t.sec,
			wday[WeekDayNum(t.year, t.mon, t.mday)]);
    fflush(stdout);

    /* 测试将时间结构转回时间戳 */
    timestamp = timeunpack(&t) - TIMEZONE;

    printf("timestamp = %ld \n", timestamp);
    fflush(stdout);

	return 0;
}

运行结果:


ends…

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C/C++ 实现时间戳和时间结构体的相互转换、格林威治与本地时间的转换 的相关文章

随机推荐

  • 吊打 CLIP 平均10个点,Meta 多模态通用模型 FLAVA真香啊

    厉害了 作者将单一模型运用于三个不同领域的不同任务 结构简单且训练直观 还能有着出色的表现 自Transformer横空出世 从NLP到CV 再到今天的多模态 无数基于Transformer的模型被应用于各类任务 似乎真的印证了当年文章的标
  • ldd not a dynamic executable

    在开发环境编译运行很ok的程序 到了客户的生产环境一直有问题 编译找不到库 类似这个样子 usr bin ld skipping incompatible lib libasound so when searching for lasoun
  • EXCEL-VBA:Workbooks.Open 参数 (打开文件)

    打开一个工作簿 语法 表达式 Open FileName UpdateLinks ReadOnly Format Password WriteResPassword IgnoreReadOnlyRecommended Origin Deli
  • UE5导入倾斜摄影

    前言 虚幻引擎是全球最先进的实时3D创作工具 可制作照片级逼真的视觉效果和沉浸式体验 2022年4月5号虚幻引擎发布了颠覆性的UE5 倾斜摄影是城市实景的基础 通过无人机采集实际照片再进行三维重建 常见的数据格式为osgb 本文主要介绍UE
  • JSP自定义标签的(生命周期与开发if,foreach,out)

    自定义标签定义 是用户定义的JSP语言元素 扩展名为tld的文件 tag标签的配置文件 通常放在WEB INF下面 自定义标签的开发及使用步骤 思路 1 1 创建一个标签助手类 继承BodyTagSupport 标签属性必须助手类的属性对应
  • 测试自动化平台

    https mp weixin qq com s WU5h8FW6BT5YZtlsSuCIcw 摘要 随着近几年国内IT行业高速发展 对测试工程师的要求也越来越高 其作用也越来越重要 但很多测试工程师也迎来了个人发展的瓶颈 下一步该向哪个方
  • clock的accuracy(tolerance)和jitter

    对于clock来说 有两个参数来衡量质量 分别是jitter和accuracy tolerance Jitter的单位是ps Tolerance的单位是ppm 百万分之 在晶振 RTC和Oscillator中也会找到类似参数 SOC和MCU
  • Hexo标签插件的使用

    tag 插件 Tag Plugin 是 Hexo 提供的一种快速生成特定内容的方式 例如 在标准 Markdown 语法中 我们无法指定图片的大小 这种情景 我们即可使用标签来解决 Hexo 内置来许多标签来帮助写作者可以更快的书写 完整的
  • docker运行nginx为什么要使用 nginx -g 'daemon off;'

    1 docker容器跑着为啥会挂掉 docker 容器默认会把容器内部第一个进程 也就是pid 1的程序作为docker容器是否正在运行的依据 如果docker 容器pid挂了 那么docker容器便会直接退出 2 docker run的时
  • 用Pandas做数据清洗的常用操作!

    大家好 我是小z 今天给大家分享一篇pandas数据清洗的干货 作为一名数据分析师 每天都在完成各种数据分析需求 其中数据清洗是必不可少的一个步骤 一般而言 当提及数据清洗时 其实是主要包括了缺失值处理 重复值处理和异常值处理三类操作 本文
  • DML语法整理笔记

    目录 1 什么是DML 2 两种INSERT方式 2 1 方式一 2 2 方式二 2 3 INSERT特点 2 4 两种方式对比 3 UPDATE 3 1 修改单标记录 3 2 修改多表记录 4 DELETE 4 1 方式一 可以删全表也可
  • 线性回归实战---Abalone鲍鱼年龄预测

    线性回归实现Abalone鲍鱼年龄预测 文章目录 线性回归实现Abalone鲍鱼年龄预测 一 环境准备 数据集简介 二 线性回归基础知识 什么是线性回归 最小二乘法 求解线性回归问题 三 Python代码 四 结果分析 前面我们使用手动编写
  • 2023年江苏省中职网络安全Web渗透测试解析(超详细)

    一 竞赛时间 180分钟 共计3小时 二 竞赛阶段 1 访问地址http 靶机IP web1 分析页面内容 获取flag值 Flag格式为flag xxx 2 访问地址http 靶机IP web2 分析页面内容 获取flag值 Flag格式
  • 什么是DNS欺骗和ARP欺骗?有何区别?

    欺骗攻击是黑客比较常用的一种攻击方式 也是一种隐蔽性较高的网络攻击方式 目前欺骗攻击的主要方式有 IP欺骗 ARP欺骗 DNS欺骗 Web欺骗 电子邮件欺骗等 那么DNS欺骗和ARP欺骗的区别是什么 具体请看下文 DNS欺骗 DNS欺骗是一
  • DIY党的福利!鹅厂程序员教你200元以内制作专属分体键盘

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由VellHe发表于云 社区专栏 前言 作为一名程序员 键盘在手 天下我有啊 不整把高大上的键盘怎么提升B格 之前一直想买个机械键盘 听说机械键盘敲代码和玩游戏都特别爽 也是装B
  • 一款linux系统下的串口调试工具 - COMTransmit

    最近在调试linux下的串口的时候找到了一款好用且功能齐全的串口调试工具 跟大家分享一下 COMTransmit的安装 安装包下载地址 64位 链接 https pan baidu com s 1rxGhMtXYNApjhXquPtiW0w
  • 实时监听nacos中的服务上下线

    1 背景 在使用spring cloud gateway时 服务的上下线可能会没那么及时 这样就会导致在进行业务服重启时会出现部分用户请求接口出现503 服务不可用的情况 nacos client版本 1 4 1 spring cloud
  • msvcp120.dll丢失的解决方法(亲测可修复方的法)

    在运行某些软件的时候 计算机提示msvcp120 dll丢失 无法打开运行软件 在第一次遇到这个问题的时候 相信很多人都不知道是怎么回事 下面小编把msvcp120 dll是什么以及如何解决这个问题的详细方法给大家科普一下 问题描述 在使用
  • linux虚拟机安装完毕之后,ifconfig命令提示command not found

    用虚拟机安装了centos 然后参考链接 https blog csdn net qiruibbb article details 80804121 重新设置了网卡的配置 使虚拟机的系统可以正常上网之后 习惯性的敲了ifconfig 结果提
  • C/C++ 实现时间戳和时间结构体的相互转换、格林威治与本地时间的转换

    C C 实现时间戳和时间结构体的相互转换 格林威治与本地时间的转换 时间是具有周期性的 每间隔四年为一个闰年 时间戳是以1970 1 1 00 00 00开始到当前时间的秒数 查看日历你会发现 1970年为平年 1971年为平年 1972年