From c0eefe7fef0298b557fc235b4c47cee12de29e7d Mon Sep 17 00:00:00 2001 From: rswindell <> Date: Sat, 23 Feb 2008 10:57:55 +0000 Subject: [PATCH] Moved time-related functions from genwrap.* to datewrap.*. Moved xpDateTime and isoDateTime functions from datewrap.* to xpdatetime.*. Created several new xp and ISO date time functions and macros. --- src/xpdev/datewrap.c | 300 ++++++------------------------- src/xpdev/datewrap.h | 110 +++--------- src/xpdev/genwrap.c | 54 ------ src/xpdev/genwrap.h | 16 +- src/xpdev/xpdatetime.c | 395 +++++++++++++++++++++++++++++++++++++++++ src/xpdev/xpdatetime.h | 148 +++++++++++++++ src/xpdev/xpdev.dsp | 4 + src/xpdev/xpdev_mt.dsp | 4 + 8 files changed, 637 insertions(+), 394 deletions(-) create mode 100644 src/xpdev/xpdatetime.c create mode 100644 src/xpdev/xpdatetime.h diff --git a/src/xpdev/datewrap.c b/src/xpdev/datewrap.c index 37cf81e6cb..5b6a3ee970 100644 --- a/src/xpdev/datewrap.c +++ b/src/xpdev/datewrap.c @@ -1,6 +1,6 @@ /* datewrap.c */ -/* Wrappers for Borland getdate() and gettime() functions */ +/* Wrappers for non-standard date and time functions */ /* $Id$ */ @@ -8,7 +8,7 @@ * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2005 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2008 Rob Swindell - http://www.synchro.net/copyright.html * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * @@ -37,7 +37,7 @@ #include "string.h" /* memset */ #include "genwrap.h" -#include "datewrap.h" /* xpDateTime_t */ +#include "datewrap.h" /* Compensates for struct tm "weirdness" */ time_t sane_mktime(struct tm* tm) @@ -51,256 +51,18 @@ time_t sane_mktime(struct tm* tm) return mktime(tm); } -/**************************************/ -/* Cross-platform date/time functions */ -/**************************************/ - -xpDateTime_t xpDateTime_create(unsigned year, unsigned month, unsigned day - ,unsigned hour, unsigned minute, float second - ,xpTimeZone_t zone) -{ - xpDateTime_t xpDateTime; - - xpDateTime.date.year = year; - xpDateTime.date.month = month; - xpDateTime.date.day = day; - xpDateTime.time.hour = hour; - xpDateTime.time.minute = minute; - xpDateTime.time.second = second; - xpDateTime.zone = zone; - - return xpDateTime; -} - -xpDateTime_t xpDateTime_now(void) -{ -#if defined(_WIN32) - SYSTEMTIME systime; - - GetLocalTime(&systime); - return(xpDateTime_create(systime.wYear,systime.wMonth,systime.wDay - ,systime.wHour,systime.wMinute,(float)systime.wSecond+(systime.wMilliseconds*0.001F) - ,xpTimeZone_local())); -#else /* !Win32 (e.g. Unix) */ - struct tm tm; - struct timeval tv; - time_t t; - - gettimeofday(&tv, NULL); - t=tv.tv_sec; - localtime_r(&t,&tm); - - return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday - ,tm.tm_hour,tm.tm_min,(float)tm.tm_sec+(tv.tv_usec*0.00001) - ,xpTimeZone_local()); -#endif -} - -xpTimeZone_t xpTimeZone_local(void) -{ -#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DARWIN__) - struct tm tm; - time_t t; - - localtime_r(&t, &tm); - return(tm.tm_gmtoff/60); -#else -#if defined(__BORLANDC__) || defined(__CYGWIN__) - #define timezone _timezone -#endif - - /* Converts (_)timezone from seconds west of UTC to minutes east of UTC */ - return -timezone/60; -#endif -} - -time_t xpDateTime_to_time(xpDateTime_t xpDateTime) -{ - struct tm tm; - - ZERO_VAR(tm); - - if(xpDateTime.date.year==0) - return(0); - - tm.tm_year = xpDateTime.date.year; - tm.tm_mon = xpDateTime.date.month; - tm.tm_mday = xpDateTime.date.day; - - tm.tm_hour = xpDateTime.time.hour; - tm.tm_min = xpDateTime.time.minute; - tm.tm_sec = (int)xpDateTime.time.second; - - return sane_mktime(&tm); - -} - -xpDateTime_t time_to_xpDateTime(time_t ti) -{ - xpDateTime_t never; - struct tm tm; - - memset(&never,0,sizeof(never)); - if(ti==0) - return(never); - - ZERO_VAR(tm); - if(gmtime_r(&ti,&tm)==NULL) - return(never); - - return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday - ,tm.tm_hour,tm.tm_min,(float)tm.tm_sec,xpTimeZone_local()); -} - -/**********************************************/ -/* Decimal-coded ISO-8601 date/time functions */ -/**********************************************/ - -isoDate_t xpDateTime_to_isoDateTime(xpDateTime_t xpDateTime, isoTime_t* isoTime) -{ - if(isoTime!=NULL) - *isoTime=0; - - if(xpDateTime.date.year==0) - return(0); - - if(isoTime!=NULL) - *isoTime=isoTime_create(xpDateTime.time.hour,xpDateTime.time.minute,xpDateTime.time.second); - - return isoDate_create(xpDateTime.date.year,xpDateTime.date.month,xpDateTime.date.day); -} - -xpDateTime_t isoDateTime_to_xpDateTime(isoDate_t date, isoTime_t ti) -{ - return xpDateTime_create(isoDate_year(date),isoDate_month(date),isoDate_day(date) - ,isoTime_hour(ti),isoTime_minute(ti),(float)isoTime_second(ti),xpTimeZone_local()); -} - -isoDate_t time_to_isoDateTime(time_t ti, isoTime_t* isoTime) -{ - struct tm tm; - - if(isoTime!=NULL) - *isoTime=0; - - if(ti==0) - return(0); - - ZERO_VAR(tm); - if(gmtime_r(&ti,&tm)==NULL) - return(0); - - if(isoTime!=NULL) - *isoTime=isoTime_create(tm.tm_hour,tm.tm_min,tm.tm_sec); - - return isoDate_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday); -} - -isoTime_t time_to_isoTime(time_t ti) -{ - isoTime_t isoTime; - - time_to_isoDateTime(ti,&isoTime); - - return isoTime; -} - -time_t isoDateTime_to_time(isoDate_t date, isoTime_t ti) -{ - struct tm tm; - - ZERO_VAR(tm); - - if(date==0) - return(0); - - tm.tm_year = isoDate_year(date); - tm.tm_mon = isoDate_month(date); - tm.tm_mday = isoDate_day(date); - - tm.tm_hour = isoTime_hour(ti); - tm.tm_min = isoTime_minute(ti); - tm.tm_sec = isoTime_second(ti); - - return sane_mktime(&tm); -} - -BOOL isoTimeZone_parse(const char* str, xpTimeZone_t* zone) -{ - unsigned hour=0,minute=0; - - switch(*str) { - case 0: /* local time-zone */ - *zone = xpTimeZone_local(); - return TRUE; - case 'Z': /* UTC */ - *zone = 0; - return TRUE; - case '+': - case '-': /* "+/- HH[:]MM" */ - if(sscanf(str+1,"%2u%*s%2u",&hour,&minute)>=1) { - *zone = (hour*60) + minute; - if(*str=='-') - *zone = -(*zone); - return TRUE; - } - break; - } - return FALSE; -} - -xpDateTime_t isoDateTime_parse(const char* str) -{ - char zone[16]; - xpDateTime_t xpDateTime; - - zone[0]=0; - ZERO_VAR(xpDateTime); - - if((sscanf(str,"%4u-%2u-%2uT%2u:%2u:%f%6s" /* CCYY-MM-DDThh:MM:ss�hhmm */ - ,&xpDateTime.date.year - ,&xpDateTime.date.month - ,&xpDateTime.date.day - ,&xpDateTime.time.hour - ,&xpDateTime.time.minute - ,&xpDateTime.time.second - ,zone)>=2 - || sscanf(str,"%4u%2u%2uT%2u%2u%f%6s" /* CCYYMMDDThhmmss�hhmm */ - ,&xpDateTime.date.year - ,&xpDateTime.date.month - ,&xpDateTime.date.day - ,&xpDateTime.time.hour - ,&xpDateTime.time.minute - ,&xpDateTime.time.second - ,zone)>=4 - || sscanf(str,"%4u%2u%2u%2u%2u%f%6s" /* CCYYMMDDhhmmss�hhmm */ - ,&xpDateTime.date.year - ,&xpDateTime.date.month - ,&xpDateTime.date.day - ,&xpDateTime.time.hour - ,&xpDateTime.time.minute - ,&xpDateTime.time.second - ,zone)>=1 - ) && isoTimeZone_parse(zone,&xpDateTime.zone)) - return xpDateTime; - - return xpDateTime; -} +#if !defined(__BORLANDC__) /***********************************/ /* Borland DOS date/time functions */ /***********************************/ -#if !defined(__BORLANDC__) - #if defined(_WIN32) #include <windows.h> /* SYSTEMTIME and GetLocalTime() */ #else #include <sys/time.h> /* stuct timeval, gettimeofday() */ #endif -#include "datewrap.h" /* struct defs, verify prototypes */ - void xp_getdate(struct date* nyd) { time_t tim; @@ -339,3 +101,57 @@ void gettime(struct time* nyt) } #endif /* !Borland */ + +#if !defined(__unix__) + +/****************************************************************************/ +/* Win32 implementations of the recursive (thread-safe) versions of std C */ +/* time functions (gmtime, localtime, ctime, and asctime) used in Unix. */ +/* The native Win32 versions of these functions are already thread-safe. */ +/****************************************************************************/ + +struct tm* DLLCALL gmtime_r(const time_t* t, struct tm* tm) +{ + struct tm* tmp = gmtime(t); + + if(tmp==NULL) + return(NULL); + + *tm = *tmp; + return(tm); +} + +struct tm* DLLCALL localtime_r(const time_t* t, struct tm* tm) +{ + struct tm* tmp = localtime(t); + + if(tmp==NULL) + return(NULL); + + *tm = *tmp; + return(tm); +} + +char* DLLCALL ctime_r(const time_t *t, char *buf) +{ + char* p = ctime(t); + + if(p==NULL) + return(NULL); + + strcpy(buf,p); + return(buf); +} + +char* DLLCALL asctime_r(const struct tm *tm, char *buf) +{ + char* p = asctime(tm); + + if(p==NULL) + return(NULL); + + strcpy(buf,p); + return(buf); +} + +#endif /* !defined(__unix__) */ diff --git a/src/xpdev/datewrap.h b/src/xpdev/datewrap.h index c32d1e4827..33a8a50aea 100644 --- a/src/xpdev/datewrap.h +++ b/src/xpdev/datewrap.h @@ -1,6 +1,6 @@ /* datewrap.h */ -/* Wrappers for Borland getdate() and gettime() functions */ +/* Wrappers for non-standard date and time functions */ /* $Id$ */ @@ -8,7 +8,7 @@ * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2005 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2008 Rob Swindell - http://www.synchro.net/copyright.html * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * @@ -40,79 +40,28 @@ #include "genwrap.h" /* time_t */ -/* Compensates for struct tm "weirdness" */ -time_t sane_mktime(struct tm*); - -/**************************************/ -/* Cross-platform date/time functions */ -/**************************************/ - -typedef struct { - unsigned year; - unsigned month; - unsigned day; -} xpDate_t; - -typedef struct { - unsigned hour; - unsigned minute; - float second; /* supports fractional seconds */ -} xpTime_t; - -typedef int xpTimeZone_t; - -typedef struct { - xpDate_t date; - xpTime_t time; - xpTimeZone_t zone; /* minutes +/- UTC */ -} xpDateTime_t; - -xpDateTime_t xpDateTime_create(unsigned year, unsigned month, unsigned day - ,unsigned hour, unsigned minute, float second - ,xpTimeZone_t); -xpDateTime_t xpDateTime_now(void); -time_t xpDateTime_to_time(xpDateTime_t); -xpDateTime_t time_to_xpDateTime(time_t); -xpTimeZone_t xpTimeZone_local(void); - -/**********************************************/ -/* Decimal-coded ISO-8601 date/time functions */ -/**********************************************/ - -typedef uint32_t isoDate_t; /* CCYYMMDD (decimal) */ -typedef uint32_t isoTime_t; /* HHMMSS (decimal) */ - -#define isoDate_create(year,mon,day) (((year)*10000)+((mon)*100)+(day)) -#define isoTime_create(hour,min,sec) (((hour)*10000)+((min)*100)+((unsigned)sec)) - -#define isoDate_year(date) ((date)/10000) -#define isoDate_month(date) (((date)/100)%100) -#define isoDate_day(date) ((date)%100) - -#define isoTime_hour(time) ((time)/10000) -#define isoTime_minute(time) (((time)/100)%100) -#define isoTime_second(time) ((time)%100) - -BOOL isoTimeZone_parse(const char* str, xpTimeZone_t*); -xpDateTime_t isoDateTime_parse(const char* str); - -/**********************************************/ -/* Conversion between time_t and isoDate/Time */ -/**********************************************/ -isoTime_t time_to_isoTime(time_t); -isoDate_t time_to_isoDateTime(time_t, isoTime_t*); -time_t isoDateTime_to_time(isoDate_t, isoTime_t); -#define time_to_isoDate(t) time_to_isoDateTime(t,NULL) - -/***************************************************/ -/* Conversion between xpDate/Time and isoDate/Time */ -/***************************************************/ - -#define xpDate_to_isoDate(date) isoDate_create((date).year,(date).month,(date).day) -#define xpTime_to_isoTime(time) isoTime_create((time).hour,(time).minute,(unsigned)((time).second)) - -xpDateTime_t isoDateTime_to_xpDateTime(isoDate_t, isoTime_t); -isoDate_t xpDateTime_to_isoDateTime(xpDateTime_t, isoTime_t*); +#if defined(__cplusplus) +extern "C" { +#endif + +/* Implementation of mktime() that handles common tm element conversions for you */ +time_t sane_mktime(struct tm* tm); + +/*********************************************************************************/ +/* Win32 implementations of recursive (thread-safe) std C time functions on Unix */ +/*********************************************************************************/ + +#if !defined(__unix__) + + #include <time.h> /* time_t, etc. */ + + DLLEXPORT struct tm* DLLCALL gmtime_r(const time_t* t, struct tm* tm); + DLLEXPORT struct tm* DLLCALL localtime_r(const time_t* t, struct tm* tm); + DLLEXPORT char* DLLCALL ctime_r(const time_t *t, char *buf); + DLLEXPORT char* DLLCALL asctime_r(const struct tm *tm, char *buf); + DLLEXPORT char* DLLCALL strtok_r(char *str, const char *delim, char **last); + +#endif /***********************************/ /* Borland DOS date/time functions */ @@ -137,19 +86,14 @@ struct time { unsigned char ti_sec; }; -#if defined(__cplusplus) -extern "C" { -#endif - #define getdate(x) xp_getdate(x) void xp_getdate(struct date*); void gettime(struct time*); +#endif /* !Borland */ + #if defined(__cplusplus) } #endif -#endif /* !Borland */ - -#endif /* Don't add anything after this line */ - +#endif /* Don't add anything after this line */ \ No newline at end of file diff --git a/src/xpdev/genwrap.c b/src/xpdev/genwrap.c index 9d0df87e1f..b42f897a0d 100644 --- a/src/xpdev/genwrap.c +++ b/src/xpdev/genwrap.c @@ -428,60 +428,6 @@ char* DLLCALL os_cmdshell(void) return(shell); } -#if !defined(__unix__) - -/****************************************************************************/ -/* Win32 implementations of the recursive (thread-safe) versions of std C */ -/* time functions (gmtime, localtime, ctime, and asctime) used in Unix. */ -/* The native Win32 versions of these functions are already thread-safe. */ -/****************************************************************************/ - -struct tm* DLLCALL gmtime_r(const time_t* t, struct tm* tm) -{ - struct tm* tmp = gmtime(t); - - if(tmp==NULL) - return(NULL); - - *tm = *tmp; - return(tm); -} - -struct tm* DLLCALL localtime_r(const time_t* t, struct tm* tm) -{ - struct tm* tmp = localtime(t); - - if(tmp==NULL) - return(NULL); - - *tm = *tmp; - return(tm); -} - -char* DLLCALL ctime_r(const time_t *t, char *buf) -{ - char* p = ctime(t); - - if(p==NULL) - return(NULL); - - strcpy(buf,p); - return(buf); -} - -char* DLLCALL asctime_r(const struct tm *tm, char *buf) -{ - char* p = asctime(tm); - - if(p==NULL) - return(NULL); - - strcpy(buf,p); - return(buf); -} - -#endif /* !defined(__unix__) */ - /****************************************************************/ /* Microsoft (DOS/Win32) real-time system clock implementation. */ /****************************************************************/ diff --git a/src/xpdev/genwrap.h b/src/xpdev/genwrap.h index 56d93ceea4..96915ff64a 100644 --- a/src/xpdev/genwrap.h +++ b/src/xpdev/genwrap.h @@ -40,6 +40,7 @@ #include <stdio.h> /* sprintf */ #include <string.h> /* strerror() */ +#include <time.h> /* clock_t */ #include "gen_defs.h" /* ulong */ #include "wrapdll.h" /* DLLEXPORT and DLLCALL */ @@ -289,24 +290,9 @@ DLLEXPORT int DLLCALL get_errno(void); #endif /* Win32 implementations of recursive (thread-safe) std C time functions on Unix */ - #if !defined(__unix__) - #include <time.h> /* time_t, etc. */ - - DLLEXPORT struct tm* DLLCALL gmtime_r(const time_t* t, struct tm* tm); - DLLEXPORT struct tm* DLLCALL localtime_r(const time_t* t, struct tm* tm); - DLLEXPORT char* DLLCALL ctime_r(const time_t *t, char *buf); - DLLEXPORT char* DLLCALL asctime_r(const struct tm *tm, char *buf); DLLEXPORT char* DLLCALL strtok_r(char *str, const char *delim, char **last); - -#endif - -#if defined(__solaris__) - #define CTIME_R(x,y) ctime_r(x,y) - /* #define CTIME_R(x,y) ctime_r(x,y,sizeof y) */ -#else - #define CTIME_R(x,y) ctime_r(x,y) #endif /* Mimic the Borland randomize() and random() CRTL functions */ diff --git a/src/xpdev/xpdatetime.c b/src/xpdev/xpdatetime.c new file mode 100644 index 0000000000..694c9875c2 --- /dev/null +++ b/src/xpdev/xpdatetime.c @@ -0,0 +1,395 @@ +/* xpdatetime.c */ + +/* Cross-platform (and eXtra Precision) date/time functions */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2008 Rob Swindell - http://www.synchro.net/copyright.html * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#include <string.h> /* memset */ +#include "datewrap.h" /* sane_mktime */ +#include "xpdatetime.h" /* xpDateTime_t */ + +/**************************************/ +/* Cross-platform date/time functions */ +/**************************************/ + +xpDateTime_t xpDateTime_create(unsigned year, unsigned month, unsigned day + ,unsigned hour, unsigned minute, float second + ,xpTimeZone_t zone) +{ + xpDateTime_t xpDateTime; + + xpDateTime.date.year = year; + xpDateTime.date.month = month; + xpDateTime.date.day = day; + xpDateTime.time.hour = hour; + xpDateTime.time.minute = minute; + xpDateTime.time.second = second; + xpDateTime.zone = zone; + + return xpDateTime; +} + +xpDateTime_t xpDateTime_now(void) +{ +#if defined(_WIN32) + SYSTEMTIME systime; + + GetLocalTime(&systime); + return(xpDateTime_create(systime.wYear,systime.wMonth,systime.wDay + ,systime.wHour,systime.wMinute,(float)systime.wSecond+(systime.wMilliseconds*0.001F) + ,xpTimeZone_local())); +#else /* !Win32 (e.g. Unix) */ + struct tm tm; + struct timeval tv; + time_t t; + + gettimeofday(&tv, NULL); + t=tv.tv_sec; + localtime_r(&t,&tm); + + return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday + ,tm.tm_hour,tm.tm_min,(float)tm.tm_sec+(tv.tv_usec*0.00001) + ,xpTimeZone_local()); +#endif +} + +xpTimeZone_t xpTimeZone_local(void) +{ +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DARWIN__) + struct tm tm; + time_t t; + + localtime_r(&t, &tm); + return(tm.tm_gmtoff/60); +#else +#if defined(__BORLANDC__) || defined(__CYGWIN__) + #define timezone _timezone +#endif + + /* Converts (_)timezone from seconds west of UTC to minutes east of UTC */ + return -timezone/60; +#endif +} + +time_t xpDateTime_to_time(xpDateTime_t xpDateTime) +{ + struct tm tm; + + ZERO_VAR(tm); + + if(xpDateTime.date.year==0) + return(INVALID_TIME); + + tm.tm_year = xpDateTime.date.year; + tm.tm_mon = xpDateTime.date.month; + tm.tm_mday = xpDateTime.date.day; + + tm.tm_hour = xpDateTime.time.hour; + tm.tm_min = xpDateTime.time.minute; + tm.tm_sec = (int)xpDateTime.time.second; + + return sane_mktime(&tm); +} + +xpDateTime_t time_to_xpDateTime(time_t time, xpTimeZone_t zone) +{ + xpDateTime_t never; + struct tm tm; + + memset(&never,0,sizeof(never)); + + ZERO_VAR(tm); + if(localtime_r(&time,&tm)==NULL) + return(never); + + return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday + ,tm.tm_hour,tm.tm_min,(float)tm.tm_sec + ,zone==xpTimeZone_LOCAL ? xpTimeZone_local() : zone); +} + +xpDateTime_t gmtime_to_xpDateTime(time_t ti) +{ + xpDateTime_t never; + struct tm tm; + + memset(&never,0,sizeof(never)); + + ZERO_VAR(tm); + if(gmtime_r(&ti,&tm)==NULL) + return(never); + + return xpDateTime_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday + ,tm.tm_hour,tm.tm_min,(float)tm.tm_sec + ,xpTimeZone_UTC); +} + +/**********************************************/ +/* Decimal-coded ISO-8601 date/time functions */ +/**********************************************/ + +isoDate_t xpDateTime_to_isoDateTime(xpDateTime_t xpDateTime, isoTime_t* isoTime) +{ + if(isoTime!=NULL) + *isoTime=0; + + if(xpDateTime.date.year==0) + return(0); + + if(isoTime!=NULL) + *isoTime=isoTime_create(xpDateTime.time.hour,xpDateTime.time.minute,xpDateTime.time.second); + + return isoDate_create(xpDateTime.date.year,xpDateTime.date.month,xpDateTime.date.day); +} + +xpDateTime_t isoDateTime_to_xpDateTime(isoDate_t date, isoTime_t ti) +{ + return xpDateTime_create(isoDate_year(date),isoDate_month(date),isoDate_day(date) + ,isoTime_hour(ti),isoTime_minute(ti),(float)isoTime_second(ti),xpTimeZone_local()); +} + +isoDate_t time_to_isoDateTime(time_t ti, isoTime_t* isoTime) +{ + struct tm tm; + + if(isoTime!=NULL) + *isoTime=0; + + ZERO_VAR(tm); + if(localtime_r(&ti,&tm)==NULL) + return(0); + + if(isoTime!=NULL) + *isoTime=isoTime_create(tm.tm_hour,tm.tm_min,tm.tm_sec); + + return isoDate_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday); +} + +isoTime_t time_to_isoTime(time_t ti) +{ + isoTime_t isoTime; + + time_to_isoDateTime(ti,&isoTime); + + return isoTime; +} + +isoDate_t gmtime_to_isoDateTime(time_t ti, isoTime_t* isoTime) +{ + struct tm tm; + + if(isoTime!=NULL) + *isoTime=0; + + ZERO_VAR(tm); + if(gmtime_r(&ti,&tm)==NULL) + return(0); + + if(isoTime!=NULL) + *isoTime=isoTime_create(tm.tm_hour,tm.tm_min,tm.tm_sec); + + return isoDate_create(1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday); +} + +isoTime_t gmtime_to_isoTime(time_t ti) +{ + isoTime_t isoTime; + + gmtime_to_isoDateTime(ti,&isoTime); + + return isoTime; +} + +time_t isoDateTime_to_time(isoDate_t date, isoTime_t time) +{ + struct tm tm; + + ZERO_VAR(tm); + + if(date==0) + return(INVALID_TIME); + + tm.tm_year = isoDate_year(date); + tm.tm_mon = isoDate_month(date); + tm.tm_mday = isoDate_day(date); + + tm.tm_hour = isoTime_hour(time); + tm.tm_min = isoTime_minute(time); + tm.tm_sec = isoTime_second(time); + + return sane_mktime(&tm); +} + +/****************************************************************************/ +/* Conversion from xpDate/Time/Zone to isoDate/Time/Zone Strings */ +/****************************************************************************/ + +char* xpDate_to_isoDateStr(xpDate_t date, const char* sep, char* str, size_t maxlen) +{ + if(sep==NULL) + sep="-"; + + snprintf(str,maxlen,"%04lu%s%02lu%s%02lu" + ,date.year ,sep + ,date.month ,sep + ,date.day); + + return str; +} + +char* xpTime_to_isoTimeStr(xpTime_t time, const char* sep, int precision + ,char* str, size_t maxlen) +{ + if(sep==NULL) + sep=":"; + + snprintf(str, maxlen, "%02lu%s%02lu%s%0*.*f" + ,time.hour ,sep + ,time.minute ,sep + ,precision ? (precision+3) : 2 + ,precision + ,time.second + ); + + return str; +} + +char* xpTimeZone_to_isoTimeZoneStr(xpTimeZone_t zone, const char* sep + ,char *str, size_t maxlen) +{ + xpTimeZone_t tz=zone; + + if(tz==xpTimeZone_UTC) + return "Z"; + + if(sep==NULL) + sep=":"; + + if(tz<0) + tz=-tz; + + snprintf(str,maxlen,"%c%02u%s%02u" + ,zone < 0 ? '-':'+' + ,tz/60 + ,sep + ,tz%60); + + return str; +} + +char* xpDateTime_to_isoDateTimeStr(xpDateTime_t dt + ,const char* date_sep, const char* datetime_sep, const char* time_sep + ,int precision + ,char* str, size_t maxlen) +{ + char tz_str[16]; + char date_str[16]; + char time_str[16]; + + if(datetime_sep==NULL) datetime_sep="T"; + + snprintf(str,maxlen,"%s%s%s%s" + ,xpDate_to_isoDateStr(dt.date, date_sep, date_str, sizeof(date_str)) + ,datetime_sep + ,xpTime_to_isoTimeStr(dt.time, time_sep, precision, time_str, sizeof(time_str)) + ,xpTimeZone_to_isoTimeZoneStr(dt.zone,time_sep,tz_str,sizeof(tz_str))); + + return str; +} + +/****************************************************************************/ +/* isoDate/Time/Zone String parsing functions */ +/****************************************************************************/ + +BOOL isoTimeZoneStr_parse(const char* str, xpTimeZone_t* zone) +{ + unsigned hour=0,minute=0; + + switch(*str) { + case 0: /* local time-zone */ + *zone = xpTimeZone_local(); + return TRUE; + case 'Z': /* UTC */ + *zone = xpTimeZone_UTC; + return TRUE; + case '+': + case '-': /* "+/- HH[:]MM" */ + if(sscanf(str+1,"%2u%*s%2u",&hour,&minute)>=1) { + *zone = (hour*60) + minute; + if(*str=='-') + *zone = -(*zone); + return TRUE; + } + break; + } + return FALSE; +} + +/* TODO: adjust times in 24:xx:xx format */ +xpDateTime_t isoDateTimeStr_parse(const char* str) +{ + char zone[16]; + xpDateTime_t xpDateTime; + + zone[0]=0; + ZERO_VAR(xpDateTime); + + if((sscanf(str,"%4u-%2u-%2uT%2u:%2u:%f%6s" /* CCYY-MM-DDThh:MM:ss�hhmm */ + ,&xpDateTime.date.year + ,&xpDateTime.date.month + ,&xpDateTime.date.day + ,&xpDateTime.time.hour + ,&xpDateTime.time.minute + ,&xpDateTime.time.second + ,zone)>=2 + || sscanf(str,"%4u%2u%2uT%2u%2u%f%6s" /* CCYYMMDDThhmmss�hhmm */ + ,&xpDateTime.date.year + ,&xpDateTime.date.month + ,&xpDateTime.date.day + ,&xpDateTime.time.hour + ,&xpDateTime.time.minute + ,&xpDateTime.time.second + ,zone)>=4 + || sscanf(str,"%4u%2u%2u%2u%2u%f%6s" /* CCYYMMDDhhmmss�hhmm */ + ,&xpDateTime.date.year + ,&xpDateTime.date.month + ,&xpDateTime.date.day + ,&xpDateTime.time.hour + ,&xpDateTime.time.minute + ,&xpDateTime.time.second + ,zone)>=1 + ) && isoTimeZoneStr_parse(zone,&xpDateTime.zone)) + return xpDateTime; + + return xpDateTime; +} diff --git a/src/xpdev/xpdatetime.h b/src/xpdev/xpdatetime.h new file mode 100644 index 0000000000..fe65c2ba59 --- /dev/null +++ b/src/xpdev/xpdatetime.h @@ -0,0 +1,148 @@ +/* xpdatetime.h */ + +/* Cross-platform (and eXtra Precision) date/time functions */ + +/* $Id$ */ + +/**************************************************************************** + * @format.tab-size 4 (Plain Text/Source Code File Header) * + * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * + * * + * Copyright 2008 Rob Swindell - http://www.synchro.net/copyright.html * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * See the GNU Lesser General Public License for more details: lgpl.txt or * + * http://www.fsf.org/copyleft/lesser.html * + * * + * Anonymous FTP access to the most recent released source is available at * + * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * + * * + * Anonymous CVS access to the development source and modification history * + * is available at cvs.synchro.net:/cvsroot/sbbs, example: * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login * + * (just hit return, no password is necessary) * + * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src * + * * + * For Synchronet coding style and modification guidelines, see * + * http://www.synchro.net/source.html * + * * + * You are encouraged to submit any modifications (preferably in Unix diff * + * format) via e-mail to mods@synchro.net * + * * + * Note: If this box doesn't appear square, then you need to fix your tabs. * + ****************************************************************************/ + +#ifndef _XPDATETIME_H_ +#define _XPDATETIME_H_ + +#include "gen_defs.h" /* uint32_t and time_t */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/**************************************/ +/* Cross-platform date/time functions */ +/**************************************/ + +#define INVALID_TIME (time_t)-1 /* time_t representation of an invalid date/time */ + +typedef struct { + unsigned year; /* 0-9999 */ + unsigned month; /* 1-12 */ + unsigned day; /* 1-31 */ +} xpDate_t; + +typedef struct { + unsigned hour; /* 0-23 */ + unsigned minute; /* 0-59 */ + float second; /* 0.0-59.999, supports fractional seconds */ +} xpTime_t; + +typedef int xpTimeZone_t; +#define xpTimeZone_UTC 0 +#define xpTimeZone_LOCAL 1 + +typedef struct { + xpDate_t date; + xpTime_t time; + xpTimeZone_t zone; /* minutes +/- UTC */ +} xpDateTime_t; + +xpDateTime_t xpDateTime_create(unsigned year, unsigned month, unsigned day + ,unsigned hour, unsigned minute, float second + ,xpTimeZone_t); +xpDateTime_t xpDateTime_now(void); +time_t xpDateTime_to_time(xpDateTime_t); +xpDateTime_t time_to_xpDateTime(time_t, xpTimeZone_t); +xpDateTime_t gmtime_to_xpDateTime(time_t); +xpTimeZone_t xpTimeZone_local(void); + +/**********************************************/ +/* Decimal-coded ISO-8601 date/time functions */ +/**********************************************/ + +typedef uint32_t isoDate_t; /* CCYYMMDD (decimal) */ +typedef uint32_t isoTime_t; /* HHMMSS (decimal) */ + +#define isoDate_create(year,mon,day) (((year)*10000)+((mon)*100)+(day)) +#define isoTime_create(hour,min,sec) (((hour)*10000)+((min)*100)+((unsigned)sec)) + +#define isoDate_year(date) ((date)/10000) +#define isoDate_month(date) (((date)/100)%100) +#define isoDate_day(date) ((date)%100) + +#define isoTime_hour(time) ((time)/10000) +#define isoTime_minute(time) (((time)/100)%100) +#define isoTime_second(time) ((time)%100) + +BOOL isoTimeZoneStr_parse(const char* str, xpTimeZone_t*); +xpDateTime_t isoDateTimeStr_parse(const char* str); + +/**************************************************************/ +/* Conversion between time_t (local and GMT) and isoDate/Time */ +/**************************************************************/ +isoTime_t time_to_isoTime(time_t); +isoTime_t gmtime_to_isoTime(time_t); +isoDate_t time_to_isoDateTime(time_t, isoTime_t*); +isoDate_t gmtime_to_isoDateTime(time_t, isoTime_t*); +time_t isoDateTime_to_time(isoDate_t, isoTime_t); +#define time_to_isoDate(t) time_to_isoDateTime(t,NULL) +#define gmtime_to_isoDate(t) gmtime_to_isoDateTime(t,NULL) + +/***************************************************/ +/* Conversion between xpDate/Time and isoDate/Time */ +/***************************************************/ + +#define xpDate_to_isoDate(date) isoDate_create((date).year,(date).month,(date).day) +#define xpTime_to_isoTime(time) isoTime_create((time).hour,(time).minute,(unsigned)((time).second)) + +xpDateTime_t isoDateTime_to_xpDateTime(isoDate_t, isoTime_t); +isoDate_t xpDateTime_to_isoDateTime(xpDateTime_t, isoTime_t*); + +/*****************************************************************/ +/* Conversion from xpDate/Time/Zone to isoDate/Time/Zone Strings */ +/*****************************************************************/ +char* xpDate_to_isoDateStr(xpDate_t + ,const char* sep + ,char* str, size_t maxlen); +char* xpTime_to_isoTimeStr(xpTime_t + ,const char* sep + ,int precision + ,char* str, size_t maxlen); +char* xpTimeZone_to_isoTimeZoneStr(xpTimeZone_t + ,const char* sep + ,char *str, size_t maxlen); +char* xpDateTime_to_isoDateTimeStr(xpDateTime_t + ,const char* date_sep, const char* datetime_sep, const char* time_sep + ,int precision + ,char* str, size_t maxlen); + +#if defined(__cplusplus) +} +#endif + +#endif /* Don't add anything after this line */ \ No newline at end of file diff --git a/src/xpdev/xpdev.dsp b/src/xpdev/xpdev.dsp index f7d5796800..54bde292a9 100644 --- a/src/xpdev/xpdev.dsp +++ b/src/xpdev/xpdev.dsp @@ -126,6 +126,10 @@ SOURCE=.\str_list.c # End Source File # Begin Source File +SOURCE=.\xpdatetime.c +# End Source File +# Begin Source File + SOURCE=.\xpprintf.c # End Source File # End Target diff --git a/src/xpdev/xpdev_mt.dsp b/src/xpdev/xpdev_mt.dsp index a753098699..cb5fea3ed3 100644 --- a/src/xpdev/xpdev_mt.dsp +++ b/src/xpdev/xpdev_mt.dsp @@ -134,6 +134,10 @@ SOURCE=.\threadwrap.c # End Source File # Begin Source File +SOURCE=.\xpdatetime.c +# End Source File +# Begin Source File + SOURCE=.\xpprintf.c # End Source File # End Target -- GitLab