Redian新闻
>
写国际化的嵌入式代码,时间问题如何处理?

写国际化的嵌入式代码,时间问题如何处理?

公众号新闻

写国际化的程序比较难处理的两个问题可能是:时间问题编码问题

本篇文章来聊一聊时间问题。

最近设备到了国外,时间不不准了~

杂烩君一直在东八区写代码,处理时间问题时,习惯性的把时区写死为东八区,即设备的小时数总是基于GMT的小时数加上8个小时作为设备的小时数。

如果设备到了国外,设备的时间就不准了,设备的小时数对不上当地的小时数。我们的设备时间,是使用设备上GPS的授时时间给设备进行时间校准的。

设备从GPS拿到的时间数据只是UTC时间。所以,不同地区的时间,需要基于UTC时间+/-时区,向西减小,向东增加。当地的时区,可以根据当地的经度进行计算,这个后面再说。

下面我们先来了解一些概念:

GMT与UTC时间

GMT时间(Greenwich Mean Time,格林威治时间),之前作为全球时间的基准参考时间。

UTC时间(Universal Time Coordinated, 世界标准时间或世界协调时间),以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统。UTC是基于标准的GMT提供的准确时间。

UTC时间和GMT时间其实是同一个时间,只不过UTC时间用秒来表示。

1、获取UTC时间

获取UTC时间的接口:

#include <time.h>
time_t time(time_t *tloc);

该接口返回1970-01-01 00:00:00 +0000至今的秒数(UTC)。

使用例子:

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

time_t get_utc_time(void)
{
    return time(NULL);
}

int main(int argc, char **argv)
{
    time_t utc_time = get_utc_time();
    printf("utc_time = %ld s\n", utc_time);

    return 0;
}

运行结果:

2、获取GMT时间

获取GMT时间的接口:

#include <time.h>
struct tm *gmtime(const time_t *timep);

该接口返回tm结构的GMT时间(UTC时间)。

tm结构:

struct tm 
{

    int tm_sec;    /* Seconds (0-60) */
    int tm_min;    /* Minutes (0-59) */
    int tm_hour;   /* Hours (0-23) */
    int tm_mday;   /* Day of the month (1-31) */
    int tm_mon;    /* Month (0-11) */
    int tm_year;   /* Year - 1900 */
    int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
    int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
    int tm_isdst;  /* Daylight saving time */
};

使用例子:

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

time_t get_utc_time(void)
{
    return time(NULL);
}

int main(int argc, char **argv)
{
    time_t utc_time = get_utc_time();
    printf("utc_time = %ld s\n", utc_time);

    struct tm *gmt_tm = gmtime(&utc_time); 
    printf("gmt time = %.4d-%.2d-%.2d %.2d:%.2d:%.2d\n", gmt_tm->tm_year + 1900,
                                                         gmt_tm->tm_mon + 1,
                                                         gmt_tm->tm_mday,
                                                         gmt_tm->tm_hour,
                                                         gmt_tm->tm_min,
                                                         gmt_tm->tm_sec);

    return 0;
}

运行结果:

时区

由于世界各国家与地区经度不同,地方时区也有所不同,因此会划分为不同的时区。

正式的时区划分包括24个时区,每一时区由一个英文字母表示。每隔经度15°划分一个时区,有一个例外,每个时区有一条中央子午线。

1、时区划分方法:

现今全球共分为24个时区。英国(格林尼治天文台旧址)为中时区(零时区)、东1—12区,西1—12区。每个时区横跨经度15度,时间正好是1小时。最后的东、西第12区各跨经度7.5度,以东、西经180度为界。每个时区的中央经线上的时间就是这个时区内统一采用的时间,称为区时,相邻两个时区的时间相差1小时。

2、经度范围:

3、当地时区计算

需要用到的接口:

#include <time.h>
struct tm *localtime(const time_t *timep);

计算当地时区:

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

time_t get_utc_time(void)
{
    return time(NULL);
}

int main(int argc, char **argv)
{
    time_t utc_time = get_utc_time();
    printf("utc_time = %ld s\n", utc_time);

    struct tm *gmt_tm = gmtime(&utc_time); 
    printf("gmt time = %.4d-%.2d-%.2d %.2d:%.2d:%.2d\n", gmt_tm->tm_year + 1900,
                                                         gmt_tm->tm_mon + 1,
                                                         gmt_tm->tm_mday,
                                                         gmt_tm->tm_hour,
                                                         gmt_tm->tm_min,
                                                         gmt_tm->tm_sec);
    int gmt_hour = gmt_tm->tm_hour;

    struct tm *local_tm = localtime(&utc_time); 
    printf("local time = %.4d-%.2d-%.2d %.2d:%.2d:%.2d\n", local_tm->tm_year + 1900,
                                                           local_tm->tm_mon + 1,
                                                           local_tm->tm_mday,
                                                           local_tm->tm_hour,
                                                           local_tm->tm_min,
                                                           local_tm->tm_sec);
    int local_hour = local_tm->tm_hour;


    int local_time_zone = local_hour - gmt_hour;
    if (local_time_zone < -12
    {
        local_time_zone += 24
    } 
    else if (local_time_zone > 12
    {
        local_time_zone -= 24;
    }else{}

    printf("local_time_zone = %d\n", local_time_zone);

    return 0;
}

我们当前为北京时间:

我们把Ubuntu时间日期里的地点改到其它国家:

CST 时间

CST (China Standard Time,中国标准时间)。

中国标准时间一般指北京时间。北京时间是中国采用国际时区东八时区的区时作为标准时间。而中国幅员辽阔,东西相跨5个时区(即东五区、东六区、东七区、东八区、东九区5个时区)

“北京时间”适用于中国(大陆、港澳、台湾)境内,但在大陆的新疆、西藏等地,政府机关、企事业单位作息时间和邮政通讯费用优惠分界点虽然用北京时间来表示,但也比其他各省延晚2小时,使用UTC+6的情况更为普遍。

根据经度计算时区

时区范围是中央经线的度数向左右分别减、加7.5度。用该地的经度除以15度,当余数小于7.5度时,商数即为该地所在的时区数,当余数大于7.5度时,商数加1即为该地所在的时区数。

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

int calc_timezone(double longitude)
{
    int timezone = 0;
    int quotient = (int)(longitude / 15);
    double remainder = (longitude - quotient * 15);
    printf("quotient = %d, remainder = %lf\n", quotient, remainder);

    if (remainder <= 7.5)
    {
        timezone = quotient;
    }
    else
    {
        timezone = quotient + (quotient >= 0 ? + 1 : -1);
    }

    return timezone;
}

int main(int argc, char **argv)
{
    while (1)
    {
        double longitude = 0.0;
        printf("please input longitude:");
        scanf("%lf", &longitude);
        printf("longitude = %lf\n", longitude);
        int timezone = calc_timezone(longitude);
        printf("timezone = %d\n", timezone);
    }

    return 0;
}

这其实也是百度百科上提供的思路:

这种方式至少可以计算得到时区中心线的时区数,但是一些临界情况可能会差1小时。在网络上也没有找到其它更好的解决方案。

设备的时间,如果只是作为一个显示功能,影响可能不是很大,但是如果设备的时间来做其它事情,比如定时功能,定时多少点多少分做什么事情,影响就很大了。

对于我们的设备,定时功能使用手机APP来操作的,这时候能想到的比较好的方法就是每当使用手机APP的时候,把手机APP的时间给设备时间进行一次校准。

大家是否有其它更好的解决方案,欢迎留言讨论

如果觉得文章有帮助,麻烦帮忙转发,谢谢!

-END-

往期推荐:点击图片即可跳转阅读

用Arduino做一面LED墙,是一种什么体验?


“寒冬”之下,二本学生是如何秋招上岸的?


什么是GPU?GPU和显卡的关系?GPU国产化布局?


蓝桥杯,进决赛了

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
人民币国际化的大势已经形成!学外国要排泄其糟粕吸收其精华线程池中线程抛了异常,该如何处理?他不仅是川菜圣手,而且是国际化的顶级厨师​ ——罗楷经回忆之四我待梦校如初恋,梦校问我“why school”?这个申请高频问题如何回答?一个月内活跃病例数增加72%!新变种来袭,全澳各地确诊病例的激增只是时间问题!​复旦大学邱锡鹏组:CNN-NER——极其简单有效的嵌套命名实体识别方法人民币国际化的最低标准,是在海上保得住用人民币结算的货日子越来越难过+Costco中国香肠【一对一介绍】珠海3号男同学,92年生,身高173,华南理工大学硕士,嵌入式软件工程师,月入1.4W,珠海金湾移民局回答关于2023财年移民排期和处理时间问题HFpEF合并肺动脉高压,该如何处理?​分裂只是时间问题?联合国大胆预测:13亿人口大国或将一分为三我的嵌入式号友国际 | 嵌入式金融:如何在新价值链中繁荣发展PCI术后高血压,应如何处理?专家共识划重点患者男性,72岁,确诊为胰腺癌,吸烟史30年……,麻醉时发生心衰,应如何处理?89 个嵌入式相关概念,你懂几个?澳洲生育率触底反弹!疫情后迎来“婴儿潮”!老龄化严重,劳动力短缺……人口问题如何破局?场所码历史数据引发隐私担忧,特殊的防疫数据该如何处理?嵌入式这个青春饭我吃了整整几十年南工大通报“某博士后教师团购要回扣”,已进行严肃处理!网友:严肃?处理?挪威交响诗 (一)序曲2022 嵌入式智能大会首日:聚焦 AIOT、加速探索人机物融合+端边云协同11月6-8日深圳,国际电子展来了!前瞻未来边缘AI、物联网、RISC-V、OS应用,全球年度嵌入式大展蓄势待发畅游法国(17)-王储的港湾先写国庆最好的一部再谈上海楼市的新变化用1个月重构了同事写的烂代码,我总结出了15条重写烂代码的经验!心脏介入诊疗术中并发急性心脏压塞如何处理?最新共识来解答!肌肉、肌腱处常见运动损伤应如何处理?这种新型存储有望杀入嵌入式市场搞嵌入式,不懂DMA?笑死人。孩子打闹、争抢如何处理?99%的父母都做错了,一张图点醒你对育儿的误解!​如何学习嵌入式系统?
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。