/* *@@sourcefile datetime.c: * contains various date and time helper functions. * Some functions in here are OS/2-specific, others * are plain C code. * * Functions marked with (C) Ray Gardner are from * "scaldate.c": * scalar date routines -- public domain by Ray Gardner * These will work over the range 1/01/01 thru 14699/12/31 * * Usage: All OS/2 programs. * * Function prefixes (new with V0.81): * -- dat* date/time helper functions * * Note: Version numbering in this file relates to XWorkplace version * numbering. * *@@header "helpers\datetime.h" *@@added V0.9.0 [umoeller] */ /* * This file Copyright (C) 1997-2000 Ulrich M”ller. * This file is part of the "XWorkplace helpers" source package. * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, in version 2 as it comes in the * "COPYING" file of the XWorkplace main distribution. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define OS2EMX_PLAIN_CHAR // this is needed for "os2emx.h"; if this is defined, // emx will define PSZ as _signed_ char, otherwise // as unsigned char #define INCL_DOSMISC #include #include #include "setup.h" // code generation and debugging options #include "helpers\datetime.h" #pragma hdrstop /* *@@category: Helpers\C helpers\Date/time helpers * See datetime.c. */ /******************************************************************* * * * Private declarations * * * ******************************************************************/ const char *pcszFormatTimestamp = "%4u%02u%02u%02u%02u%02u%"; ULONG G_ulDateScalarFirstCalled = 0; /* *@@ dtGetULongTime: * this returns the current time as a ULONG value (in milliseconds). * Useful for stopping how much time the machine has spent in * a certain function. To do this, simply call this function twice, * and subtract the two values, which will give you the execution * time in milliseconds. * * A ULONG can hold a max value of 4'294'967'295. * So this overflows after 49.71... days. * *@@changed V0.9.7 (2000-12-08) [umoeller]: replaced, now using DosQuerySysInfo(QSV_MS_COUNT) */ ULONG dtGetULongTime(VOID) { ULONG ulTimeNow; DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &ulTimeNow, sizeof(ulTimeNow)); return ulTimeNow; } /* *@@ dtCreateFileTimeStamp: * this creates a time stamp string in pszTimeStamp * from the given FDATE and FTIME structures (which * are, for example, used in the FILESTATUS3 structure * returned by DosQueryPathInfo). * * The time stamp string is exactly 15 bytes in length * (including the terminating null byte) and has the * following format: + YYYYMMDDhhmmss * (being year, mondth, day, hours, minutes, seconds). * Your buffer must be large enough for that, this is * not checked. * * This time stamp can be used to compare two dates * simply by calling strcmp. * * Note that since FTIME only has a two-seconds resolution, * the seconds part of the time stamp will have that too. * * This returns the string length (excluding the null * terminator), which should be 14. * *@@added V0.9.0 [umoeller] */ int dtCreateFileTimeStamp(PSZ pszTimeStamp, // out: time stamp FDATE* pfdate, // in: date FTIME* pftime) // in: time { return sprintf(pszTimeStamp, pcszFormatTimestamp, pfdate->year + 1980, pfdate->month, pfdate->day, pftime->hours, pftime->minutes, pftime->twosecs * 2); } /* *@@ dtCreateDosTimeStamp: * just like dtCreateFileTimeStamp, * except that this takes a DATETIME * structure as input. The time stamp * string is exactly the same. * *@@added V0.9.0 [umoeller] */ int dtCreateDosTimeStamp(PSZ pszTimeStamp, DATETIME* pdt) { return sprintf(pszTimeStamp, pcszFormatTimestamp, pdt->year, pdt->month, pdt->day, pdt->hours, pdt->minutes, pdt->seconds); } /* ** ** ** day: day of month ** mon: month (1-12) ** yr: year ** ** */ /* *@@ dtDayOfWeek: * returns an integer that represents the day of * the week for the date passed as parameters. * * Returns 0-6 where 0 is sunday. * *@@added V0.9.7 (2000-12-05) [umoeller] */ ULONG dtDayOfWeek(ULONG day, ULONG mon, // 1-12 ULONG yr) { int dow; if (mon <= 2) { mon += 12; yr -= 1; } dow = ( day + mon * 2 + ((mon + 1) * 6) / 10 + yr + yr / 4 - yr / 100 + yr / 400 + 2); dow = dow % 7; return ((dow ? dow : 7) - 1); } /* *@@ dtIsLeapYear: * returns TRUE if yr is a leap year. * * (W) Ray Gardner. Public domain. */ int dtIsLeapYear(unsigned yr) { return ( (yr % 400 == 0) || ( (yr % 4 == 0) && (yr % 100 != 0) ) ); } /* *@@ dtMonths2Days: * returns the no. of days for the beginning * of "month" (starting from 1). * * For example, if you pass 1 (for january), * you get 0 because there's no days at jan 1st * yet. * * If you pass 2 (for february), you get 31. * * If you pass 3 (for march), you get 61. * * This is useful for computing a day index * for a given month/day pair. Pass the month * in here and add (day-1); for march 3rd, * you then get 63. * * (W) Ray Gardner. Public domain. */ unsigned dtMonths2Days(unsigned month) { return (month * 3057 - 3007) / 100; } /* *@@ dtYears2Days: * converts a year to the no. of days passed. * * (W) Ray Gardner. Public domain. */ long dtYears2Days (unsigned yr) { return ( yr * 365L + yr / 4 - yr / 100 + yr / 400); } /* *@@ dtDate2Scalar: * returns a scalar (i.e. the no. of days) for * the given date. * * (W) Ray Gardner. Public domain. */ long dtDate2Scalar(unsigned yr, // in: year (e.g. 1999) unsigned mo, // in: month (1-12) unsigned day) // in: day (1-31) { long scalar; scalar = day + dtMonths2Days(mo); if ( mo > 2 ) /* adjust if past February */ scalar -= dtIsLeapYear(yr) ? 1 : 2; yr--; scalar += dtYears2Days(yr); return scalar; } /* *@@ dtScalar2Date: * * * (W) Ray Gardner. Public domain. */ void dtScalar2Date(long scalar, // in: date scalar unsigned *pyr, // out: year (e.g. 1999) unsigned *pmo, // out: month (1-12) unsigned *pday) // out: day (1-31) { unsigned n; /* compute inverse of dtYears2Days() */ for ( n = (unsigned)((scalar * 400L) / 146097); dtYears2Days(n) < scalar;) n++; /* 146097 == dtYears2Days(400) */ *pyr = n; n = (unsigned)(scalar - dtYears2Days(n-1)); if ( n > 59 ) /* adjust if past February */ { n += 2; if ( dtIsLeapYear(*pyr) ) n -= n > 62 ? 1 : 2; } *pmo = (n * 100 + 3007) / 3057; /* inverse of dtMonths2Days() */ *pday = n - dtMonths2Days(*pmo); } /* *@@ dtIsValidDate: * returns TRUE if the given date is valid. * *@@added V0.9.7 (2000-12-05) [umoeller] */ BOOL dtIsValidDate(LONG day, // in: day (1-31) LONG month, // in: month (1-12) ULONG year) // in: year (e.g. 1999) { if (day > 0) { switch( month ) { case 1 : case 3 : case 5 : case 7 : case 8 : case 10 : case 12 : if (day <= 31) return TRUE; break; case 4 : case 6 : case 9 : case 11 : if (day <= 30) return TRUE; break; case 2 : if (day < 29) return TRUE; else if (day == 29) if (dtIsLeapYear(year)) return TRUE; } } return FALSE; }