home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2178 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  5.3 KB

  1. From: jfh@rpp386.cactus.org (John F. Haugh II)
  2. Newsgroups: alt.sources
  3. Subject: mktime() function (was: Re: UNIX-Time ...)
  4. Message-ID: <18767@rpp386.cactus.org>
  5. Date: 1 Dec 90 01:21:19 GMT
  6.  
  7. This is the last and final mktime()-like function.  It has been
  8. tested for several million values of "time" and seems to work
  9. quite perfectly.  One of the tests covered a random time over a
  10. several year stretch, comparing the value input to localtime()
  11. against the value returned by mktime() when handed the output
  12. of localtime().  It was also tested for over 10 million other
  13. values as well, all of which returned the same exact value for
  14. "time" that was initially fed to localtime().
  15.  
  16. This version includes support for the tm_isdst structure member,
  17. which is something which Boyd left out of his original version,
  18. and which is responsible for the ambiguity between which 1:51:45
  19. his function computed the time for last October 28th.
  20.  
  21. Below are the performance results of executing the two functions
  22. 1,000 times each.  The driver function consists of
  23.  
  24. main ()
  25. {
  26.     long    i, t;
  27.     struct    tm    tm;
  28.  
  29.     i = 12345678L;
  30.     tm = *(localtime (&i));
  31.  
  32.     for (i = 0;i < 100000000;i += 100000)
  33. #ifdef    BOYD
  34.         t = gmsecs (&tm);
  35. #else
  36.         t = mktime (&tm);
  37. #endif
  38. }
  39.  
  40. % timex ./bfoo
  41. execution complete, exit code = 1
  42.  
  43. real            21.81
  44. user            21.76
  45. sys             0.05
  46. % timex ./jfoo
  47. execution complete, exit code = 1
  48.  
  49. real             1.79
  50. user             1.73
  51. sys             0.04
  52. % calc 21.81 / 1.79
  53.      12.18435754189944
  54.  
  55. OK, so it's only 12 times faster instead of 15.  Sue me ;-)  Both
  56. were compiled with optimization turned on (-Ox) on a 16Mhz 386.
  57. Your milage may vary.  I really didn't mean for this to be an
  58. attack on Boyd's code - I had initially made my suggestion about
  59. making a more educated guess to improve upon his code, not to
  60. replace it.
  61.  
  62. And now for the source code ...
  63.  
  64. ----- cut and save as mktime.c -----
  65. /*
  66.  * Copyright 1990, John F. Haugh II
  67.  * All rights reserved.
  68.  *
  69.  * Use, duplication, and disclosure prohibited without
  70.  * the express written permission of the author.
  71.  *
  72.  * Non-commercial (not for profit) source code distribution
  73.  * is permitted, provided this notice remains intact.
  74.  */
  75.  
  76. #include <time.h>
  77.  
  78. /*
  79.  * days and juldays are used to compute the number of days in the
  80.  * current month, and the cummulative number of days in the preceding
  81.  * months.
  82.  */
  83.  
  84. static    short    days[12] = {
  85.     31,    28,    31,    30,    31,    30,    /* JAN - JUN */
  86.     31,    31,    30,    31,    30,    31 };    /* JUL - DEC */
  87.  
  88. static    short    juldays[12] = {
  89.     0,    31,    59,    90,    120,    151,    /* JAN - JUN */
  90.     181,    212,    243,    273,    304,    334 };    /* JUL - DEC */
  91.  
  92. static time_t
  93. dtime (tm, time)
  94. struct    tm    *tm;
  95. time_t    time;
  96. {
  97.     struct    tm    *sm;
  98.     time_t    diff;
  99.     time_t    julian1, julian2;
  100.  
  101.     sm = localtime (&time);
  102.  
  103.     julian1 = ((tm->tm_year - 70) * 365) +    /* days in whole years */
  104.         (((tm->tm_year + 1) - 70) / 4);    /* days in leap years */
  105.     julian1 += juldays[tm->tm_mon] +    /* days in whole months */
  106.         (tm->tm_mon > 1 && (tm->tm_year % 4) == 0 ? 1:0); /* leap day */
  107.     julian1 += tm->tm_mday - 1;        /* days so far this month */
  108.  
  109.     julian2 = ((sm->tm_year - 70) * 365) +    /* days in whole years */
  110.         (((sm->tm_year + 1) - 70) / 4);    /* days in leap years */
  111.     julian2 += juldays[sm->tm_mon] +    /* days in whole months */
  112.         (sm->tm_mon > 1 && (sm->tm_year % 4) == 0 ? 1:0); /* leap day */
  113.     julian2 += sm->tm_mday - 1;        /* days so far this month */
  114.  
  115.     diff = (julian1 - julian2) * (24L*3600);    /* add the days */
  116.     diff += (tm->tm_hour - sm->tm_hour) * (3600L);    /* add the hours */
  117.     diff += (tm->tm_min - sm->tm_min) * (60L);    /* add the minutes */
  118.     diff += (tm->tm_sec - sm->tm_sec);        /* add the seconds */
  119.  
  120.     if (daylight && ((tm->tm_isdst == 0) != (sm->tm_isdst == 0))) {
  121.         if (tm->tm_isdst)
  122.             diff -= (timezone - altzone);
  123.         if (sm->tm_isdst)
  124.             diff += (timezone - altzone);
  125.     }
  126.     return diff;                /* that's how far off */
  127. }
  128.  
  129. time_t
  130. mktime (tm)
  131. struct    tm    *tm;
  132. {
  133.     time_t    init, diff;
  134.     int    i;
  135.  
  136.     /*
  137.      * Let's validate the tm structure.
  138.      */
  139.  
  140.     if (! tm || tm->tm_year < 0 || tm->tm_year > 200
  141.         || tm->tm_mon < 0 || tm->tm_mon > 11
  142.         || tm->tm_mday < 0    /* other half later */
  143.         || tm->tm_hour < 0 || tm->tm_hour > 23
  144.         || tm->tm_min < 0 || tm->tm_min > 59
  145.         || tm->tm_sec < 0 || tm->tm_sec > 59)
  146.         return -1L;
  147.  
  148.     if (tm->tm_mon == 2 && tm->tm_year % 4 == 0) {
  149.         if (tm->tm_mday > 29)
  150.             return -1L;
  151.     } else if (tm->tm_mday > days[tm->tm_mon])
  152.         return -1L;
  153.  
  154.     /*
  155.      * POSIX says that tzset() must be called to get the
  156.      * timezone information. [ "AS-IF" tzset() were called ]
  157.      */
  158.  
  159.     tzset ();
  160.  
  161.     /*
  162.      * The first guess is within a few hours, the second
  163.      * guess should get it exactly right.  A third guess
  164.      * may be needed in some cases.
  165.      *
  166.      * In practice the first call is exact and the second
  167.      * call is only needed to verify this.  Bizarre behavior
  168.      * around daylight savings time could trip this up, so
  169.      * I go again just to make sure.
  170.      */
  171.  
  172.     if ((init = dtime (tm, 0L)) == 0)
  173.         return init;
  174.  
  175.     if ((diff = dtime (tm, init)) == 0)
  176.         return init;
  177.  
  178.     if ((diff = dtime (tm, init += diff)) == 0)
  179.         return init;
  180.  
  181.     /*
  182.      * The difference had better be less than a minute
  183.      * by this time or the date is probably invalid
  184.      * some how.
  185.      */
  186.  
  187.     if (diff < -60 || diff > 60)
  188.         return -1;
  189.  
  190.     return init + diff;
  191. }
  192. -- 
  193. John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
  194. Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org
  195. "SCCS, the source motel!  Programs check in and never check out!"
  196.         -- Ken Thompson
  197.