mkgmtime.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*this guts of this file come from the following source*/
  2. /*standing on the shoulders of giants and all*/
  3. /*I have stripped it down to minimize gross namespace collisions and*/
  4. /*reduce complexity as I only really need the mkgmtime function*/
  5. /* free mktime function
  6. Copyright 1988, 1989 by David MacKenzie <djm@ai.mit.edu>
  7. and Michael Haertel <mike@ai.mit.edu>
  8. Unlimited distribution permitted provided this copyright notice is
  9. retained and any functional modifications are prominently identified. */
  10. /* Revised 1997 by Christian Spieler:
  11. The code was changed to get more conformance with ANSI's (resp. modern
  12. UNIX releases) definition for mktime():
  13. - Added adjustment for out-of-range values in the fields of struct tm.
  14. - Added iterations to get the correct UTC result for input values at
  15. the gaps when daylight saving time is switched on or off.
  16. - Allow forcing of DST "on" or DST "off" by setting `tm_isdst' field in
  17. the tm struct to positive number resp. zero. The `tm_isdst' field must
  18. be negative on entrance of mktime() to enable automatic determination
  19. if DST is in effect for the requested local time.
  20. - Added optional check for overflowing the time_t range. */
  21. /* Note: This version of mktime is ignorant of the tzfile.
  22. When the tm structure passed to mktime represents a local time that
  23. is valid both as DST time and as standard time (= time value in the
  24. gap when switching from DST back to standard time), the behaviour
  25. for `tm_isdst < 0' depends on the current timezone: TZ east of GMT
  26. assumes winter time, TZ west of GMT assumes summer time.
  27. Although mktime() (resp. mkgmtime()) tries to adjust for invalid values
  28. of struct tm members, this may fail for input values that are far away
  29. from the valid ranges. The adjustment process does not check for overflows
  30. or wrap arounds in the struct tm components. */
  31. #include <time.h>
  32. #include <stdio.h>
  33. #ifndef NO_TIME_T_MAX
  34. /* Provide default values for the upper limit of the time_t range.
  35. These are the result of the decomposition into a `struct tm' for
  36. the time value 0xFFFFFFFEL ( = (time_t)-2 ).
  37. Note: `(time_t)-1' is reserved for "invalid time"! */
  38. # ifndef TM_YEAR_MAX
  39. # define TM_YEAR_MAX 2106
  40. # endif
  41. # ifndef TM_MON_MAX
  42. # define TM_MON_MAX 1 /* February */
  43. # endif
  44. # ifndef TM_MDAY_MAX
  45. # define TM_MDAY_MAX 7
  46. # endif
  47. # ifndef TM_HOUR_MAX
  48. # define TM_HOUR_MAX 6
  49. # endif
  50. # ifndef TM_MIN_MAX
  51. # define TM_MIN_MAX 28
  52. # endif
  53. # ifndef TM_SEC_MAX
  54. # define TM_SEC_MAX 14
  55. # endif
  56. #endif /* NO_TIME_T_MAX */
  57. /* Adjusts out-of-range values for `tm' field `tm_member'. */
  58. #define ADJUST_TM(tm_member, tm_carry, modulus) \
  59. if ((tm_member) < 0) { \
  60. tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
  61. tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
  62. } else if ((tm_member) >= (modulus)) { \
  63. tm_carry += (tm_member) / (modulus); \
  64. tm_member = (tm_member) % (modulus); \
  65. }
  66. /* Nonzero if `y' is a leap year, else zero. */
  67. #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  68. /* Number of leap years from 1970 to `y' (not including `y' itself). */
  69. #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
  70. /* Additional leapday in February of leap years. */
  71. #define leapday(m, y) ((m) == 1 && leap (y))
  72. /* Length of month `m' (0 .. 11) */
  73. #define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y))
  74. /* Accumulated number of days from 01-Jan up to start of current month. */
  75. static const short ydays[] =
  76. {
  77. 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  78. };
  79. /* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
  80. of the Greenwich Mean time and date in the exploded time structure `tm'.
  81. This function does always put back normalized values into the `tm' struct,
  82. parameter, including the calculated numbers for `tm->tm_yday',
  83. `tm->tm_wday', and `tm->tm_isdst'.
  84. Returns -1 if the time in the `tm' parameter cannot be represented
  85. as valid `time_t' number. */
  86. time_t mkgmtime(struct tm *tm)
  87. {
  88. int years, months, days, hours, minutes, seconds;
  89. years = tm->tm_year + 1900; /* year - 1900 -> year */
  90. months = tm->tm_mon; /* 0..11 */
  91. days = tm->tm_mday - 1; /* 1..31 -> 0..30 */
  92. hours = tm->tm_hour; /* 0..23 */
  93. minutes = tm->tm_min; /* 0..59 */
  94. seconds = tm->tm_sec; /* 0..61 in ANSI C. */
  95. ADJUST_TM(seconds, minutes, 60)
  96. ADJUST_TM(minutes, hours, 60)
  97. ADJUST_TM(hours, days, 24)
  98. ADJUST_TM(months, years, 12)
  99. if (days < 0)
  100. do {
  101. if (--months < 0) {
  102. --years;
  103. months = 11;
  104. }
  105. days += monthlen(months, years);
  106. } while (days < 0);
  107. else
  108. while (days >= monthlen(months, years)) {
  109. days -= monthlen(months, years);
  110. if (++months >= 12) {
  111. ++years;
  112. months = 0;
  113. }
  114. }
  115. /* Restore adjusted values in tm structure */
  116. tm->tm_year = years - 1900;
  117. tm->tm_mon = months;
  118. tm->tm_mday = days + 1;
  119. tm->tm_hour = hours;
  120. tm->tm_min = minutes;
  121. tm->tm_sec = seconds;
  122. /* Set `days' to the number of days into the year. */
  123. days += ydays[months] + (months > 1 && leap (years));
  124. tm->tm_yday = days;
  125. /* Now calculate `days' to the number of days since Jan 1, 1970. */
  126. days = (unsigned)days + 365 * (unsigned)(years - 1970) +
  127. (unsigned)(nleap (years));
  128. tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */
  129. tm->tm_isdst = 0;
  130. if (years < 1970)
  131. return (time_t)-1;
  132. #if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
  133. #if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
  134. if (years > TM_YEAR_MAX ||
  135. (years == TM_YEAR_MAX &&
  136. (tm->tm_yday > ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
  137. (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) ||
  138. (tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
  139. (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) &&
  140. (hours > TM_HOUR_MAX ||
  141. (hours == TM_HOUR_MAX &&
  142. (minutes > TM_MIN_MAX ||
  143. (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
  144. return (time_t)-1;
  145. #endif
  146. #endif
  147. return (time_t)(86400L * (unsigned long)(unsigned)days +
  148. 3600L * (unsigned long)hours +
  149. (unsigned long)(60 * minutes + seconds));
  150. }
  151. /*
  152. int main()
  153. {
  154. struct tm crud;
  155. time_t now,then;
  156. now=time(NULL);
  157. gmtime_r(&now,&crud);
  158. then=mkgmtime(&crud);
  159. printf("%d %d",now,then);
  160. printf("Hello World!\n");
  161. }
  162. */