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
、