Annotation of sbbs/src/xpdev/xpdatetime.c, revision 1.1.1.1

1.1       root        1: /* xpdatetime.c */
                      2: 
                      3: /* Cross-platform (and eXtra Precision) date/time functions */
                      4: 
                      5: /* $Id: xpdatetime.c,v 1.7 2010/05/28 01:27:40 sbbs Exp $ */
                      6: 
                      7: /****************************************************************************
                      8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                     10:  *                                                                                                                                                     *
                     11:  * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html         *
                     12:  *                                                                                                                                                     *
                     13:  * This library is free software; you can redistribute it and/or                       *
                     14:  * modify it under the terms of the GNU Lesser General Public License          *
                     15:  * as published by the Free Software Foundation; either version 2                      *
                     16:  * of the License, or (at your option) any later version.                                      *
                     17:  * See the GNU Lesser General Public License for more details: lgpl.txt or     *
                     18:  * http://www.fsf.org/copyleft/lesser.html                                                                     *
                     19:  *                                                                                                                                                     *
                     20:  * Anonymous FTP access to the most recent released source is available at     *
                     21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     22:  *                                                                                                                                                     *
                     23:  * Anonymous CVS access to the development source and modification history     *
                     24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     26:  *     (just hit return, no password is necessary)                                                     *
                     27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     28:  *                                                                                                                                                     *
                     29:  * For Synchronet coding style and modification guidelines, see                                *
                     30:  * http://www.synchro.net/source.html                                                                          *
                     31:  *                                                                                                                                                     *
                     32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     33:  * format) via e-mail to [email protected]                                                                      *
                     34:  *                                                                                                                                                     *
                     35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     36:  ****************************************************************************/
                     37: 
                     38: #include <string.h>            /* memset */
                     39: #include "datewrap.h"  /* sane_mktime */
                     40: #include "xpdatetime.h"        /* xpDateTime_t */
                     41: 
                     42: /**************************************/
                     43: /* Cross-platform date/time functions */
                     44: /**************************************/
                     45: 
                     46: xpDateTime_t xpDateTime_create(unsigned year, unsigned month, unsigned day
                     47:                                                          ,unsigned hour, unsigned minute, float second
                     48:                                                          ,xpTimeZone_t zone)
                     49: {
                     50:        xpDateTime_t    xpDateTime;
                     51: 
                     52:        xpDateTime.date.year    = year;
                     53:        xpDateTime.date.month   = month;
                     54:        xpDateTime.date.day             = day;
                     55:        xpDateTime.time.hour    = hour;
                     56:        xpDateTime.time.minute  = minute;
                     57:        xpDateTime.time.second  = second;
                     58:        xpDateTime.zone                 = zone;
                     59: 
                     60:        return xpDateTime;
                     61: }
                     62: 
                     63: xpDateTime_t xpDateTime_now(void)
                     64: {
                     65: #if defined(_WIN32)
                     66:        SYSTEMTIME systime;
                     67: 
                     68:        GetLocalTime(&systime);
                     69:        return(xpDateTime_create(systime.wYear,systime.wMonth,systime.wDay
                     70:                ,systime.wHour,systime.wMinute,(float)systime.wSecond+(systime.wMilliseconds*0.001F)
                     71:                ,xpTimeZone_local()));
                     72: #else  /* !Win32 (e.g. Unix) */
                     73:        struct tm tm;
                     74:        struct timeval tv;
                     75:        time_t  t;
                     76: 
                     77:        gettimeofday(&tv, NULL);
                     78:        t=tv.tv_sec;
                     79:        localtime_r(&t,&tm);
                     80: 
                     81:        return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday
                     82:                ,tm.tm_hour,tm.tm_min,(float)tm.tm_sec+(tv.tv_usec*0.00001)
                     83:                ,xpTimeZone_local());
                     84: #endif
                     85: }
                     86: 
                     87: xpTimeZone_t xpTimeZone_local(void)
                     88: {
                     89: #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DARWIN__)
                     90:        struct tm tm;
                     91:        time_t t;
                     92: 
                     93:        localtime_r(&t, &tm);
                     94:        return(tm.tm_gmtoff/60);
                     95: #elif defined(_WIN32)
                     96:        TIME_ZONE_INFORMATION   tz;
                     97:        DWORD                                   tzRet;
                     98: 
                     99:        /*****************************/
                    100:        /* Get Time-zone information */
                    101:        /*****************************/
                    102:     memset(&tz,0,sizeof(tz));
                    103:        tzRet=GetTimeZoneInformation(&tz);
                    104:        switch(tzRet) {
                    105:                case TIME_ZONE_ID_DAYLIGHT:
                    106:                        tz.Bias += tz.DaylightBias;
                    107:                        break;
                    108:                case TIME_ZONE_ID_STANDARD:
                    109:                        tz.Bias += tz.StandardBias;
                    110:                        break;
                    111:        }
                    112: 
                    113:        return -tz.Bias;
                    114: #else
                    115: 
                    116: #if defined(__BORLANDC__) || defined(__CYGWIN__)
                    117:        #define timezone _timezone
                    118: #endif
                    119: 
                    120:        /* Converts (_)timezone from seconds west of UTC to minutes east of UTC */
                    121:        /* Adjust for DST, assuming adjustment is always 60 minutes <sigh> */
                    122:        return -((timezone/60) - (daylight*60));
                    123: #endif
                    124: }
                    125: 
                    126: time_t xpDateTime_to_time(xpDateTime_t xpDateTime)
                    127: {
                    128:        struct tm tm;
                    129: 
                    130:        ZERO_VAR(tm);
                    131: 
                    132:        if(xpDateTime.date.year==0)
                    133:                return(INVALID_TIME);
                    134: 
                    135:        tm.tm_year      = xpDateTime.date.year;
                    136:        tm.tm_mon       = xpDateTime.date.month;
                    137:        tm.tm_mday      = xpDateTime.date.day;
                    138: 
                    139:        tm.tm_hour      = xpDateTime.time.hour;
                    140:        tm.tm_min       = xpDateTime.time.minute;
                    141:        tm.tm_sec       = (int)xpDateTime.time.second;
                    142: 
                    143:        return sane_mktime(&tm);
                    144: }
                    145: 
                    146: xpDateTime_t time_to_xpDateTime(time_t ti, xpTimeZone_t zone)
                    147: {
                    148:        xpDateTime_t    never;
                    149:        struct tm tm;
                    150: 
                    151:        ZERO_VAR(never);
                    152:        ZERO_VAR(tm);
                    153:        if(localtime_r(&ti,&tm)==NULL)
                    154:                return(never);
                    155: 
                    156:        return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday
                    157:                ,tm.tm_hour,tm.tm_min,(float)tm.tm_sec
                    158:                ,zone==xpTimeZone_LOCAL ? xpTimeZone_local() : zone);
                    159: }
                    160: 
                    161: xpDateTime_t gmtime_to_xpDateTime(time_t ti)
                    162: {
                    163:        xpDateTime_t    never;
                    164:        struct tm tm;
                    165: 
                    166:        ZERO_VAR(never);
                    167:        ZERO_VAR(tm);
                    168:        if(gmtime_r(&ti,&tm)==NULL)
                    169:                return(never);
                    170: 
                    171:        return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday
                    172:                ,tm.tm_hour,tm.tm_min,(float)tm.tm_sec
                    173:                ,xpTimeZone_UTC);
                    174: }
                    175: 
                    176: /**********************************************/
                    177: /* Decimal-coded ISO-8601 date/time functions */
                    178: /**********************************************/
                    179: 
                    180: isoDate_t xpDateTime_to_isoDateTime(xpDateTime_t xpDateTime, isoTime_t* isoTime)
                    181: {
                    182:        if(isoTime!=NULL)
                    183:                *isoTime=0;
                    184: 
                    185:        if(xpDateTime.date.year==0)
                    186:                return(0);
                    187: 
                    188:        if(isoTime!=NULL)
                    189:                *isoTime=isoTime_create(xpDateTime.time.hour,xpDateTime.time.minute,xpDateTime.time.second);
                    190: 
                    191:        return isoDate_create(xpDateTime.date.year,xpDateTime.date.month,xpDateTime.date.day);
                    192: }
                    193: 
                    194: xpDateTime_t isoDateTime_to_xpDateTime(isoDate_t date, isoTime_t ti)
                    195: {
                    196:        return xpDateTime_create(isoDate_year(date),isoDate_month(date),isoDate_day(date)
                    197:                ,isoTime_hour(ti),isoTime_minute(ti),(float)isoTime_second(ti),xpTimeZone_local());
                    198: }
                    199: 
                    200: isoDate_t time_to_isoDateTime(time_t ti, isoTime_t* isoTime)
                    201: {
                    202:        struct tm tm;
                    203: 
                    204:        if(isoTime!=NULL)
                    205:                *isoTime=0;
                    206: 
                    207:        ZERO_VAR(tm);
                    208:        if(localtime_r(&ti,&tm)==NULL)
                    209:                return(0);
                    210: 
                    211:        if(isoTime!=NULL)
                    212:                *isoTime=isoTime_create(tm.tm_hour,tm.tm_min,tm.tm_sec);
                    213: 
                    214:        return isoDate_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday);
                    215: }
                    216: 
                    217: isoTime_t time_to_isoTime(time_t ti)
                    218: {
                    219:        isoTime_t isoTime;
                    220:        
                    221:        time_to_isoDateTime(ti,&isoTime);
                    222: 
                    223:        return isoTime;
                    224: }
                    225: 
                    226: isoDate_t gmtime_to_isoDateTime(time_t ti, isoTime_t* isoTime)
                    227: {
                    228:        struct tm tm;
                    229: 
                    230:        if(isoTime!=NULL)
                    231:                *isoTime=0;
                    232: 
                    233:        ZERO_VAR(tm);
                    234:        if(gmtime_r(&ti,&tm)==NULL)
                    235:                return(0);
                    236: 
                    237:        if(isoTime!=NULL)
                    238:                *isoTime=isoTime_create(tm.tm_hour,tm.tm_min,tm.tm_sec);
                    239: 
                    240:        return isoDate_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday);
                    241: }
                    242: 
                    243: isoTime_t gmtime_to_isoTime(time_t ti)
                    244: {
                    245:        isoTime_t isoTime;
                    246:        
                    247:        gmtime_to_isoDateTime(ti,&isoTime);
                    248: 
                    249:        return isoTime;
                    250: }
                    251: 
                    252: time_t isoDateTime_to_time(isoDate_t date, isoTime_t ti)
                    253: {
                    254:        struct tm tm;
                    255: 
                    256:        ZERO_VAR(tm);
                    257: 
                    258:        if(date==0)
                    259:                return(INVALID_TIME);
                    260: 
                    261:        tm.tm_year      = isoDate_year(date);
                    262:        tm.tm_mon       = isoDate_month(date);
                    263:        tm.tm_mday      = isoDate_day(date);
                    264: 
                    265:        tm.tm_hour      = isoTime_hour(ti);
                    266:        tm.tm_min       = isoTime_minute(ti);
                    267:        tm.tm_sec       = isoTime_second(ti);
                    268: 
                    269:        return sane_mktime(&tm);
                    270: }
                    271: 
                    272: /****************************************************************************/
                    273: /* Conversion from xpDate/Time/Zone to isoDate/Time/Zone Strings                       */
                    274: /****************************************************************************/
                    275: 
                    276: char* xpDate_to_isoDateStr(xpDate_t date, const char* sep, char* str, size_t maxlen)
                    277: {
                    278:        if(sep==NULL)
                    279:                sep="-";
                    280: 
                    281:        snprintf(str,maxlen,"%04u%s%02u%s%02u"
                    282:                ,date.year      ,sep
                    283:                ,date.month     ,sep
                    284:                ,date.day);
                    285: 
                    286:        return str;
                    287: }
                    288: 
                    289: /* precision   example output
                    290:  * -2                  "14"
                    291:  * -1                  "14:02"
                    292:  * 0            "14:02:39"
                    293:  * 1            "14:02:39.8"
                    294:  * 2            "14:02:39.82"
                    295:  * 3            "14:02:39.829"
                    296:  */
                    297: char* xpTime_to_isoTimeStr(xpTime_t ti, const char* sep, int precision
                    298:                                                                   ,char* str, size_t maxlen)
                    299: {
                    300:        if(sep==NULL)
                    301:                sep=":";
                    302: 
                    303:        if(precision < -1)                      /* HH */
                    304:                snprintf(str, maxlen, "%02u", ti.hour);
                    305:        else if(precision < 0)          /* HH:MM */
                    306:                snprintf(str, maxlen, "%02u%s%02u"
                    307:                        ,ti.hour                ,sep
                    308:                        ,ti.minute
                    309:                        );
                    310:        else                                            /* HH:MM:SS[.fract] */
                    311:                snprintf(str, maxlen, "%02u%s%02u%s%0*.*f"
                    312:                        ,ti.hour                ,sep
                    313:                        ,ti.minute              ,sep
                    314:                        ,precision ? (precision+3) : 2
                    315:                        ,precision
                    316:                        ,ti.second
                    317:                        );
                    318: 
                    319:        return str;
                    320: }
                    321: 
                    322: char* xpTimeZone_to_isoTimeZoneStr(xpTimeZone_t zone, const char* sep
                    323:                                                                   ,char *str, size_t maxlen)
                    324: {
                    325:        xpTimeZone_t    tz=zone;
                    326: 
                    327:        if(tz==xpTimeZone_UTC)
                    328:                return "Z";
                    329: 
                    330:        if(sep==NULL)
                    331:                sep=":";
                    332: 
                    333:        if(tz<0)
                    334:                tz=-tz;
                    335: 
                    336:        snprintf(str,maxlen,"%c%02u%s%02u"
                    337:                ,zone < 0 ? '-':'+'
                    338:                ,tz/60
                    339:                ,sep
                    340:                ,tz%60);
                    341: 
                    342:        return str;
                    343: }
                    344: 
                    345: char* xpDateTime_to_isoDateTimeStr(xpDateTime_t dt
                    346:                                                                   ,const char* date_sep, const char* datetime_sep, const char* time_sep
                    347:                                                                   ,int precision
                    348:                                                                   ,char* str, size_t maxlen)
                    349: {
                    350:        char                    tz_str[16];
                    351:        char                    date_str[16];
                    352:        char                    time_str[16];
                    353:        
                    354:        if(datetime_sep==NULL)  datetime_sep="T";
                    355: 
                    356:        snprintf(str,maxlen,"%s%s%s%s"
                    357:                ,xpDate_to_isoDateStr(dt.date, date_sep, date_str, sizeof(date_str))
                    358:                ,datetime_sep
                    359:                ,xpTime_to_isoTimeStr(dt.time, time_sep, precision, time_str, sizeof(time_str))
                    360:                ,xpTimeZone_to_isoTimeZoneStr(dt.zone,time_sep,tz_str,sizeof(tz_str)));
                    361: 
                    362:        return str;
                    363: }
                    364: 
                    365: /****************************************************************************/
                    366: /* isoDate/Time/Zone String parsing functions                                                          */
                    367: /****************************************************************************/
                    368: 
                    369: BOOL isoTimeZoneStr_parse(const char* str, xpTimeZone_t* zone)
                    370: {
                    371:        unsigned hour=0,minute=0;
                    372: 
                    373:        switch(*str) {
                    374:                case 0:         /* local time-zone */
                    375:                        *zone = xpTimeZone_local();     
                    376:                        return TRUE;    
                    377:                case 'Z':       /* UTC */
                    378:                        *zone = xpTimeZone_UTC;         
                    379:                        return TRUE;
                    380:                case '+':
                    381:                case '-':       /* "+/- HH[:]MM" */
                    382:                        if(sscanf(str+1,"%2u%*s%2u",&hour,&minute)>=1) {
                    383:                                *zone = (hour*60) + minute;
                    384:                                if(*str=='-')
                    385:                                        *zone = -(*zone);
                    386:                                return TRUE;
                    387:                        }
                    388:                        break;
                    389:        }
                    390:        return FALSE;
                    391: }
                    392: 
                    393: /* TODO: adjust times in 24:xx:xx format */
                    394: xpDateTime_t isoDateTimeStr_parse(const char* str)
                    395: {
                    396:        char zone[16];
                    397:        xpDateTime_t    xpDateTime;
                    398: 
                    399:        zone[0]=0;
                    400:        ZERO_VAR(xpDateTime);
                    401: 
                    402:        if((sscanf(str,"%4u-%2u-%2uT%2u:%2u:%f%6s"              /* CCYY-MM-DDThh:MM:ss�hhmm */
                    403:                ,&xpDateTime.date.year
                    404:                ,&xpDateTime.date.month
                    405:                ,&xpDateTime.date.day
                    406:                ,&xpDateTime.time.hour
                    407:                ,&xpDateTime.time.minute
                    408:                ,&xpDateTime.time.second
                    409:                ,zone)>=2
                    410:        ||      sscanf(str,"%4u%2u%2uT%2u%2u%f%6s"                      /* CCYYMMDDThhmmss�hhmm */
                    411:                ,&xpDateTime.date.year
                    412:                ,&xpDateTime.date.month
                    413:                ,&xpDateTime.date.day
                    414:                ,&xpDateTime.time.hour
                    415:                ,&xpDateTime.time.minute
                    416:                ,&xpDateTime.time.second
                    417:                ,zone)>=4
                    418:        ||      sscanf(str,"%4u%2u%2u%2u%2u%f%6s"                       /* CCYYMMDDhhmmss�hhmm */
                    419:                ,&xpDateTime.date.year
                    420:                ,&xpDateTime.date.month
                    421:                ,&xpDateTime.date.day
                    422:                ,&xpDateTime.time.hour
                    423:                ,&xpDateTime.time.minute
                    424:                ,&xpDateTime.time.second
                    425:                ,zone)>=1
                    426:                ) && isoTimeZoneStr_parse(zone,&xpDateTime.zone))
                    427:                return xpDateTime;
                    428: 
                    429:        return xpDateTime;
                    430: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.