C++.时间间隔

1、HMI(Linux底层)上测试OK    20220315

#include "macrotypedef.h"
#include "math.h"

// 功能: ???

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
//using namespace std;

void setDay(struct tm* day,int y,int m,int d)
{
    day->tm_year=y-1900;
    day->tm_mon=m-1;
    day->tm_mday=d;
    day->tm_hour=day->tm_min=day->tm_sec=0;   
}
 

int MacroEntry()
{
    struct tm time1,time2;
    time_t tim1,tim2;
     
    int y1=1970,mon1=5,day1=4;
    int y2=2000,mon2=6,day2=14;
//    cin>>y1>>mon1>>day1;
 //   cin>>y2>>mon2>>day2;
     
    setDay(&time1,y1,mon1,day1);
    setDay(&time2,y2,mon2,day2);
     
    tim1=mktime(&time1);
    tim2=mktime(&time2);
     
    int len=(tim2-tim1)/(24*60*60);
    //cout<<len<<endl;

LW4000 = len;

    return 0;
}

 

2、20220608 上面的方案基本正确,但是有一个问题:32位的操作系统 函数mktime(...)返回的是 32位的 time_t,在 超过时间 2038+的时候,int32溢出导致结果出错...

 2.1、Win10(64bit) + vs2017,测试 time_t 是64位的,应该是 兼容了。也能手动使用 64位的 函数"__time64_t __cdecl _mktime64(_Inout_ struct tm* _Tm);"

 2.2、嵌入式硬件(Linux),是32位的系统,里面没有_mktime64()的声明,但是调用它的时候 整个宏执行时会报错...(应该是没有实现函数【裁剪掉了?】)

  

 

  网上找了一个 mktime64实现的函数,Win10(64bit) + vs2017 测试OK,代码如下:

void setDay(struct tm* day, int y, int m, int d)
{
    day->tm_year = y -1900;
    day->tm_mon = m - 1;
    day->tm_mday = d;
    day->tm_hour = day->tm_min = day->tm_sec = 0;
}

/***************************************************************************//**
 * \brief       Convert time struct to UTC seconds.
 * \param       year : [1900, ..., 2018, ...]
 * \param       mon  : [1, 12]
 * \param       day  : [1, 31]
 * \param       hour : [0, 23]
 * \param       min  : [0, 59]
 * \param       sec  : [0, 59]
 * \return      seconds from 1970-1-1 0:0:0
 * \author      glic
 * \note        timezone is ignored
 ******************************************************************************/
long long mktime64(unsigned int year, unsigned int mon,
    unsigned int day, unsigned int hour,
    unsigned int min, unsigned int sec)
{
    if (0 >= (int)(mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
        mon += 12;      /* Puts Feb last since it has leap day */
        year -= 1;
    }

    return (((
        (long long)(year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) +
        year * 365 - 719499
        ) * 24 + hour /* now have hours */
        ) * 60 + min /* now have minutes */
        ) * 60 + sec; /* finally seconds */
}

void Test01()
{
    struct tm tmRW;

    int year_rw = 2039;
    int month_rw = 6;
    int day_rw = 8;
    setDay(&tmRW, year_rw, month_rw, day_rw);

    time_t timeRW = _mktime64(&tmRW);
    printf("%lld, 0x%llx\n", timeRW, timeRW);
    printf("%I64d, 0x%I64x\n", timeRW, timeRW);

    long long ll = mktime64(
        year_rw, month_rw, day_rw,
        0, 0, 0);
    ll -= 28800;// 这里是 差了8小时的秒数。时区问题
    printf("%lld, 0x%llx\n", ll, ll);
}

  PS:网址:(7条消息) mktime64和gmtime64实现_skysky97的博客-CSDN博客.html(https://blog.csdn.net/skysky97/article/details/83275201

    由于某些嵌入式标准库中的时间函数没有64位版本,所以需要自己实现。

    这里的两个函数我在linux上与库函数作了对比测试,遍历了1970到2270的每一秒,结果无误。代码是从网上搜集修改而来,具体出处实在是忘记了,印象中都来源于glic库。

    gmtime64实现:

#define SECS_PER_HOUR        (60 * 60)
#define SECS_PER_DAY         (SECS_PER_HOUR * 24)
#define DIV(a, b)            ((a) / (b) - ((a) % (b) < 0))
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))

#define __isleap(year) \
    ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
    
/***************************************************************************//**
 * \brief       Convert UTC seconds to tm struct.
 * \param       t : seconds from 1970-1-1 0:0:0
 * \param       tp : tm struct pointer
 * \return      0 : overflow error
 * \return      1 : success
 * \author      glic __offtime
 * \note        timezone is ignored
 *               struct tm
 *               {
 *                   int tm_sec;            Seconds. [0-60] (1 leap second) 
 *                   int tm_min;            Minutes. [0-59] 
 *                   int tm_hour;           Hours.   [0-23] 
 *                   int tm_mday;           Day.     [1-31] 
 *                   int tm_mon;            Month.   [0-11] 
 *                   int tm_year;           Year - 1900.  
 *                   int tm_wday;           Day of week. [0-6] 
 *                   int tm_yday;           Days in year.[0-365] 
 *               }
 ******************************************************************************/
int gmtime64 (const long long *t, struct tm *tp) 
{
    const unsigned short int __mon_yday[2][13] =
    {
        /* Normal years.  */
        { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
        /* Leap years.  */
        { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
    };
    long int days, rem, y;
    const unsigned short int *ip;

    days = *t / SECS_PER_DAY;
    rem = *t % SECS_PER_DAY;
    while (rem < 0)
    {
        rem += SECS_PER_DAY;
        --days;
    }
    while (rem >= SECS_PER_DAY)
    {
        rem -= SECS_PER_DAY;
        ++days;
    }

    tp->tm_hour = rem / SECS_PER_HOUR;
    rem %= SECS_PER_HOUR;
    tp->tm_min = rem / 60;
    tp->tm_sec = rem % 60;
    /* January 1, 1970 was a Thursday.  */
    tp->tm_wday = (4 + days) % 7;
    if (tp->tm_wday < 0)
    tp->tm_wday += 7;
    y = 1970;
    
    while (days < 0 || days >= (__isleap (y) ? 366 : 365))
    {
        /* Guess a corrected year, assuming 365 days per year.  */
        long int yg = y + days / 365 - (days % 365 < 0);
        /* Adjust DAYS and Y to match the guessed year.  */
        days -= ((yg - y) * 365
               + LEAPS_THRU_END_OF (yg - 1)
               - LEAPS_THRU_END_OF (y - 1));
        y = yg;
    }

    tp->tm_year = y - 1900;
    if (tp->tm_year != y - 1900)
    {
        /* The year cannot be represented due to overflow.  */
        //__set_errno (EOVERFLOW);
        return 0;
    }

    tp->tm_yday = days;
    ip = __mon_yday[__isleap(y)];
    for (y = 11; days < (long int) ip[y]; --y)
        continue;
    days -= ip[y];
    tp->tm_mon = y;
    tp->tm_mday = days + 1;
    return 1;
}

 

  2.3、相关网址:

   (1)__time64_t 解决了 2038 年问题,可是没解决 1969年问题 - personnel - 博客园.html(https://www.cnblogs.com/personnel/p/13955548.html

      里面提到:后来网上搜索了一下,看到一篇介绍说,在 linux 下, _mktime64() 能支持到 1900 年开始,但是在 windows 下,_mktime64() 只能支持从 1970 开始。

      ZC:个人未测试

 

 

 

 

3、

4、

5

posted @ 2022-03-15 11:47  CppSkill  阅读(384)  评论(0编辑  收藏  举报