libc_time.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /* Originally released by the musl project (http://www.musl-libc.org/) under the
  2. * MIT license. Taken from the file /src/time/__secs_to_tm.c */
  3. #include <limits.h>
  4. #include "libc_time.h"
  5. /* 2000-03-01 (mod 400 year, immediately after feb29 */
  6. #define LEAPOCH (946684800LL + 86400*(31+29))
  7. #define DAYS_PER_400Y (365*400 + 97)
  8. #define DAYS_PER_100Y (365*100 + 24)
  9. #define DAYS_PER_4Y (365*4 + 1)
  10. int __secs_to_tm(long long t, struct mytm *tm) {
  11. long long days, secs, years;
  12. int remdays, remsecs, remyears;
  13. int qc_cycles, c_cycles, q_cycles;
  14. int months;
  15. static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};
  16. /* Reject time_t values whose year would overflow int */
  17. if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
  18. return -1;
  19. secs = t - LEAPOCH;
  20. days = secs / 86400LL;
  21. remsecs = (int)(secs % 86400);
  22. if (remsecs < 0) {
  23. remsecs += 86400;
  24. --days;
  25. }
  26. qc_cycles = (int)(days / DAYS_PER_400Y);
  27. remdays = (int)(days % DAYS_PER_400Y);
  28. if (remdays < 0) {
  29. remdays += DAYS_PER_400Y;
  30. --qc_cycles;
  31. }
  32. c_cycles = remdays / DAYS_PER_100Y;
  33. if (c_cycles == 4) --c_cycles;
  34. remdays -= c_cycles * DAYS_PER_100Y;
  35. q_cycles = remdays / DAYS_PER_4Y;
  36. if (q_cycles == 25) --q_cycles;
  37. remdays -= q_cycles * DAYS_PER_4Y;
  38. remyears = remdays / 365;
  39. if (remyears == 4) --remyears;
  40. remdays -= remyears * 365;
  41. years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles;
  42. for (months=0; days_in_month[months] <= remdays; ++months)
  43. remdays -= days_in_month[months];
  44. if (years+100 > INT_MAX || years+100 < INT_MIN)
  45. return -1;
  46. tm->tm_year = (int)(years + 100);
  47. tm->tm_mon = months + 2;
  48. if (tm->tm_mon >= 12) {
  49. tm->tm_mon -=12;
  50. ++tm->tm_year;
  51. }
  52. tm->tm_mday = remdays + 1;
  53. tm->tm_hour = remsecs / 3600;
  54. tm->tm_min = remsecs / 60 % 60;
  55. tm->tm_sec = remsecs % 60;
  56. return 0;
  57. }
  58. static const int secs_through_month[] =
  59. {0, 31*86400, 59*86400, 90*86400,
  60. 120*86400, 151*86400, 181*86400, 212*86400,
  61. 243*86400, 273*86400, 304*86400, 334*86400 };
  62. static int
  63. __month_to_secs(int month, int is_leap) {
  64. int t = secs_through_month[month];
  65. if (is_leap && month >= 2)
  66. t+=86400;
  67. return t;
  68. }
  69. static long long
  70. __year_to_secs(const long long year, int *is_leap) {
  71. int cycles, centuries, leaps, rem;
  72. int is_leap_val = 0;
  73. if (!is_leap) {
  74. is_leap = &is_leap_val;
  75. }
  76. cycles = (int)((year-100) / 400);
  77. rem = (int)((year-100) % 400);
  78. if (rem < 0) {
  79. cycles--;
  80. rem += 400;
  81. }
  82. if (!rem) {
  83. *is_leap = 1;
  84. centuries = 0;
  85. leaps = 0;
  86. } else {
  87. if (rem >= 200) {
  88. if (rem >= 300) centuries = 3, rem -= 300;
  89. else centuries = 2, rem -= 200;
  90. } else {
  91. if (rem >= 100) centuries = 1, rem -= 100;
  92. else centuries = 0;
  93. }
  94. if (!rem) {
  95. *is_leap = 0;
  96. leaps = 0;
  97. } else {
  98. leaps = (rem / (int)4U);
  99. rem %= (int)4U;
  100. *is_leap = !rem;
  101. }
  102. }
  103. leaps += 97*cycles + 24*centuries - *is_leap;
  104. return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
  105. }
  106. long long __tm_to_secs(const struct mytm *tm) {
  107. int is_leap;
  108. long long year = tm->tm_year;
  109. int month = tm->tm_mon;
  110. if (month >= 12 || month < 0) {
  111. int adj = month / 12;
  112. month %= 12;
  113. if (month < 0) {
  114. adj--;
  115. month += 12;
  116. }
  117. year += adj;
  118. }
  119. long long t = __year_to_secs(year, &is_leap);
  120. t += __month_to_secs(month, is_leap);
  121. t += 86400LL * (tm->tm_mday-1);
  122. t += 3600LL * tm->tm_hour;
  123. t += 60LL * tm->tm_min;
  124. t += tm->tm_sec;
  125. return t;
  126. }