clock_subr.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* $OpenBSD: clock_subr.c,v 1.5 2015/03/14 03:38:50 jsg Exp $ */
  2. /* $NetBSD: clock_subr.c,v 1.3 1997/03/15 18:11:16 is Exp $ */
  3. /*
  4. * Copyright (c) 1988 University of Utah.
  5. * Copyright (c) 1982, 1990, 1993
  6. * The Regents of the University of California. All rights reserved.
  7. *
  8. * This code is derived from software contributed to Berkeley by
  9. * the Systems Programming Group of the University of Utah Computer
  10. * Science Department.
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. * 1. Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in the
  19. * documentation and/or other materials provided with the distribution.
  20. * 3. Neither the name of the University nor the names of its contributors
  21. * may be used to endorse or promote products derived from this software
  22. * without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34. * SUCH DAMAGE.
  35. *
  36. * from: Utah $Hdr: clock.c 1.18 91/01/21$
  37. *
  38. * @(#)clock.c 8.2 (Berkeley) 1/12/94
  39. */
  40. /*
  41. * Generic routines to convert between a POSIX date
  42. * (seconds since 1/1/1970) and yr/mo/day/hr/min/sec
  43. * Derived from arch/hp300/hp300/clock.c
  44. */
  45. #include <sys/types.h>
  46. #include <sys/systm.h>
  47. static inline int leapyear(int year);
  48. #define FEBRUARY 2
  49. #define days_in_year(a) (leapyear(a) ? 366 : 365)
  50. #define days_in_month(a) (month_days[(a) - 1])
  51. static const int month_days[12] = {
  52. 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  53. };
  54. /*
  55. * This inline avoids some unnecessary modulo operations
  56. * as compared with the usual macro:
  57. * ( ((year % 4) == 0 &&
  58. * (year % 100) != 0) ||
  59. * ((year % 400) == 0) )
  60. * It is otherwise equivalent.
  61. */
  62. static inline int
  63. leapyear(int year)
  64. {
  65. int rv = 0;
  66. if ((year & 3) == 0) {
  67. rv = 1;
  68. if ((year % 100) == 0) {
  69. rv = 0;
  70. if ((year % 400) == 0)
  71. rv = 1;
  72. }
  73. }
  74. return (rv);
  75. }
  76. time_t
  77. clock_ymdhms_to_secs(struct clock_ymdhms *dt)
  78. {
  79. time_t secs;
  80. int i, year, days;
  81. year = dt->dt_year;
  82. /*
  83. * Compute days since start of time.
  84. * First from years, then from months.
  85. */
  86. days = 0;
  87. for (i = POSIX_BASE_YEAR; i < year; i++)
  88. days += days_in_year(i);
  89. if (leapyear(year) && dt->dt_mon > FEBRUARY)
  90. days++;
  91. /* Months */
  92. for (i = 1; i < dt->dt_mon; i++)
  93. days += days_in_month(i);
  94. days += (dt->dt_day - 1);
  95. /* Add hours, minutes, seconds. */
  96. secs = (time_t)((days
  97. * 24 + dt->dt_hour)
  98. * 60 + dt->dt_min)
  99. * 60 + dt->dt_sec;
  100. return (secs);
  101. }
  102. /* This function uses a copy of month_days[] */
  103. #undef days_in_month
  104. #define days_in_month(a) (mthdays[(a) - 1])
  105. void
  106. clock_secs_to_ymdhms(time_t secs, struct clock_ymdhms *dt)
  107. {
  108. int mthdays[12];
  109. int i, days;
  110. int rsec; /* remainder seconds */
  111. memcpy(mthdays, month_days, sizeof(mthdays));
  112. days = secs / SECDAY;
  113. rsec = secs % SECDAY;
  114. /* Day of week (Note: 1/1/1970 was a Thursday) */
  115. dt->dt_wday = (days + 4) % 7;
  116. /* Subtract out whole years, counting them in i. */
  117. for (i = POSIX_BASE_YEAR; days >= days_in_year(i); i++)
  118. days -= days_in_year(i);
  119. dt->dt_year = i;
  120. /* Subtract out whole months, counting them in i. */
  121. if (leapyear(i))
  122. days_in_month(FEBRUARY) = 29;
  123. for (i = 1; days >= days_in_month(i); i++)
  124. days -= days_in_month(i);
  125. dt->dt_mon = i;
  126. /* Days are what is left over (+1) from all that. */
  127. dt->dt_day = days + 1;
  128. /* Hours, minutes, seconds are easy */
  129. dt->dt_hour = rsec / 3600;
  130. rsec = rsec % 3600;
  131. dt->dt_min = rsec / 60;
  132. rsec = rsec % 60;
  133. dt->dt_sec = rsec;
  134. }