home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD2.bin / bbs / gnu / sh-utils-1.12-src.lha / sh-utils-1.12 / lib / mktime.c < prev    next >
C/C++ Source or Header  |  1994-09-27  |  14KB  |  504 lines

  1. /* Copyright (C) 1993, 1994 Free Software Foundation, Inc.
  2.    Contributed by Noel Cragg (noel@cs.oberlin.edu), with fixes by
  3.    Michael E. Calwas (calwas@ttd.teradyne.com) and
  4.    Wade Hampton (tasi029@tmn.com).
  5.  
  6.  
  7. NOTE: The canonical source of this file is maintained with the GNU C Library.
  8. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
  9.  
  10. This program is free software; you can redistribute it and/or modify it
  11. under the terms of the GNU General Public License as published by the
  12. Free Software Foundation; either version 2, or (at your option) any
  13. later version.
  14.  
  15. This program is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. GNU General Public License for more details.
  19.  
  20. You should have received a copy of the GNU General Public License
  21. along with this program; if not, write to the Free Software
  22. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  23.  
  24. /* Define this to have a standalone program to test this implementation of
  25.    mktime.  */
  26. /* #define DEBUG */
  27.  
  28. #ifdef HAVE_CONFIG_H
  29. #include <config.h>
  30. #endif
  31.  
  32. #include <sys/types.h>        /* Some systems define `time_t' here.  */
  33. #include <time.h>
  34.  
  35.  
  36. #ifndef __isleap
  37. /* Nonzero if YEAR is a leap year (every 4 years,
  38.    except every 100th isn't, and every 400th is).  */
  39. #define    __isleap(year)    \
  40.   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
  41. #endif
  42.  
  43. #ifndef __P
  44. #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
  45. #define __P(args) args
  46. #else
  47. #define __P(args) ()
  48. #endif  /* GCC.  */
  49. #endif  /* Not __P.  */
  50.  
  51. /* How many days are in each month.  */
  52. const unsigned short int __mon_lengths[2][12] =
  53.   {
  54.     /* Normal years.  */
  55.     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  56.     /* Leap years.  */
  57.     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  58.   };
  59.  
  60.  
  61. static int times_through_search; /* This library routine should never
  62.                     hang -- make sure we always return
  63.                     when we're searching for a value */
  64.  
  65.  
  66. #ifdef DEBUG
  67.  
  68. #include <stdio.h>
  69. #include <ctype.h>
  70.  
  71. int debugging_enabled = 0;
  72.  
  73. /* Print the values in a `struct tm'. */
  74. static void
  75. printtm (it)
  76.      struct tm *it;
  77. {
  78.   printf ("%02d/%02d/%04d %02d:%02d:%02d (%s) yday:%03d dst:%d gmtoffset:%ld",
  79.       it->tm_mon + 1,
  80.       it->tm_mday,
  81.       it->tm_year + 1900,
  82.       it->tm_hour,
  83.       it->tm_min,
  84.       it->tm_sec,
  85.       it->tm_zone,
  86.       it->tm_yday,
  87.       it->tm_isdst,
  88.       it->tm_gmtoff);
  89. }
  90. #endif
  91.  
  92.  
  93. static time_t
  94. dist_tm (t1, t2)
  95.      struct tm *t1;
  96.      struct tm *t2;
  97. {
  98.   time_t distance = 0;
  99.   unsigned long int v1, v2;
  100.   int diff_flag = 0;
  101.  
  102.   v1 = v2 = 0;
  103.  
  104. #define doit(x, secs)                                                         \
  105.   v1 += t1->x * secs;                                                         \
  106.   v2 += t2->x * secs;                                                         \
  107.   if (!diff_flag)                                                             \
  108.     {                                                                         \
  109.       if (t1->x < t2->x)                                                      \
  110.     diff_flag = -1;                                                       \
  111.       else if (t1->x > t2->x)                                                 \
  112.     diff_flag = 1;                                                        \
  113.     }
  114.   
  115.   doit (tm_year, 31536000);    /* Okay, not all years have 365 days. */
  116.   doit (tm_mon, 2592000);    /* Okay, not all months have 30 days. */
  117.   doit (tm_mday, 86400);
  118.   doit (tm_hour, 3600);
  119.   doit (tm_min, 60);
  120.   doit (tm_sec, 1);
  121.   
  122. #undef doit
  123.   
  124.   /* We should also make sure that the sign of DISTANCE is correct -- if
  125.      DIFF_FLAG is positive, the distance should be positive and vice versa. */
  126.   
  127.   distance = (v1 > v2) ? (v1 - v2) : (v2 - v1);
  128.   if (diff_flag < 0)
  129.     distance = -distance;
  130.  
  131.   if (times_through_search > 20) /* Arbitrary # of calls, but makes sure we
  132.                     never hang if there's a problem with
  133.                     this algorithm.  */
  134.     {
  135.       distance = diff_flag;
  136.     }
  137.  
  138.   /* We need this DIFF_FLAG business because it is forseeable that the
  139.      distance may be zero when, in actuality, the two structures are
  140.      different.  This is usually the case when the dates are 366 days apart
  141.      and one of the years is a leap year.  */
  142.  
  143.   if (distance == 0 && diff_flag)
  144.     distance = 86400 * diff_flag;
  145.  
  146.   return distance;
  147. }
  148.       
  149.  
  150. /* MKTIME converts the values in a struct tm to a time_t.  The values
  151.    in tm_wday and tm_yday are ignored; other values can be put outside
  152.    of legal ranges since they will be normalized.  This routine takes
  153.    care of that normalization. */
  154.  
  155. void
  156. do_normalization (tmptr)
  157.      struct tm *tmptr;
  158. {
  159.  
  160. #define normalize(foo,x,y,bar); \
  161.   while (tmptr->foo < x) \
  162.     { \
  163.       tmptr->bar--; \
  164.       tmptr->foo = (y - (x - tmptr->foo) + 1); \
  165.     } \
  166.   while (tmptr->foo > y) \
  167.     { \
  168.       tmptr->foo = (x + (tmptr->foo - y) - 1); \
  169.       tmptr->bar++; \
  170.     }
  171.   
  172.   normalize (tm_sec, 0, 59, tm_min);
  173.   normalize (tm_min, 0, 59, tm_hour);
  174.   normalize (tm_hour, 0, 23, tm_mday);
  175.   
  176.   /* Do the month first, so day range can be found. */
  177.   normalize (tm_mon, 0, 11, tm_year);
  178.  
  179.   /* Since the day range modifies the month, we should be careful how
  180.      we reference the array of month lengths -- it is possible that
  181.      the month will go negative, hence the modulo...
  182.  
  183.      Also, tm_year is the year - 1900, so we have to 1900 to have it
  184.      work correctly. */
  185.  
  186.   normalize (tm_mday, 1,
  187.          __mon_lengths[__isleap (tmptr->tm_year + 1900)]
  188.                           [((tmptr->tm_mon < 0)
  189.                 ? (12 + (tmptr->tm_mon % 12))
  190.                 : (tmptr->tm_mon % 12)) ],
  191.          tm_mon);
  192.  
  193.   /* Do the month again, because the day may have pushed it out of range. */
  194.   normalize (tm_mon, 0, 11, tm_year);
  195.  
  196.   /* Do the day again, because the month may have changed the range. */
  197.   normalize (tm_mday, 1,
  198.          __mon_lengths[__isleap (tmptr->tm_year + 1900)]
  199.                       [((tmptr->tm_mon < 0)
  200.                 ? (12 + (tmptr->tm_mon % 12))
  201.                 : (tmptr->tm_mon % 12)) ],
  202.          tm_mon);
  203.   
  204. #ifdef DEBUG
  205.   if (debugging_enabled)
  206.     {
  207.       printf ("   After normalizing:\n     ");
  208.       printtm (tmptr);
  209.       putchar ('\n');
  210.     }
  211. #endif
  212.  
  213. }
  214.  
  215.  
  216. /* Here's where the work gets done. */
  217.  
  218. #define BAD_STRUCT_TM ((time_t) -1)
  219.  
  220. time_t
  221. _mktime_internal (timeptr, producer)
  222.      struct tm *timeptr;
  223.      struct tm *(*producer) __P ((const time_t *));
  224. {
  225.   struct tm our_tm;        /* our working space */
  226.   struct tm *me = &our_tm;    /* a pointer to the above */
  227.   time_t result;        /* the value we return */
  228.  
  229.   *me = *timeptr;        /* copy the struct tm that was passed
  230.                    in by the caller */
  231.  
  232.  
  233.   /***************************/
  234.   /* Normalize the structure */
  235.   /***************************/
  236.  
  237.   /* This routine assumes that the value of TM_ISDST is -1, 0, or 1.
  238.      If the user didn't pass it in that way, fix it. */
  239.  
  240.   if (me->tm_isdst > 0)
  241.     me->tm_isdst = 1;
  242.   else if (me->tm_isdst < 0)
  243.     me->tm_isdst = -1;
  244.  
  245.   do_normalization (me);
  246.  
  247.   /* Get out of here if it's not possible to represent this struct.
  248.      If any of the values in the normalized struct tm are negative,
  249.      our algorithms won't work.  Luckily, we only need to check the
  250.      year at this point; normalization guarantees that all values will
  251.      be in correct ranges EXCEPT the year. */
  252.  
  253.   if (me->tm_year < 0)
  254.     return BAD_STRUCT_TM;
  255.  
  256.   /*************************************************/
  257.   /* Find the appropriate time_t for the structure */
  258.   /*************************************************/
  259.  
  260.   /* Modified b-search -- make intelligent guesses as to where the
  261.      time might lie along the timeline, assuming that our target time
  262.      lies a linear distance (w/o considering time jumps of a
  263.      particular region).
  264.  
  265.      Assume that time does not fluctuate at all along the timeline --
  266.      e.g., assume that a day will always take 86400 seconds, etc. --
  267.      and come up with a hypothetical value for the time_t
  268.      representation of the struct tm TARGET, in relation to the guess
  269.      variable -- it should be pretty close!
  270.  
  271.      After testing this, the maximum number of iterations that I had
  272.      on any number that I tried was 3!  Not bad.
  273.  
  274.      Th