home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / datetime.c < prev    next >
C/C++ Source or Header  |  2002-07-05  |  10KB  |  352 lines

  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 Möller.
  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.  
  352.