帮Windows Mobile实现gmtime,localtime,mktime和strftime
偶尔发现Windows Mobile连一些标准的C语言库函数都没有实现,而这些函数的在头文件中的声明却是有的,实在有些不方便,上网一搜索,才知道原来Windows CE也没实现,而Windows Mobile这方面照搬了Windows CE的,如果真要用这些函数,只能自己来写了,我写了这几个:gmtime,localtime,mktime,strftime,其中用到了Variant Time这个类型,它实质上是个浮点数,浮点数就意味着有时候不太精确,我实践下来确实发觉有时候会有1秒钟的偏差,在计算time_t的时候,不过暂时懒得去管它了。使用方法很简单,把代码复制一份,保存到一个叫“TimeFunctions.cpp”的文件中去,然后在你的project中添加这个文件即可。
#include
<
time.h
>
#include < windows.h >
static BOOL IsLeapYear(WORD nYear)
{
return ! (nYear % 4 ) && (nYear % 100 ) || ! (nYear % 400 );
}
static int DaysFromJan1st(WORD wYear, WORD wMonth)
{
static WORD monthday[] = { 0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 };
return monthday[wMonth - 1 ] + (IsLeapYear(wYear) && wMonth > 2 ? 1 : 0 );
}
static tm * GetTmByVariant(DOUBLE dTime)
{
SYSTEMTIME stResult;
VariantTimeToSystemTime(dTime, & stResult);
static tm s_tm;
s_tm.tm_sec = stResult.wSecond;
s_tm.tm_min = stResult.wMinute;
s_tm.tm_hour = stResult.wHour;
s_tm.tm_mday = stResult.wDay;
s_tm.tm_mon = stResult.wMonth - 1 ;
s_tm.tm_year = stResult.wYear - 1900 ;
s_tm.tm_wday = stResult.wDayOfWeek;
s_tm.tm_yday = DaysFromJan1st(stResult.wYear, stResult.wMonth);
s_tm.tm_isdst = 0 ;
return & s_tm;
}
const DOUBLE VT_SECOND_1970 = 2209161600.0 ;
const DOUBLE SECONDS_IN_ONE_DAY = 86400 ;
tm * __cdecl gmtime( const time_t * pTT)
{
return GetTmByVariant((VT_SECOND_1970 + ( * pTT)) / SECONDS_IN_ONE_DAY);
}
tm * __cdecl localtime( const time_t * pTT)
{
TIME_ZONE_INFORMATION tz;
GetTimeZoneInformation( & tz);
return GetTmByVariant((VT_SECOND_1970 + ( * pTT) - tz.Bias * 60 ) / SECONDS_IN_ONE_DAY);
}
time_t __cdecl mktime(tm * pTM)
{
SYSTEMTIME stToConvert = {
pTM -> tm_year + 1900 ,
pTM -> tm_mon + 1 ,
pTM -> tm_wday,
pTM -> tm_mday,
pTM -> tm_hour,
pTM -> tm_min,
pTM -> tm_sec,
0 };
DOUBLE dToCal;
SystemTimeToVariantTime( & stToConvert, & dToCal);
return (time_t)(dToCal * SECONDS_IN_ONE_DAY - VT_SECOND_1970);
}
static void strfmt( char * str, const char * fmt, )
{
int ival, ilen;
char * sval;
static int pow[ 5 ] = { 1 , 10 , 100 , 1000 , 10000 };
va_list vp;
va_start(vp, fmt);
while ( * fmt)
{
if ( * fmt ++ == ' % ' )
{
ilen = * fmt ++ - ' 0 ' ;
if (ilen == 0 ) // zero means string arg
{
sval = va_arg(vp, char * );
while ( * sval)
* str ++ = * sval ++ ;
}
else // always leading zeros
{
ival = va_arg(vp, int );
while (ilen)
{
ival %= pow[ilen -- ];
* str ++ = ( char )( ' 0 ' + ival / pow[ilen]);
}
}
}
else * str ++ = fmt[ - 1 ];
}
* str = ' \0 ' ;
va_end(vp);
}
#define DAYSPERWEEK 7
size_t __cdecl strftime( char * pTimeStr, size_t stStrLen, const char * pFmt, const tm * pTM)
{
static char * aday[] = { " Sun " , " Mon " , " Tue " , " Wed " , " Thu " , " Fri " , " Sat " };
static char * day[] = { " Sunday " , " Monday " , " Tuesday " , " Wednesday " , " Thursday " , " Friday " , " Saturday " };
static char * amonth[] = { " Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " , " Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " };
static char * month[] = { " January " , " February " , " March " , " April " , " May " , " June " , " July " , " August " , " September " , " October " , " November " , " December " };
int w;
char * p, * q, * r;
static char buf[ 26 ];
p = pTimeStr;
q = pTimeStr + stStrLen - 1 ;
while (( * pFmt != ' \0 ' ))
{
if ( * pFmt ++ == ' % ' )
{
r = buf;
switch ( * pFmt ++ )
{
case ' % ' :
r = " % " ;
break ;
case ' a ' :
r = aday[pTM -> tm_wday];
break ;
case ' A ' :
r = day[pTM -> tm_wday];
break ;
case ' b ' :
r = amonth[pTM -> tm_mon];
break ;
case ' B ' :
r = month[pTM -> tm_mon];
break ;
case ' c ' :
strfmt(r, " %0 %0 %2 %2:%2:%2 %4 " ,
aday[pTM -> tm_wday], amonth[pTM -> tm_mon],
pTM -> tm_mday,pTM -> tm_hour, pTM -> tm_min,
pTM -> tm_sec, pTM -> tm_year + 1900 );
break ;
case ' d ' :
strfmt(r, " %2 " ,pTM -> tm_mday);
break ;
case ' H ' :
strfmt(r, " %2 " ,pTM -> tm_hour);
break ;
case ' I ' :
strfmt(r, " %2 " ,(pTM -> tm_hour % 12 ) ? pTM -> tm_hour % 12 : 12 );
break ;
case ' j ' :
strfmt(r, " %3 " ,pTM -> tm_yday + 1 );
break ;
case ' m ' :
strfmt(r, " %2 " ,pTM -> tm_mon + 1 );
break ;
case ' M ' :
strfmt(r, " %2 " ,pTM -> tm_min);
break ;
case ' p ' :
r = (pTM -> tm_hour > 11 ) ? " PM " : " AM " ;
break ;
case ' S ' :
strfmt(r, " %2 " ,pTM -> tm_sec);
break ;
case ' U ' :
w = pTM -> tm_yday / 7 ;
if (pTM -> tm_yday % 7 > pTM -> tm_wday)
w ++ ;
strfmt(r, " %2 " , w);
break ;
case ' W ' :
w = (pTM -> tm_yday + DAYSPERWEEK -
(pTM -> tm_wday ?
(pTM -> tm_wday - 1 ) :
(DAYSPERWEEK - 1 ))) / DAYSPERWEEK;
strfmt(r, " %2 " , w);
break ;
case ' w ' :
strfmt(r, " %1 " ,pTM -> tm_wday);
break ;
case ' x ' :
strfmt(r, " %2/%2/%2 " , pTM -> tm_mon + 1 ,
pTM -> tm_mday, pTM -> tm_year + 1900 );
break ;
case ' X ' :
strfmt(r, " %2:%2:%2 " , pTM -> tm_hour,
pTM -> tm_min, pTM -> tm_sec);
break ;
case ' y ' :
strfmt(r, " %2 " ,pTM -> tm_year % 100 );
break ;
case ' Y ' :
strfmt(r, " %4 " ,pTM -> tm_year + 1900 );
break ;
case ' Z ' :
// r = (pTM->tm_isdst && tz_name[1][0])?tz_name[1]:tz_name[0];
break ;
default :
buf[ 0 ] = ' % ' ; // reconstruct the format
buf[ 1 ] = pFmt[ - 1 ];
buf[ 2 ] = ' \0 ' ;
if (buf[ 1 ] == 0 )
pFmt -- ; // back up if at end of string
}
while ( * r)
{
if (p == q)
{
* q = ' \0 ' ;
return 0 ;
}
* p ++ = * r ++ ;
}
}
else
{
if (p == q)
{
* q = ' \0 ' ;
return 0 ;
}
* p ++ = pFmt[ - 1 ];
}
}
* p = ' \0 ' ;
return p - pTimeStr;
}
#include < windows.h >
static BOOL IsLeapYear(WORD nYear)
{
return ! (nYear % 4 ) && (nYear % 100 ) || ! (nYear % 400 );
}
static int DaysFromJan1st(WORD wYear, WORD wMonth)
{
static WORD monthday[] = { 0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 };
return monthday[wMonth - 1 ] + (IsLeapYear(wYear) && wMonth > 2 ? 1 : 0 );
}
static tm * GetTmByVariant(DOUBLE dTime)
{
SYSTEMTIME stResult;
VariantTimeToSystemTime(dTime, & stResult);
static tm s_tm;
s_tm.tm_sec = stResult.wSecond;
s_tm.tm_min = stResult.wMinute;
s_tm.tm_hour = stResult.wHour;
s_tm.tm_mday = stResult.wDay;
s_tm.tm_mon = stResult.wMonth - 1 ;
s_tm.tm_year = stResult.wYear - 1900 ;
s_tm.tm_wday = stResult.wDayOfWeek;
s_tm.tm_yday = DaysFromJan1st(stResult.wYear, stResult.wMonth);
s_tm.tm_isdst = 0 ;
return & s_tm;
}
const DOUBLE VT_SECOND_1970 = 2209161600.0 ;
const DOUBLE SECONDS_IN_ONE_DAY = 86400 ;
tm * __cdecl gmtime( const time_t * pTT)
{
return GetTmByVariant((VT_SECOND_1970 + ( * pTT)) / SECONDS_IN_ONE_DAY);
}
tm * __cdecl localtime( const time_t * pTT)
{
TIME_ZONE_INFORMATION tz;
GetTimeZoneInformation( & tz);
return GetTmByVariant((VT_SECOND_1970 + ( * pTT) - tz.Bias * 60 ) / SECONDS_IN_ONE_DAY);
}
time_t __cdecl mktime(tm * pTM)
{
SYSTEMTIME stToConvert = {
pTM -> tm_year + 1900 ,
pTM -> tm_mon + 1 ,
pTM -> tm_wday,
pTM -> tm_mday,
pTM -> tm_hour,
pTM -> tm_min,
pTM -> tm_sec,
0 };
DOUBLE dToCal;
SystemTimeToVariantTime( & stToConvert, & dToCal);
return (time_t)(dToCal * SECONDS_IN_ONE_DAY - VT_SECOND_1970);
}
static void strfmt( char * str, const char * fmt, )
{
int ival, ilen;
char * sval;
static int pow[ 5 ] = { 1 , 10 , 100 , 1000 , 10000 };
va_list vp;
va_start(vp, fmt);
while ( * fmt)
{
if ( * fmt ++ == ' % ' )
{
ilen = * fmt ++ - ' 0 ' ;
if (ilen == 0 ) // zero means string arg
{
sval = va_arg(vp, char * );
while ( * sval)
* str ++ = * sval ++ ;
}
else // always leading zeros
{
ival = va_arg(vp, int );
while (ilen)
{
ival %= pow[ilen -- ];
* str ++ = ( char )( ' 0 ' + ival / pow[ilen]);
}
}
}
else * str ++ = fmt[ - 1 ];
}
* str = ' \0 ' ;
va_end(vp);
}
#define DAYSPERWEEK 7
size_t __cdecl strftime( char * pTimeStr, size_t stStrLen, const char * pFmt, const tm * pTM)
{
static char * aday[] = { " Sun " , " Mon " , " Tue " , " Wed " , " Thu " , " Fri " , " Sat " };
static char * day[] = { " Sunday " , " Monday " , " Tuesday " , " Wednesday " , " Thursday " , " Friday " , " Saturday " };
static char * amonth[] = { " Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " , " Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " };
static char * month[] = { " January " , " February " , " March " , " April " , " May " , " June " , " July " , " August " , " September " , " October " , " November " , " December " };
int w;
char * p, * q, * r;
static char buf[ 26 ];
p = pTimeStr;
q = pTimeStr + stStrLen - 1 ;
while (( * pFmt != ' \0 ' ))
{
if ( * pFmt ++ == ' % ' )
{
r = buf;
switch ( * pFmt ++ )
{
case ' % ' :
r = " % " ;
break ;
case ' a ' :
r = aday[pTM -> tm_wday];
break ;
case ' A ' :
r = day[pTM -> tm_wday];
break ;
case ' b ' :
r = amonth[pTM -> tm_mon];
break ;
case ' B ' :
r = month[pTM -> tm_mon];
break ;
case ' c ' :
strfmt(r, " %0 %0 %2 %2:%2:%2 %4 " ,
aday[pTM -> tm_wday], amonth[pTM -> tm_mon],
pTM -> tm_mday,pTM -> tm_hour, pTM -> tm_min,
pTM -> tm_sec, pTM -> tm_year + 1900 );
break ;
case ' d ' :
strfmt(r, " %2 " ,pTM -> tm_mday);
break ;
case ' H ' :
strfmt(r, " %2 " ,pTM -> tm_hour);
break ;
case ' I ' :
strfmt(r, " %2 " ,(pTM -> tm_hour % 12 ) ? pTM -> tm_hour % 12 : 12 );
break ;
case ' j ' :
strfmt(r, " %3 " ,pTM -> tm_yday + 1 );
break ;
case ' m ' :
strfmt(r, " %2 " ,pTM -> tm_mon + 1 );
break ;
case ' M ' :
strfmt(r, " %2 " ,pTM -> tm_min);
break ;
case ' p ' :
r = (pTM -> tm_hour > 11 ) ? " PM " : " AM " ;
break ;
case ' S ' :
strfmt(r, " %2 " ,pTM -> tm_sec);
break ;
case ' U ' :
w = pTM -> tm_yday / 7 ;
if (pTM -> tm_yday % 7 > pTM -> tm_wday)
w ++ ;
strfmt(r, " %2 " , w);
break ;
case ' W ' :
w = (pTM -> tm_yday + DAYSPERWEEK -
(pTM -> tm_wday ?
(pTM -> tm_wday - 1 ) :
(DAYSPERWEEK - 1 ))) / DAYSPERWEEK;
strfmt(r, " %2 " , w);
break ;
case ' w ' :
strfmt(r, " %1 " ,pTM -> tm_wday);
break ;
case ' x ' :
strfmt(r, " %2/%2/%2 " , pTM -> tm_mon + 1 ,
pTM -> tm_mday, pTM -> tm_year + 1900 );
break ;
case ' X ' :
strfmt(r, " %2:%2:%2 " , pTM -> tm_hour,
pTM -> tm_min, pTM -> tm_sec);
break ;
case ' y ' :
strfmt(r, " %2 " ,pTM -> tm_year % 100 );
break ;
case ' Y ' :
strfmt(r, " %4 " ,pTM -> tm_year + 1900 );
break ;
case ' Z ' :
// r = (pTM->tm_isdst && tz_name[1][0])?tz_name[1]:tz_name[0];
break ;
default :
buf[ 0 ] = ' % ' ; // reconstruct the format
buf[ 1 ] = pFmt[ - 1 ];
buf[ 2 ] = ' \0 ' ;
if (buf[ 1 ] == 0 )
pFmt -- ; // back up if at end of string
}
while ( * r)
{
if (p == q)
{
* q = ' \0 ' ;
return 0 ;
}
* p ++ = * r ++ ;
}
}
else
{
if (p == q)
{
* q = ' \0 ' ;
return 0 ;
}
* p ++ = pFmt[ - 1 ];
}
}
* p = ' \0 ' ;
return p - pTimeStr;
}