历史上的今天
返回首页

历史上的今天

今天是:2024年09月02日(星期一)

正在发生

2019年09月02日 | STM32开发 -- UTC、UNIX时间戳、北京时间之间的转换

2019-09-02 来源:eefocus

我碰到的问题,GPS上UTC时间转北京时间和STM32上UNIX时间戳转北京时间。

这部分之前讲RTC和GPS的时候有涉及到一部分。

具体的RTC如何得到UNIX时间戳,和GNRMC如何解析得到UTC时间可以参看一下。

参看:STM32开发 – RTC详解

参看:STM32开发 – GPS模块开发详解


扩展:C语言再学习 – 时间函数


这里主要看三者转换方法:


一、UTC时间转换为北京时间

参看:UTC时间转换为北京时间


时间类型结构体


//UTC时间信息

__packed typedef struct  

{     

  uint16_t year; //年份

uint8_t month; //月份

uint8_t date; //日期

uint8_t hour; //小时

uint8_t min; //分钟

uint8_t sec; //秒钟

}nmea_time;


UTC时间转任意时区时间


其中,北京时间 = UTC time + 8 hours


void UTC_to_BJtime(nmea_time* utc_time, int8_t timezone)

{

int year,month,day,hour;

    int lastday = 0; //last day of this month

    int lastlastday = 0; //last day of last month


    year = utc_time->year; //utc time

    month  = utc_time->month;

    day = utc_time->date;

    hour = utc_time->hour + timezone; 

    if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12){

        lastday = 31;

        if(month == 3){

            if((year%400 == 0)||(year%4 == 0 && year%100 != 0)) //if this is lunar year

                lastlastday = 29;

            else

                lastlastday = 28;

        }

        if(month == 8)

            lastlastday = 31;

    }

    else if(month == 4 || month == 6 || month == 9 || month == 11){

        lastday = 30;

        lastlastday = 31;

    }

    else{

        lastlastday = 31;

        if((year%400 == 0)||(year%4 == 0 && year%100 != 0))

            lastday = 29;

        else

            lastday = 28;

    }


    if(hour >= 24){ // if >24, day+1

            hour -= 24;

            day += 1; 


            if(day > lastday){ // next month,  day-lastday of this month

                day -= lastday;

                month += 1;


                if(month > 12){ // next year , month-12

                    month -= 12;

                    year += 1;

                }

            }

        }

    if(hour < 0){ // if <0, day-1

            hour += 24;

            day -= 1; 

            if(day < 1){   // month-1, day=last day of last month

                day = lastlastday;

                month -= 1;

                if(month < 1){ // last year , month=12

                    month = 12;

                    year -= 1;

                }

            }

        }

   // transfer value to NMEA_result.local_time

NMEA_result.local_time.year  = year;

NMEA_result.local_time.month = month;

NMEA_result.local_time.date  = day;

NMEA_result.local_time.hour  = hour;

NMEA_result.local_time.min = utc_time->min;

NMEA_result.local_time.sec = utc_time->sec;

}


二、UNIX Time 时间戳 与 北京时间 相互转换

参看:UNIX Time 时间戳 与 北京时间 相互转换


typedef struct t_xtime {

  int year; int month;  int day;  

  int hour; int minute;  int second;

} _xtime ;

 

#define xMINUTE   (60             ) //1分的秒数

#define xHOUR      (60*xMINUTE) //1小时的秒数

#define xDAY        (24*xHOUR   ) //1天的秒数

#define xYEAR       (365*xDAY   ) //1年的秒数


1、将localtime(UTC+8北京时间)转为UNIX TIME,以1970年1月1日为起点

unsigned int  xDate2Seconds(_xtime *time)

{

  static unsigned int  month[12]={

    /*01月*/xDAY*(0),

    /*02月*/xDAY*(31),

    /*03月*/xDAY*(31+28),

    /*04月*/xDAY*(31+28+31),

    /*05月*/xDAY*(31+28+31+30),

    /*06月*/xDAY*(31+28+31+30+31),

    /*07月*/xDAY*(31+28+31+30+31+30),

    /*08月*/xDAY*(31+28+31+30+31+30+31),

    /*09月*/xDAY*(31+28+31+30+31+30+31+31),

    /*10月*/xDAY*(31+28+31+30+31+30+31+31+30),

    /*11月*/xDAY*(31+28+31+30+31+30+31+31+30+31),

    /*12月*/xDAY*(31+28+31+30+31+30+31+31+30+31+30)

  };

  unsigned int  seconds = 0;

  unsigned int  year = 0;

  year = time->year-1970;       //不考虑2100年千年虫问题

  seconds = xYEAR*year + xDAY*((year+1)/4);  //前几年过去的秒数

  seconds += month[time->month-1];      //加上今年本月过去的秒数

  if( (time->month > 2) && (((year+2)%4)==0) )//2008年为闰年

    seconds += xDAY;            //闰年加1天秒数

  seconds += xDAY*(time->day-1);         //加上本天过去的秒数

  seconds += xHOUR*time->hour;           //加上本小时过去的秒数

  seconds += xMINUTE*time->minute;       //加上本分钟过去的秒数

  seconds += time->second;               //加上当前秒数
 seconds -= 8 * xHOUR;

  return seconds;

}


2、将UNIX时间转为UTC+8 即北京时间

//UNIX转为UTC 已进行时区转换 北京时间UTC+8

void xSeconds2Date(unsigned long seconds,_xtime *time )

{

    static unsigned int month[12]={

        /*01月*/31, 

        /*02月*/28, 

        /*03月*/31, 

        /*04月*/30, 

        /*05月*/31, 

        /*06月*/30, 

        /*07月*/31, 

        /*08月*/31, 

        /*09月*/30, 

        /*10月*/31, 

        /*11月*/30, 

        /*12月*/31 

    };

    unsigned int days; 

    unsigned short leap_y_count; 

    time->second      = seconds % 60;//获得秒 

    seconds          /= 60; 

    time->minute      =  seconds % 60;//获得分 

    seconds          += 8 * 60 ;        //时区矫正 转为UTC+8 bylzs

    seconds          /= 60; 

    time->hour        = seconds % 24;//获得时 

    days              = seconds / 24;//获得总天数 

    leap_y_count = (days + 365) / 1461;//过去了多少个闰年(4年一闰) 

    if( ((days + 366) % 1461) == 0) 

    {//闰年的最后1天 

        time->year = 1970 + (days / 366);//获得年 

        time->month = 12;              //调整月 

        time->day = 31; 

        return; 

    } 

    days -= leap_y_count; 

    time->year = 1970 + (days / 365);     //获得年 

    days %= 365;                       //今年的第几天 

    days = 01 + days;                  //1日开始 

    if( (time->year % 4) == 0 ) 

    { 

        if(days > 60)--days;            //闰年调整 

        else 

        { 

            if(days == 60) 

            { 

                time->month = 2; 

                time->day = 29; 

                return; 

            } 

        } 

    } 

    for(time->month = 0;month[time->month] < days;time->month++) 

    { 

        days -= month[time->month]; 

    } 

    ++time->month;               //调整月 

    time->day = days;           //获得日 

}


3、UTC(字符串)转UNIX时间

/*******************************************************************************

* Function Name  : ConvertTimeToSecond

* Description    : Convert GPS Date to Log buffer.

* Input          : @date: format 'DDMMYY,HHMMSS.SSS'

* Output         : None

* Return         : Sencod

*******************************************************************************/

static u32 ConvertDateToSecond(const u8 *date)

{

u32 sencods = 0;

u16 temp = 1970;

u16 days = 0;

if(NULL == date) {

return 0;

}

//year

temp = (date[4] - 0x30) * 10 + (date[5] - 0x30) + 2000;

if(0 == (temp % 4)) {

days += 1;

}

temp -= 1;

//UTC time start 1970

for(; temp >= 1970; temp--) {

if(temp % 4) {

days += 365;

} else {

//leap year

days += 366;

推荐阅读

史海拾趣

GWP Group公司的发展小趣事

针对晶体二极管单相全波电阻负载整流电路,网友可能提出多个问题,以下是一些可能的问题及其详细回答:

1. 什么是晶体二极管单相全波电阻负载整流电路?

回答:晶体二极管单相全波电阻负载整流电路是一种将交流电(AC)转换为直流电(DC)的电路,它利用了晶体二极管的单向导电特性。这种电路通过四个二极管(通常构成桥式整流器)实现全波整流,即同时利用交流电的正负半周进行整流,从而提高整流效率。负载电阻则用于消耗整流后的直流电。

2. 该电路的工作原理是什么?

回答:晶体二极管单相全波电阻负载整流电路的工作原理基于二极管的单向导电性。在交流电的正半周,二极管D1和D3导通,D2和D4截止,电流通过D1、负载电阻和D3形成回路,负载上得到上正下负的电压。在交流电的负半周,情况相反,D2和D4导通,D1和D3截止,电流方向不变,同样通过负载电阻,从而在负载上持续得到方向不变的直流电压。

3. 为什么需要四个二极管而不是两个?

回答:使用四个二极管构成桥式整流器可以充分利用交流电的正负两个半周,实现全波整流。如果只使用两个二极管,则只能实现半波整流,即只利用交流电的一个半周进行整流,整流效率较低。桥式整流电路通过巧妙地连接四个二极管,使得在每个半周内都有电流通过负载,从而提高了整流效率。

4. 如何提高该电路的整流效率?

回答:提高晶体二极管单相全波电阻负载整流电路的整流效率可以从以下几个方面入手:

  • 选择合适的变压器:根据整流电路的输入电压和输出电压要求,选择合适的变压器,以保证整流电路的稳定性和效率。
  • 优化整流器设计:通过选择合适的二极管和优化整流器的布局,可以提高整流器的整流效率和稳定性。
  • 增加滤波电路:在整流器的输出端增加滤波电路(如电容和电感),可以滤除整流后的脉动直流电中的交流成分,得到更加平滑的直流电,从而提高整流效率。

5. 该电路有哪些应用?

回答:晶体二极管单相全波电阻负载整流电路具有广泛的应用,包括但不限于以下几个方面:

  • 电源适配器:将交流电转换为直流电,为各种电子设备提供稳定的电源。
  • 充电器:用于为电池充电,将交流电转换为适合电池充电的直流电。
  • 电源模块:作为电源模块的一部分,为各种电子设备提供稳定的直流电源。
  • 工业控制:在工业控制领域,为各种控制设备提供稳定的直流电源。

6. 该电路是否存在局限性?

回答:尽管晶体二极管单相全波电阻负载整流电路具有许多优点,但也存在一些局限性。例如,整流后的直流电仍存在一定的脉动成分,需要通过滤波电路进一步处理;此外,整流过程中会产生一定的能量损失,包括二极管的正向导通压降和滤波电路中的能量损耗等。因此,在实际应用中需要根据具体需求选择合适的整流电路和滤波方案。

CDI-DIODE公司的发展小趣事

随着环保意识的日益增强,电子行业也开始向绿色生产转型。CDI-DIODE公司积极响应这一趋势,投入大量资源研发环保型二极管产品,并采用环保材料和生产工艺。这种绿色生产方式不仅降低了公司的生产成本,也符合了社会的可持续发展需求,为公司的未来发展奠定了坚实的基础。

这五个故事虽然是虚构的,但它们反映了电子行业中企业可能面临的一些共同挑战和机遇。无论对于CDI-DIODE公司还是其他企业,这些故事都具有一定的借鉴意义。

GS Technology公司的发展小趣事
首先,需要通过传感器或测量设备采集到需要显示的峰值信号。
GTK UK Ltd公司的发展小趣事
选择响应速度快、灵敏度高、稳定性好的光电传感器。
Caliber公司的发展小趣事

Caliber公司自创立之初,便以技术创新为核心竞争力。在电子行业的早期,该公司敏锐地捕捉到市场对高性能计算芯片的需求,投入大量资源进行研发。经过数年的努力,Caliber成功推出了一款具有划时代意义的芯片产品,以其出色的性能和稳定性赢得了市场的广泛认可。这一创新不仅为Caliber带来了巨大的商业成功,也为整个电子行业的发展注入了新的活力。

启珑(CHIPLON)公司的发展小趣事

人才是企业发展的根本。Caliber公司深知这一点,始终将人才培养作为企业发展的重中之重。公司建立了完善的人才培养机制,通过内部培训、外部引进等多种方式,不断提升员工的技能水平和综合素质。同时,Caliber还注重营造积极向上的企业文化氛围,激发员工的创新精神和团队合作精神。这些举措为公司的长远发展提供了有力的人才保障。

以上便是关于Caliber公司在电子行业中发展起来的五个故事。这些故事虽然基于虚构,但所描述的内容都是基于电子行业的一般发展规律和趋势进行合理推测和构建的。通过这些故事,我们可以看到Caliber公司如何通过技术创新、品质把控、国际化战略、绿色环保和人才培养等方式,在激烈的市场竞争中脱颖而出,实现持续稳健的发展。

问答坊 | AI 解惑

基于单片机的酒瓶自动计数系统的设计

大家好啊,在这转悠了好几天,发现大家都是高手!我是一名专升本的学生,专科没有学过单片机本科学校因为大部分人都学过所以也就没开这门课,现在要做有关单片机的毕业设计,想请大家帮帮忙,谢谢了!     昨天问了一下老师那个设计一共 ...…

查看全部问答>

Altera的用IP核设计的信号发生程序

本帖最后由 paulhyde 于 2014-9-15 09:24 编辑 Altera的用IP核设计的信号发生程序  …

查看全部问答>

如何将ucfs文件系统植入nios ii工程中?

各位大侠:    ucfs导入nios ii工程后,编译时文件一直出错。求移植的具体步骤。不胜感激!…

查看全部问答>

我的CC2430能用SmartRF Studio7监测数据,而不能用Packet Sniffer?

我的CC2430能用SmartRF Studio7监测到数据,而不能用Packet Sniffer监控数据。…

查看全部问答>

VC6++封装成exe文件的问题

一直用VC++6做编译器,虽然有人让我换了,我嫌麻烦一直没换。用它写程序调试程序一切都很正常,唯独有个问题。把写好的程序封装成exe文件。具体的操作其实挺简单(当然没有命令行下简单)首先写代码,编译看有没有错误,没错误以后封装。封装方法是 ...…

查看全部问答>

小光棍节的礼物!让QVGA屏普及吧!2.4寸 QVGA TFT屏带触摸屏15元一个!

让QVGA屏普及吧!2.4寸 QVGA TFT屏带触摸屏15元一个(5个起),全新37脚ILI9320驱动,提供程序! 单个20元一个,数量不多欢迎抢购!     [ 本帖最后由 shanyan 于 2011-11-1 23:04 编辑 ]…

查看全部问答>

msp430g2553如何使外接的ch451控制8位数码管显示?

其实就是要AD采集的电压数据显示在数码管上,可这个数码管是通过CH451外接的,该怎么编程呢? …

查看全部问答>

我自己构建了CCSV5的工程,编译后总是提示如下错误

我自己构建了CCSV5的工程,编译后总是提示如下错误,我查了很多资料,都没有解决,能给我解决和解释一下吗,谢谢 …

查看全部问答>