home *** CD-ROM | disk | FTP | other *** search
/ pc.louisiana.edu/pub/unix/ / Louisiana_UNIX.tar / Louisiana_UNIX / date+.zoo / mktime.shar < prev    next >
Text File  |  1991-10-10  |  6KB  |  206 lines

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