| 1 |  | 
|---|
| 2 | /* | 
|---|
| 3 | *@@sourcefile datetime.c: | 
|---|
| 4 | *      contains various date and time helper functions. | 
|---|
| 5 | *      Some functions in here are OS/2-specific, others | 
|---|
| 6 | *      are plain C code. | 
|---|
| 7 | * | 
|---|
| 8 | *      Functions marked with (C) Ray Gardner are from | 
|---|
| 9 | *      "scaldate.c": | 
|---|
| 10 | *          scalar date routines    --    public domain by Ray Gardner | 
|---|
| 11 | *          These will work over the range 1/01/01 thru 14699/12/31 | 
|---|
| 12 | * | 
|---|
| 13 | *      Usage: All OS/2 programs. | 
|---|
| 14 | * | 
|---|
| 15 | *      Function prefixes (new with V0.81): | 
|---|
| 16 | *      --  dat*   date/time helper functions | 
|---|
| 17 | * | 
|---|
| 18 | *      Note: Version numbering in this file relates to XWorkplace version | 
|---|
| 19 | *            numbering. | 
|---|
| 20 | * | 
|---|
| 21 | *@@header "helpers\datetime.h" | 
|---|
| 22 | *@@added V0.9.0 [umoeller] | 
|---|
| 23 | */ | 
|---|
| 24 |  | 
|---|
| 25 | /* | 
|---|
| 26 | *      This file Copyright (C) 1997-2000 Ulrich Mller. | 
|---|
| 27 | *      This file is part of the "XWorkplace helpers" source package. | 
|---|
| 28 | *      This is free software; you can redistribute it and/or modify | 
|---|
| 29 | *      it under the terms of the GNU General Public License as published | 
|---|
| 30 | *      by the Free Software Foundation, in version 2 as it comes in the | 
|---|
| 31 | *      "COPYING" file of the XWorkplace main distribution. | 
|---|
| 32 | *      This program is distributed in the hope that it will be useful, | 
|---|
| 33 | *      but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 34 | *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 35 | *      GNU General Public License for more details. | 
|---|
| 36 | */ | 
|---|
| 37 |  | 
|---|
| 38 | #define OS2EMX_PLAIN_CHAR | 
|---|
| 39 | // this is needed for "os2emx.h"; if this is defined, | 
|---|
| 40 | // emx will define PSZ as _signed_ char, otherwise | 
|---|
| 41 | // as unsigned char | 
|---|
| 42 |  | 
|---|
| 43 | #define INCL_DOSMISC | 
|---|
| 44 | #include <os2.h> | 
|---|
| 45 |  | 
|---|
| 46 | #include <stdio.h> | 
|---|
| 47 |  | 
|---|
| 48 | #include "setup.h"                      // code generation and debugging options | 
|---|
| 49 |  | 
|---|
| 50 | #include "helpers\datetime.h" | 
|---|
| 51 |  | 
|---|
| 52 | #pragma hdrstop | 
|---|
| 53 |  | 
|---|
| 54 | /* | 
|---|
| 55 | *@@category: Helpers\C helpers\Date/time helpers | 
|---|
| 56 | *      See datetime.c. | 
|---|
| 57 | */ | 
|---|
| 58 |  | 
|---|
| 59 | /******************************************************************* | 
|---|
| 60 | *                                                                 * | 
|---|
| 61 | *  Private declarations                                           * | 
|---|
| 62 | *                                                                 * | 
|---|
| 63 | ******************************************************************/ | 
|---|
| 64 |  | 
|---|
| 65 | const char  *pcszFormatTimestamp = "%4u%02u%02u%02u%02u%02u%"; | 
|---|
| 66 |  | 
|---|
| 67 | ULONG G_ulDateScalarFirstCalled = 0; | 
|---|
| 68 |  | 
|---|
| 69 | /* | 
|---|
| 70 | *@@ dtGetULongTime: | 
|---|
| 71 | *      this returns the current time as a ULONG value (in milliseconds). | 
|---|
| 72 | *      Useful for stopping how much time the machine has spent in | 
|---|
| 73 | *      a certain function. To do this, simply call this function twice, | 
|---|
| 74 | *      and subtract the two values, which will give you the execution | 
|---|
| 75 | *      time in milliseconds. | 
|---|
| 76 | * | 
|---|
| 77 | *      A ULONG can hold a max value of 4'294'967'295. | 
|---|
| 78 | *      So this overflows after 49.71... days. | 
|---|
| 79 | * | 
|---|
| 80 | *@@changed V0.9.7 (2000-12-08) [umoeller]: replaced, now using DosQuerySysInfo(QSV_MS_COUNT) | 
|---|
| 81 | */ | 
|---|
| 82 |  | 
|---|
| 83 | ULONG dtGetULongTime(VOID) | 
|---|
| 84 | { | 
|---|
| 85 | ULONG ulTimeNow; | 
|---|
| 86 | DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, | 
|---|
| 87 | &ulTimeNow, | 
|---|
| 88 | sizeof(ulTimeNow)); | 
|---|
| 89 | return ulTimeNow; | 
|---|
| 90 | } | 
|---|
| 91 |  | 
|---|
| 92 | /* | 
|---|
| 93 | *@@ dtCreateFileTimeStamp: | 
|---|
| 94 | *      this creates a time stamp string in pszTimeStamp | 
|---|
| 95 | *      from the given FDATE and FTIME structures (which | 
|---|
| 96 | *      are, for example, used in the FILESTATUS3 structure | 
|---|
| 97 | *      returned by DosQueryPathInfo). | 
|---|
| 98 | * | 
|---|
| 99 | *      The time stamp string is exactly 15 bytes in length | 
|---|
| 100 | *      (including the terminating null byte) and has the | 
|---|
| 101 | *      following format: | 
|---|
| 102 | +          YYYYMMDDhhmmss | 
|---|
| 103 | *      (being year, mondth, day, hours, minutes, seconds). | 
|---|
| 104 | *      Your buffer must be large enough for that, this is | 
|---|
| 105 | *      not checked. | 
|---|
| 106 | * | 
|---|
| 107 | *      This time stamp can be used to compare two dates | 
|---|
| 108 | *      simply by calling strcmp. | 
|---|
| 109 | * | 
|---|
| 110 | *      Note that since FTIME only has a two-seconds resolution, | 
|---|
| 111 | *      the seconds part of the time stamp will have that too. | 
|---|
| 112 | * | 
|---|
| 113 | *      This returns the string length (excluding the null | 
|---|
| 114 | *      terminator), which should be 14. | 
|---|
| 115 | * | 
|---|
| 116 | *@@added V0.9.0 [umoeller] | 
|---|
| 117 | */ | 
|---|
| 118 |  | 
|---|
| 119 | int dtCreateFileTimeStamp(PSZ pszTimeStamp,      // out: time stamp | 
|---|
| 120 | FDATE* pfdate,         // in: date | 
|---|
| 121 | FTIME* pftime)         // in: time | 
|---|
| 122 | { | 
|---|
| 123 | return sprintf(pszTimeStamp, | 
|---|
| 124 | pcszFormatTimestamp, | 
|---|
| 125 | pfdate->year + 1980, | 
|---|
| 126 | pfdate->month, | 
|---|
| 127 | pfdate->day, | 
|---|
| 128 | pftime->hours, | 
|---|
| 129 | pftime->minutes, | 
|---|
| 130 | pftime->twosecs * 2); | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | /* | 
|---|
| 134 | *@@ dtCreateDosTimeStamp: | 
|---|
| 135 | *      just like dtCreateFileTimeStamp, | 
|---|
| 136 | *      except that this takes a DATETIME | 
|---|
| 137 | *      structure as input. The time stamp | 
|---|
| 138 | *      string is exactly the same. | 
|---|
| 139 | * | 
|---|
| 140 | *@@added V0.9.0 [umoeller] | 
|---|
| 141 | */ | 
|---|
| 142 |  | 
|---|
| 143 | int dtCreateDosTimeStamp(PSZ pszTimeStamp, | 
|---|
| 144 | DATETIME* pdt) | 
|---|
| 145 | { | 
|---|
| 146 | return sprintf(pszTimeStamp, | 
|---|
| 147 | pcszFormatTimestamp, | 
|---|
| 148 | pdt->year, | 
|---|
| 149 | pdt->month, | 
|---|
| 150 | pdt->day, | 
|---|
| 151 | pdt->hours, | 
|---|
| 152 | pdt->minutes, | 
|---|
| 153 | pdt->seconds); | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | /* | 
|---|
| 157 | ** | 
|---|
| 158 | ** | 
|---|
| 159 | **   day:    day of month | 
|---|
| 160 | **   mon:    month (1-12) | 
|---|
| 161 | **   yr:     year | 
|---|
| 162 | ** | 
|---|
| 163 | ** | 
|---|
| 164 | */ | 
|---|
| 165 |  | 
|---|
| 166 | /* | 
|---|
| 167 | *@@ dtDayOfWeek: | 
|---|
| 168 | *      returns an integer that represents the day of | 
|---|
| 169 | *      the week for the date passed as parameters. | 
|---|
| 170 | * | 
|---|
| 171 | *      Returns 0-6 where 0 is sunday. | 
|---|
| 172 | * | 
|---|
| 173 | *@@added V0.9.7 (2000-12-05) [umoeller] | 
|---|
| 174 | */ | 
|---|
| 175 |  | 
|---|
| 176 | ULONG dtDayOfWeek(ULONG day, | 
|---|
| 177 | ULONG mon,    // 1-12 | 
|---|
| 178 | ULONG yr) | 
|---|
| 179 | { | 
|---|
| 180 | int dow; | 
|---|
| 181 |  | 
|---|
| 182 | if (mon <= 2) | 
|---|
| 183 | { | 
|---|
| 184 | mon += 12; | 
|---|
| 185 | yr -= 1; | 
|---|
| 186 | } | 
|---|
| 187 | dow = (   day | 
|---|
| 188 | + mon * 2 | 
|---|
| 189 | + ((mon + 1) * 6) / 10 | 
|---|
| 190 | + yr | 
|---|
| 191 | + yr / 4 | 
|---|
| 192 | - yr / 100 | 
|---|
| 193 | + yr / 400 | 
|---|
| 194 | + 2); | 
|---|
| 195 | dow = dow % 7; | 
|---|
| 196 | return ((dow ? dow : 7) - 1); | 
|---|
| 197 | } | 
|---|
| 198 |  | 
|---|
| 199 | /* | 
|---|
| 200 | *@@ dtIsLeapYear: | 
|---|
| 201 | *      returns TRUE if yr is a leap year. | 
|---|
| 202 | * | 
|---|
| 203 | *      (W) Ray Gardner. Public domain. | 
|---|
| 204 | */ | 
|---|
| 205 |  | 
|---|
| 206 | int dtIsLeapYear(unsigned yr) | 
|---|
| 207 | { | 
|---|
| 208 | return (    (yr % 400 == 0) | 
|---|
| 209 | || (    (yr % 4 == 0) | 
|---|
| 210 | && (yr % 100 != 0) | 
|---|
| 211 | ) | 
|---|
| 212 | ); | 
|---|
| 213 | } | 
|---|
| 214 |  | 
|---|
| 215 | /* | 
|---|
| 216 | *@@ dtMonths2Days: | 
|---|
| 217 | *      returns the no. of days for the beginning | 
|---|
| 218 | *      of "month" (starting from 1). | 
|---|
| 219 | * | 
|---|
| 220 | *      For example, if you pass 1 (for january), | 
|---|
| 221 | *      you get 0 because there's no days at jan 1st | 
|---|
| 222 | *      yet. | 
|---|
| 223 | * | 
|---|
| 224 | *      If you pass 2 (for february), you get 31. | 
|---|
| 225 | * | 
|---|
| 226 | *      If you pass 3 (for march), you get 61. | 
|---|
| 227 | * | 
|---|
| 228 | *      This is useful for computing a day index | 
|---|
| 229 | *      for a given month/day pair. Pass the month | 
|---|
| 230 | *      in here and add (day-1); for march 3rd, | 
|---|
| 231 | *      you then get 63. | 
|---|
| 232 | * | 
|---|
| 233 | *      (W) Ray Gardner. Public domain. | 
|---|
| 234 | */ | 
|---|
| 235 |  | 
|---|
| 236 | unsigned dtMonths2Days(unsigned month) | 
|---|
| 237 | { | 
|---|
| 238 | return (month * 3057 - 3007) / 100; | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 | /* | 
|---|
| 242 | *@@ dtYears2Days: | 
|---|
| 243 | *      converts a year to the no. of days passed. | 
|---|
| 244 | * | 
|---|
| 245 | *      (W) Ray Gardner. Public domain. | 
|---|
| 246 | */ | 
|---|
| 247 |  | 
|---|
| 248 | long dtYears2Days (unsigned yr) | 
|---|
| 249 | { | 
|---|
| 250 | return ( yr * 365L | 
|---|
| 251 | + yr / 4 | 
|---|
| 252 | - yr / 100 | 
|---|
| 253 | + yr / 400); | 
|---|
| 254 | } | 
|---|
| 255 |  | 
|---|
| 256 | /* | 
|---|
| 257 | *@@ dtDate2Scalar: | 
|---|
| 258 | *      returns a scalar (i.e. the no. of days) for | 
|---|
| 259 | *      the given date. | 
|---|
| 260 | * | 
|---|
| 261 | *      (W) Ray Gardner. Public domain. | 
|---|
| 262 | */ | 
|---|
| 263 |  | 
|---|
| 264 | long dtDate2Scalar(unsigned yr,     // in: year     (e.g. 1999) | 
|---|
| 265 | unsigned mo,     // in: month    (1-12) | 
|---|
| 266 | unsigned day)    // in: day      (1-31) | 
|---|
| 267 | { | 
|---|
| 268 | long scalar; | 
|---|
| 269 | scalar = day + dtMonths2Days(mo); | 
|---|
| 270 | if ( mo > 2 )                         /* adjust if past February */ | 
|---|
| 271 | scalar -= dtIsLeapYear(yr) ? 1 : 2; | 
|---|
| 272 | yr--; | 
|---|
| 273 | scalar += dtYears2Days(yr); | 
|---|
| 274 | return scalar; | 
|---|
| 275 | } | 
|---|
| 276 |  | 
|---|
| 277 | /* | 
|---|
| 278 | *@@ dtScalar2Date: | 
|---|
| 279 | * | 
|---|
| 280 | * | 
|---|
| 281 | *      (W) Ray Gardner. Public domain. | 
|---|
| 282 | */ | 
|---|
| 283 |  | 
|---|
| 284 | void dtScalar2Date(long scalar,     // in: date scalar | 
|---|
| 285 | unsigned *pyr,   // out: year    (e.g. 1999) | 
|---|
| 286 | unsigned *pmo,   // out: month   (1-12) | 
|---|
| 287 | unsigned *pday)  // out: day     (1-31) | 
|---|
| 288 | { | 
|---|
| 289 | unsigned n;                /* compute inverse of dtYears2Days() */ | 
|---|
| 290 |  | 
|---|
| 291 | for ( n = (unsigned)((scalar * 400L) / 146097); dtYears2Days(n) < scalar;) | 
|---|
| 292 | n++;                          /* 146097 == dtYears2Days(400) */ | 
|---|
| 293 | *pyr = n; | 
|---|
| 294 | n = (unsigned)(scalar - dtYears2Days(n-1)); | 
|---|
| 295 | if ( n > 59 )    /* adjust if past February */ | 
|---|
| 296 | { | 
|---|
| 297 | n += 2; | 
|---|
| 298 | if ( dtIsLeapYear(*pyr) ) | 
|---|
| 299 | n -= n > 62 ? 1 : 2; | 
|---|
| 300 | } | 
|---|
| 301 | *pmo = (n * 100 + 3007) / 3057;  /* inverse of dtMonths2Days() */ | 
|---|
| 302 | *pday = n - dtMonths2Days(*pmo); | 
|---|
| 303 | } | 
|---|
| 304 |  | 
|---|
| 305 | /* | 
|---|
| 306 | *@@ dtIsValidDate: | 
|---|
| 307 | *      returns TRUE if the given date is valid. | 
|---|
| 308 | * | 
|---|
| 309 | *@@added V0.9.7 (2000-12-05) [umoeller] | 
|---|
| 310 | */ | 
|---|
| 311 |  | 
|---|
| 312 | BOOL dtIsValidDate(LONG day,      // in: day (1-31) | 
|---|
| 313 | LONG month,    // in: month (1-12) | 
|---|
| 314 | ULONG year)    // in: year (e.g. 1999) | 
|---|
| 315 | { | 
|---|
| 316 | if (day > 0) | 
|---|
| 317 | { | 
|---|
| 318 | switch( month ) | 
|---|
| 319 | { | 
|---|
| 320 | case 1  : | 
|---|
| 321 | case 3  : | 
|---|
| 322 | case 5  : | 
|---|
| 323 | case 7  : | 
|---|
| 324 | case 8  : | 
|---|
| 325 | case 10 : | 
|---|
| 326 | case 12 : | 
|---|
| 327 | if (day <= 31) | 
|---|
| 328 | return (TRUE); | 
|---|
| 329 | break; | 
|---|
| 330 |  | 
|---|
| 331 | case 4  : | 
|---|
| 332 | case 6  : | 
|---|
| 333 | case 9  : | 
|---|
| 334 | case 11 : | 
|---|
| 335 | if (day <= 30) | 
|---|
| 336 | return (TRUE); | 
|---|
| 337 | break; | 
|---|
| 338 |  | 
|---|
| 339 | case 2 : | 
|---|
| 340 | if (day < 29) | 
|---|
| 341 | return (TRUE); | 
|---|
| 342 | else | 
|---|
| 343 | if (day == 29) | 
|---|
| 344 | if (dtIsLeapYear(year)) | 
|---|
| 345 | return TRUE; | 
|---|
| 346 | } | 
|---|
| 347 | } | 
|---|
| 348 |  | 
|---|
| 349 | return FALSE; | 
|---|
| 350 | } | 
|---|
| 351 |  | 
|---|