ctime, mktime 64位版本

来源:互联网 发布:晓风网贷软件 编辑:程序博客网 时间:2024/04/29 18:33

背景介绍

====

     进来因为移植万年历, 需要比较和计算1970之前和之后的时间,比如1900-2100。javascript 中Date.UTC() 对于小于

1970 的日期返回负值,对大的日期也支持,很好用。于是想如何在C中做。

    我试图改造过 ADOdb Date Library, part of the ADOdb abstraction library

Download: http://phplens.com/phpeverywhere/,把PHP翻译为C, 但是它写的啰嗦, 很是麻烦, 还有性能问题。

    最后想到可以参考标准库, 设计决策, 不要使用负值time_t, 处理起来麻烦;规定1900为0起点,-1表示出错。

全文如下,FYI:

/*time64.c -- 64 bit version of time.cauthor: ludiref P.J. PLAUCER "the standard C library.pdf"doc:time_t -- unsigned int -- [1900,2036]unix -- 1970.01.01 00:00:00 -- (70*365+17)*86400 seconds passed since 1900._I64_MAX = 9223372036854775807 -- enough for big bang time--15 billion years = 47304 * 10^13 seconds.*/#include <stdint.h>#include <limits.h>#include <stdio.h>typedef struct datetime{int second; /*seconds after the minute [0,61]*/int minute; /*minutes after the hour [0,59]*/int hour; /*hours since midnight [0,23]*/int mday; /*day of the month [1,31]*/int mon; /*months since January [0,11]*/int year; /*years since _1900_*/int wday; /*days since Sunday [0,6]*/int yday; /*days since January 1 [0,365]*/}datetime_t;typedef int64_t date_t;#define _TBIAS ((date_t)(70*365+17)*86400)#define WDAY 1static const short lmos[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};static const short mos[]  = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};#define MONTAB(y) (y & 03 || y == 0 ? mos : lmos)int isLeapYear(int year){/*四年一闰,百年不闰,四百年再闰*/return (year%4==0&&year%100!=0)||year%400==0;}void test_leap(){int start = 1901, end = 50050;int i, sum = 0, day;for(i = start; i <= end; ++i){if(isLeapYear(i))++sum;}end = end - start;day = end/4 - end/100 + (1900+end)/400 - 1900/400;printf("real %d, esti %d\n", sum, day);}int Daysto(int year, int mon){/*compute extra days to start of month*/int days, end;/*correct for leap year: 1801-*/if(0 < year){end = year - 1;days = end/4 - end/100 + (1900+end)/400 - 1900/400;}else if(year <= -4){days = 1 + (4-year)/4;}else{days = 0;}return days + MONTAB(year)[mon];}datetime_t Ttotm( date_t secarg){/*convert scalar time to datetime*/int year, mon;date_t days, i;date_t secs;datetime_t dt;const short *pm;secs = secarg + _TBIAS;days = secs/86400;dt.wday = (days + WDAY)%7;for(year = days/365; days < (i = Daysto(year, 0) + 365*year);)--year;days -= i;dt.year = year;dt.yday = days;pm = MONTAB(year);for(mon = 12; days < pm[--mon]; );dt.mon = mon;dt.mday = days - pm[mon] + 1;secs %= 86400;dt.hour = secs/3600;secs %= 3600;dt.minute = secs/60;dt.second = secs%60;return dt;}date_t tmtoT(datetime_t *t){/*convert time structure to scalar time*/long double dsecs;int mon, year, ymon;date_t secs;ymon = t->mon/12;mon = t->mon - ymon*12;if(mon < 0)mon += 12, --ymon;if(ymon < 0 && t->year < INT_MIN - ymon   || 0 < ymon && INT_MAX - ymon < t->year)   return (date_t)-1;year = t->year + ymon;dsecs = 86400.0 * (Daysto(year, mon) - 1)+ 31536000.0 * year + 86400.0 * t->mday;dsecs += 3600.0 * t->hour + 60.0 * t->minute + (double)t->second;if(dsecs < 0.0)return (date_t)(-1);secs = (date_t)dsecs - _TBIAS;return secs;}int main(){test_leap();datetime_t dt = {.year = 1900 - 1900,.mon = 6 - 1,.mday = 18,.hour = 18,.minute = 48,.second = 0,};datetime_t d2 = {0};date_t t = tmtoT(&dt);d2 = Ttotm(t);/*you can compare with:     var t = Date.UTC(3013,5,18, 18, 48,0)/1000;    document.write(" t " + t);*/printf("t %I64d \n", t);printf("%d-%d-%d %02d:%02d:%02d\n", d2.year + 1900, d2.mon + 1, d2.mday, d2.hour, d2.minute, d2.second);}


 

原创粉丝点击