日期与时间戳-如何将时间戳转换成日期

        日期和时间戳都是对时间的编码,日期站在人角度对时间的编码,而时间戳是站在计算机的角度对时间的编码。虽然每天都感受到时间的存在,若你若问什么是时间?这个问题比较哲学很难回给出简洁的定义,但有一种观点认为“时间本不存在,时间就是运动”。

1. 什么是时间戳

        时间戳一般指unix时间戳,是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数(UTC时间),尽管时间戳在全球范围内应该是一致的,但由于不同地区采用了不同的时区,同一时刻在不同地方的电脑显示的日期和时间可能会有所不同。

2. 什么是时区

        时区的概念是为了让不同地区的人们在相同的时刻看到相同的天文事件,比如日出和日落。因此,全球被划分成了24个时区,每个时区都与地球上的经线相对应,使得当地的时间与太阳的位置相对应。这导致了在同一时刻,位于不同时区的计算机所显示的时间会有所不同。在北京的电脑显示的时间可能是早晨8点,而在纽约的电脑显示的时间可能是晚上8点,即使它们在同一时刻都是根据相同的Unix时间戳计算出来的。这是因为北京采用东八区时区,而纽约采用东部标准时间(EST)时区,它们之间相差了12个小时。

        在中国内部时区有些特殊,即使你没有到新疆和黑龙江,你应该也听过"新疆晚上10点了天还没黑,黑龙江下午4点天就开始黑了",在中国从新疆的最东边到黑龙江最西边跨越了约62度,按15度每个时区,这里至少跨越5个时区,但实际上中国仅采用了一个时区-东八区。另外现在我们谈到的“北京时间”,并不是真正意义上的北京时间,而是以陕西省渭南市蒲城县授时中心发出的时间为“北京时间”。

3. 如何将时间戳转换成日期

        在一些高级开发语言都提供了相应的接口,如在python中直接使用time.localtime()可完成时间戳到日期的转换、在c#中使用TimeZone.CurrentTimeZone.ToLocalTim可以将时间戳转换成日期,但在嵌入式开发中特别是MCU开发,每个芯片原厂可能使用不同的编译器,而这个编译器对C运行库实现并不完整导致了对某些时间戳(如闰年)向日期转换过程中可能存在一定的错误,当理清楚这个转换关系后我们也能编写我们自己的转换函数。

        第一个我们需要能清楚的是时区关系,转换前需要加上时区偏移,如下所示:

时间戳与时区

        在日期中,每天都有24个小时,每个小时都有60分钟,每分钟都有60秒这是完全固定的,并不存在那一天少了1个小时那一天多了1个小时,通过时间戳计算时分秒这部分相对来说较为容易;而年月日这部分计算相关规定来较为复杂,这是由于每个月天数不一样,而且在闰年中与非闰年年单色天数可能也不一样。 

闰年规则的韦恩图表示

        对于时分秒计算类似,仅仅使用取余+整除可计算时分秒;而对于年月日由于闰年存在不能通过一个简单的公式计算等到,而需要使用当前时间戳从1970年进行递推并,递推中需要对闰年进行补偿。 

4. C实现逻辑

        时间戳转日期实现原型,与C库的localtime功能相同:

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

struct DateTime {
    int year;   // 年
    int month;  // 月
    int day;    // 日
    int hour;   // 时
    int min;    // 分
    int sec;    // 秒
};

void timestampToDateTime(uint32_t timestamp, struct DateTime *dt, int timezoneOffset) 
{
    uint32_t totalSeconds = timestamp + timezoneOffset * 3600;

    // 计算年份
    dt->year = 1970;
    while (totalSeconds >= (31536000UL + ((dt->year % 4 == 0 && (dt->year % 100 != 0 || dt->year % 400 == 0)) ? 86400 : 0))) 
    {
        totalSeconds -= 31536000UL + ((dt->year % 4 == 0 && (dt->year % 100 != 0 || dt->year % 400 == 0)) ? 86400 : 0);
        dt->year++;
    }

    // 计算月份和日期
    uint8_t daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if ((dt->year % 4 == 0 && (dt->year % 100 != 0 || dt->year % 400 == 0))) 
    {
        daysInMonth[1] = 29;  // 闰年2月有29天
    }
    dt->month = 0;
    while (totalSeconds >= (daysInMonth[dt->month] * 86400UL)) 
    {
        totalSeconds -= daysInMonth[dt->month] * 86400UL;
        dt->month++;
    }
    dt->day = totalSeconds / 86400UL + 1;

    // 计算时分秒
    dt->hour = (totalSeconds % 86400) / 3600;
    dt->min = (totalSeconds % 3600) / 60;
    dt->sec = totalSeconds % 60;
}

int main() 
{
    uint32_t timestamp = 1711324800; //(0时区) 2021-03-25 00:00:00 的时间戳
    int timezoneOffset = 8; // 北京时间的偏移量(小时)
    struct DateTime dt;

    timestampToDateTime(timestamp, &dt, timezoneOffset);

    // 输出日期时间信息
    printf("Date & Time: %d-%02d-%02d %02d:%02d:%02d\n",
           dt.year, dt.month + 1, dt.day, dt.hour, dt.min, dt.sec);

    return 0;
}

        时间装时间戳转实现原型,与C库的localtime功能相同:

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

struct DateTime {
    int year;
    uint8_t month;
    uint8_t day;
    uint8_t hour;
    uint8_t min;
    uint8_t sec;
};

uint32_t dateTimeToTimestamp(struct DateTime dt, int timezoneOffset) 
{
    // 计算总秒数
    uint32_t totalSeconds = 0;

    // 计算年份对应的秒数
    for (int year = 1970; year < dt.year; ++year) {
        totalSeconds += ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 31622400UL : 31536000UL);
    }

    // 计算月份对应的秒数
    uint8_t daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (dt.year % 4 == 0 && (dt.year % 100 != 0 || dt.year % 400 == 0)) {
        daysInMonth[1] = 29;  // 闰年2月有29天
    }
    for (int month = 0; month < dt.month - 1; ++month) {
        totalSeconds += daysInMonth[month] * 86400UL;
    }

    // 加上日期对应的秒数
    totalSeconds += (dt.day - 1) * 86400UL;

    // 加上时间对应的秒数
    totalSeconds += dt.hour * 3600 + dt.min * 60 + dt.sec;

    // 考虑时区偏移量
    totalSeconds -= timezoneOffset * 3600;

    return totalSeconds;
}

int main() 
{
    struct DateTime dateTime = {2024, 3, 25, 8, 0, 0}; // 日期时间示例
    int timezoneOffset = 8; // 北京时间的偏移量(小时)

    // 将日期时间转换为时间戳并输出
    uint32_t timestamp = dateTimeToTimestamp(dateTime, timezoneOffset);
    printf("Converted Timestamp: %u\n", timestamp);

    return 0;
}

  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值