UTC时间戳与北京时间转换

简介: UTC时间戳与北京时间转换

前言

在应用中用到了 UTC 时间戳与北京时间进行转换的需求,这里做一个记录,方便后面有需求时直接拿来用。


一、几个时间相关的概念

  • GMT 时间:Greenwich Mean Time,格林尼治平时,又称格林尼治平均时间或格林尼治标准时间。是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间。
  • GMT存在较大误差,因此现在已不再被作为标准时间使用。现在的标准时间,是由原子钟报时的协调世界时(UTC)
  • UTC 时间:Universal Time Coordinated,中文名称:世界标准时间或世界协调时。
  • UTC时间可以理解为全世界都公用的一个时间。它实际上反映了一种约定,即为全世界所认可的一个统一时间,而不是某特定地区的时间。
  • 中国人常用的北京时间比 UTC 时间快8个小时。也即 UTC 时间凌晨 0 点时,北京时间已经是早上 8 点,这就是为啥全世界人往往不直接用 UTC 时间计时原因。
  • CST 时间:China Standard Time,即中国标准时间。在时区划分上,属东八区,比协调世界时早8小时,记为UTC+8。
  • UNIX 时间戳(timestamp):计算机中的 UNIX 时间戳,是以 GMT/UTC 时间 1970-01-01 00:00:00 为起点,到当前具体时间的秒数(不考虑闰秒)。这样做的目的,主要是通过“整数计算”来简化计算机对时间操作的复杂度。

二、场景

1、场景 1

要求实现 UTC 时间戳和北京时间的互相转换,其中月份取值范围为 0~11 代表 1~12月,其他时间参数正常(年、日、时、分、秒)

2、场景 2

要求实现 UTC 时间戳和北京时间的互相转换,时间日期参数正常(年、月、日、时、分、秒),例如月份取值范围为 1~12 代表 1~12 月,日取值范围为 1~31 代表 1~31 日

三、验证方法

可以使用 时间戳转换在线工具 来验证转换后的时间是否正确。

这里以 2023-10-30 18:42:00 这个时间为例,转换后的 UTC 秒数为 1698662520。

四、源码

1、场景 1

其中月份取值范围为 0~11 代表 1~12月

#include <stdio.h>
typedef struct {
    int year;   // 年份
    int month;  // 月份范围:0-11代表1-12月
    int day;    // 日
    int hour;   // 小时
    int minute; // 分钟
    int second; // 秒
} DateTime;
int IsLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
int DaysInMonth(int year, int month) {
    int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if (month == 1 && IsLeapYear(year))
        return 29;
    else
        return days[month];
}
int UTCSecondsToBeijing(DateTime* dt, int seconds) {
    int offset = 8 * 3600; // 北京为东八区,相对于UTC的偏移量为8小时
    int totalSeconds = seconds + offset;
    dt->year = 1970;
    dt->month = 0;
    dt->day = 1;
    dt->hour = 0;
    dt->minute = 0;
    dt->second = 0;
    while (totalSeconds >= 86400) {
        int daysInYear = IsLeapYear(dt->year) ? 366 : 365;
        if (totalSeconds >= daysInYear * 86400) {
            totalSeconds -= daysInYear * 86400;
            dt->year++;
        }
        else {
            int month = 0;
            while (totalSeconds >= DaysInMonth(dt->year, month) * 86400) {
                totalSeconds -= DaysInMonth(dt->year, month) * 86400;
                month++;
            }
            dt->month = month;
            dt->day = totalSeconds / 86400 + 1;
            totalSeconds %= 86400;
            dt->hour = totalSeconds / 3600;
            dt->minute = (totalSeconds % 3600) / 60;
            dt->second = totalSeconds % 60;
            break;
        }
    }
    return totalSeconds;
}
int BeijingTimeToUTCSeconds(const DateTime* dt) {
    int totalSeconds = 0;
    for (int year = 1970; year < dt->year; year++) {
        totalSeconds += IsLeapYear(year) ? 366 * 86400 : 365 * 86400;
    }
    for (int month = 0; month < dt->month; month++) {
        totalSeconds += DaysInMonth(dt->year, month) * 86400;
    }
    totalSeconds += (dt->day - 1) * 86400;
    totalSeconds += dt->hour * 3600;
    totalSeconds += dt->minute * 60;
    totalSeconds += dt->second;
    int offset = 8 * 3600; // 北京为东八区,相对于UTC的偏移量为8小时
    totalSeconds -= offset;
    return totalSeconds;
}
int main() {
    // 示例:UTC秒数转换成北京时间
    int utcSeconds = 1698662520; // 假设给定的UTC秒数
    DateTime beijingTime;
    int remainingSeconds = UTCSecondsToBeijing(&beijingTime, utcSeconds);
    printf("UTC Seconds: %d\n", utcSeconds);
    printf("Beijing Time: %04d-%02d-%02d %02d:%02d:%02d\n",
        beijingTime.year, beijingTime.month + 1, beijingTime.day,
        beijingTime.hour, beijingTime.minute, beijingTime.second);
    printf("Remaining Seconds: %d\n\n", remainingSeconds);
    // 示例:北京时间转换成UTC秒数
    DateTime inputTime;
    inputTime.year = 2023;
    inputTime.month = 12 - 1; // 月份范围:0-11代表1-12月
    inputTime.day = 30;
    inputTime.hour = 18;
    inputTime.minute = 42;
    inputTime.second = 0;
    int utcSecondsResult = BeijingTimeToUTCSeconds(&inputTime);
    printf("Beijing Time: %04d-%02d-%02d %02d:%02d:%02d\n",
        inputTime.year, inputTime.month + 1, inputTime.day,
        inputTime.hour, inputTime.minute, inputTime.second);
    printf("UTC Seconds: %d\n", utcSecondsResult);
    return 0;
}

上述代码分为两个部分,一个是将 UTC 秒数转换为北京时间,另一个是将北京时间转换为 UTC 秒数。你可以根据需要使用其中的任一部分。示例中的北京时间转换成 UTC 秒数部分使用的北京时间为 2023年10月30日18时42分,

2、场景 2

时间日期均为正常

#include <stdio.h>
typedef struct {
    int year;   // 年份
    int month;  // 月
    int day;    // 日
    int hour;   // 小时
    int minute; // 分钟
    int second; // 秒
} DateTime;
int IsLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
int DaysInMonth(int year, int month) {
    int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if (month == 2 && IsLeapYear(year))
        return 29;
    else
        return days[month - 1];
}
int UTCSecondsToBeijing(DateTime* dt, int seconds) {
    int offset = 8 * 3600; // 北京为东八区,相对于UTC的偏移量为8小时
    int totalSeconds = seconds + offset;
    dt->year = 1970;
    dt->month = 1;
    dt->day = 1;
    dt->hour = 0;
    dt->minute = 0;
    dt->second = 0;
    while (totalSeconds >= 86400) {
        int daysInYear = IsLeapYear(dt->year) ? 366 : 365;
        if (totalSeconds >= daysInYear * 86400) {
            totalSeconds -= daysInYear * 86400;
            dt->year++;
        }
        else {
            int month = 1;
            while (totalSeconds >= DaysInMonth(dt->year, month) * 86400) {
                totalSeconds -= DaysInMonth(dt->year, month) * 86400;
                month++;
            }
            dt->month = month;
            dt->day = totalSeconds / 86400 + 1;
            totalSeconds %= 86400;
            dt->hour = totalSeconds / 3600;
            dt->minute = (totalSeconds % 3600) / 60;
            dt->second = totalSeconds % 60;
            break;
        }
    }
    return totalSeconds;
}
int BeijingTimeToUTCSeconds(const DateTime* dt) {
    int totalSeconds = 0;
    for (int year = 1970; year < dt->year; year++) {
        totalSeconds += IsLeapYear(year) ? 366 * 86400 : 365 * 86400;
    }
    for (int month = 1; month < dt->month; month++) {
        totalSeconds += DaysInMonth(dt->year, month) * 86400;
    }
    totalSeconds += (dt->day - 1) * 86400;
    totalSeconds += dt->hour * 3600;
    totalSeconds += dt->minute * 60;
    totalSeconds += dt->second;
    int offset = 8 * 3600; // 北京为东八区,相对于UTC的偏移量为8小时
    totalSeconds -= offset;
    return totalSeconds;
}
int main() {
    // 示例:UTC秒数转换成北京时间
    int utcSeconds = 1677566700; // 假设给定的UTC秒数
    DateTime beijingTime;
    int remainingSeconds = UTCSecondsToBeijing(&beijingTime, utcSeconds);
    printf("UTC Seconds: %d\n", utcSeconds);
    printf("Beijing Time: %04d-%02d-%02d %02d:%02d:%02d\n",
        beijingTime.year, beijingTime.month, beijingTime.day,
        beijingTime.hour, beijingTime.minute, beijingTime.second);
    printf("Remaining Seconds: %d\n\n", remainingSeconds);
    // 示例:北京时间转换成UTC秒数
    DateTime inputTime;
    inputTime.year = 2023;
    inputTime.month = 2;
    inputTime.day = 28;
    inputTime.hour = 14;
    inputTime.minute = 45;
    inputTime.second = 0;
    int utcSecondsResult = BeijingTimeToUTCSeconds(&inputTime);
    printf("Beijing Time: %04d-%02d-%02d %02d:%02d:%02d\n",
        inputTime.year, inputTime.month, inputTime.day,
        inputTime.hour, inputTime.minute, inputTime.second);
    printf("UTC Seconds: %d\n", utcSecondsResult);
    return 0;
}

上述代码分为两个部分,一个是将 UTC 秒数转换为北京时间,另一个是将北京时间转换为 UTC 秒数。你可以根据需要使用其中的任一部分。示例中的北京时间转换成 UTC 秒数部分使用的北京时间为 2023年2月28日14时45分,

五、运行结果

1、场景 1

从结果可以看到将 UTC 秒数转换成北京时间,以及从北京时间转换成 UTC 秒数无误。

2、场景 2

从结果可以看到将 UTC 秒数转换成北京时间,以及从北京时间转换成 UTC 秒数无误。

六、资源自取

UTC时间戳与北京时间转换

目录
相关文章
|
存储 Java Android开发
Android系统升级的机制概要
Android系统升级的机制概要
505 0
|
网络协议 安全 Shell
如何在 SSH 客户端中强制使用 IPv4 或 IPv6?
如何在 SSH 客户端中强制使用 IPv4 或 IPv6?
2031 0
如何在 SSH 客户端中强制使用 IPv4 或 IPv6?
|
自然语言处理 语音技术 开发者
开源上新|FunASR多语言离线文件转写软件包
开源上新|FunASR多语言离线文件转写软件包
|
Linux Docker 异构计算
ModelScope问题之下载了官方镜像 但是启动不了如何解决
ModelScope镜像是指用于在ModelScope平台上创建和管理的容器镜像,这些镜像包含用于模型训练和推理的环境和依赖;本合集将说明如何使用ModelScope镜像以及管理镜像的技巧和注意事项。
475 0
|
开发工具 git 缓存
Git忽略规则.gitignore不生效
在项目开发过程中个,一般都会添加 .gitignore 文件,规则很简单,但有时会发现,规则不生效。 原因是 .gitignore 只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。
61858 4
|
10月前
|
缓存 Kubernetes Docker
GitLab Runner 全面解析:Kubernetes 环境下的应用
GitLab Runner 是 GitLab CI/CD 的核心组件,负责执行由 `.gitlab-ci.yml` 定义的任务。它支持多种执行方式(如 Shell、Docker、Kubernetes),可在不同环境中运行作业。本文详细介绍了 GitLab Runner 的基本概念、功能特点及使用方法,重点探讨了流水线缓存(以 Python 项目为例)和构建镜像的应用,特别是在 Kubernetes 环境中的配置与优化。通过合理配置缓存和镜像构建,能够显著提升 CI/CD 流水线的效率和可靠性,助力开发团队实现持续集成与交付的目标。
|
缓存 Linux 开发工具
CentOS 7- 配置阿里镜像源
阿里镜像官方地址http://mirrors.aliyun.com/ 1、点击官方提供的相应系统的帮助 :2、查看不同版本的系统操作: 下载源1、安装wget yum install -y wget2、下载CentOS 7的repo文件wget -O /etc/yum.
261024 0
|
JSON 安全 数据安全/隐私保护
从0到1搭建权限管理系统系列三 .net8 JWT创建Token并使用
【9月更文挑战第22天】在.NET 8中,从零开始搭建权限管理系统并使用JWT(JSON Web Tokens)创建Token是关键步骤。JWT是一种开放标准(RFC 7519),用于安全传输信息,由头部、载荷和签名三部分组成。首先需安装`Microsoft.AspNetCore.Authentication.JwtBearer`包,并在`Program.cs`中配置JWT服务。接着,创建一个静态方法`GenerateToken`生成包含用户名和角色的Token。最后,在控制器中使用`[Authorize]`属性验证和解析Token,从而实现身份验证和授权功能。
1099 4
|
存储 搜索推荐 Linux
2024年 15 个最佳免费开源 Linux 文件管理器
【4月更文挑战第25天】
10938 53
2024年 15 个最佳免费开源 Linux 文件管理器
|
Prometheus Cloud Native NoSQL
【2023】Prometheus-Prometheus与Alertmanager配置详解
【2023】Prometheus-Prometheus与Alertmanager配置详解
1331 0
【2023】Prometheus-Prometheus与Alertmanager配置详解
下一篇
oss云网关配置