|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.