dow.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2015-2019 Derick Rethans
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "timelib.h"
  25. #include "timelib_private.h"
  26. static int m_table_common[13] = { -1, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }; /* 1 = jan */
  27. static int m_table_leap[13] = { -1, 6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }; /* 1 = jan */
  28. static timelib_sll positive_mod(timelib_sll x, timelib_sll y)
  29. {
  30. timelib_sll tmp;
  31. tmp = x % y;
  32. if (tmp < 0) {
  33. tmp += y;
  34. }
  35. return tmp;
  36. }
  37. static timelib_sll century_value(timelib_sll j)
  38. {
  39. return 6 - positive_mod(j, 4) * 2;
  40. }
  41. static timelib_sll timelib_day_of_week_ex(timelib_sll y, timelib_sll m, timelib_sll d, int iso)
  42. {
  43. timelib_sll c1, y1, m1, dow;
  44. /* Only valid for Gregorian calendar, commented out as we don't handle
  45. * Julian calendar. We just return the 'wrong' day of week to be
  46. * consistent. */
  47. c1 = century_value(y / 100);
  48. y1 = positive_mod(y, 100);
  49. m1 = timelib_is_leap(y) ? m_table_leap[m] : m_table_common[m];
  50. dow = positive_mod((c1 + y1 + m1 + (y1 / 4) + d), 7);
  51. if (iso) {
  52. if (dow == 0) {
  53. dow = 7;
  54. }
  55. }
  56. return dow;
  57. }
  58. timelib_sll timelib_day_of_week(timelib_sll y, timelib_sll m, timelib_sll d)
  59. {
  60. return timelib_day_of_week_ex(y, m, d, 0);
  61. }
  62. timelib_sll timelib_iso_day_of_week(timelib_sll y, timelib_sll m, timelib_sll d)
  63. {
  64. return timelib_day_of_week_ex(y, m, d, 1);
  65. }
  66. /* jan feb mar apr may jun jul aug sep oct nov dec */
  67. static int d_table_common[13] = { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
  68. static int d_table_leap[13] = { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
  69. static int ml_table_common[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  70. static int ml_table_leap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  71. timelib_sll timelib_day_of_year(timelib_sll y, timelib_sll m, timelib_sll d)
  72. {
  73. return (timelib_is_leap(y) ? d_table_leap[m] : d_table_common[m]) + d - 1;
  74. }
  75. timelib_sll timelib_days_in_month(timelib_sll y, timelib_sll m)
  76. {
  77. return timelib_is_leap(y) ? ml_table_leap[m] : ml_table_common[m];
  78. }
  79. void timelib_isoweek_from_date(timelib_sll y, timelib_sll m, timelib_sll d, timelib_sll *iw, timelib_sll *iy)
  80. {
  81. int y_leap, prev_y_leap, doy, jan1weekday, weekday;
  82. y_leap = timelib_is_leap(y);
  83. prev_y_leap = timelib_is_leap(y-1);
  84. doy = timelib_day_of_year(y, m, d) + 1;
  85. if (y_leap && m > 2) {
  86. doy++;
  87. }
  88. jan1weekday = timelib_day_of_week(y, 1, 1);
  89. weekday = timelib_day_of_week(y, m, d);
  90. if (weekday == 0) weekday = 7;
  91. if (jan1weekday == 0) jan1weekday = 7;
  92. /* Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53 */
  93. if (doy <= (8 - jan1weekday) && jan1weekday > 4) {
  94. *iy = y - 1;
  95. if (jan1weekday == 5 || (jan1weekday == 6 && prev_y_leap)) {
  96. *iw = 53;
  97. } else {
  98. *iw = 52;
  99. }
  100. } else {
  101. *iy = y;
  102. }
  103. /* 8. Find if Y M D falls in YearNumber Y+1, WeekNumber 1 */
  104. if (*iy == y) {
  105. int i;
  106. i = y_leap ? 366 : 365;
  107. if ((i - (doy - y_leap)) < (4 - weekday)) {
  108. *iy = y + 1;
  109. *iw = 1;
  110. return;
  111. }
  112. }
  113. /* 9. Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53 */
  114. if (*iy == y) {
  115. int j;
  116. j = doy + (7 - weekday) + (jan1weekday - 1);
  117. *iw = j / 7;
  118. if (jan1weekday > 4) {
  119. *iw -= 1;
  120. }
  121. }
  122. }
  123. void timelib_isodate_from_date(timelib_sll y, timelib_sll m, timelib_sll d, timelib_sll *iy, timelib_sll *iw, timelib_sll *id)
  124. {
  125. timelib_isoweek_from_date(y, m, d, iw, iy);
  126. *id = timelib_day_of_week_ex(y, m, d, 1);
  127. }
  128. static timelib_sll timelib_daynr_from_weeknr_ex(timelib_sll iy, timelib_sll iw, timelib_sll id, timelib_sll *y)
  129. {
  130. timelib_sll dow, day;
  131. /* Figure out the dayofweek for y-1-1 */
  132. dow = timelib_day_of_week(iy, 1, 1);
  133. /* then use that to figure out the offset for day 1 of week 1 */
  134. day = 0 - (dow > 4 ? dow - 7 : dow);
  135. /* and adjust the year to the natural year if we need to */
  136. *y = (iw == 1 && day < 0 && id < dow) ? iy - 1 : iy;
  137. /* Add weeks and days */
  138. return day + ((iw - 1) * 7) + id;
  139. }
  140. timelib_sll timelib_daynr_from_weeknr(timelib_sll iy, timelib_sll iw, timelib_sll id)
  141. {
  142. timelib_sll dummy_iso_year;
  143. return timelib_daynr_from_weeknr_ex(iy, iw, id, &dummy_iso_year);
  144. }
  145. void timelib_date_from_isodate(timelib_sll iy, timelib_sll iw, timelib_sll id, timelib_sll *y, timelib_sll *m, timelib_sll *d)
  146. {
  147. timelib_sll daynr = timelib_daynr_from_weeknr_ex(iy, iw, id, y) + 1;
  148. int *table;
  149. *m = 0;
  150. if (daynr <= 0) {
  151. *y += 1;
  152. }
  153. if (timelib_is_leap(*y)) {
  154. table = ml_table_leap;
  155. if (daynr > 366) {
  156. *y += 1;
  157. daynr -= 366;
  158. }
  159. } else {
  160. table = ml_table_common;
  161. if (daynr > 365) {
  162. *y += 1;
  163. daynr -= 365;
  164. }
  165. }
  166. do {
  167. daynr -= table[*m];
  168. (*m)++;
  169. } while (daynr > table[*m]);
  170. if (daynr <= 0) {
  171. daynr += 31;
  172. *y -= 1;
  173. *m = 12;
  174. }
  175. *d = daynr;
  176. }
  177. int timelib_valid_time(timelib_sll h, timelib_sll i, timelib_sll s)
  178. {
  179. if (h < 0 || h > 23 || i < 0 || i > 59 || s < 0 || s > 59) {
  180. return 0;
  181. }
  182. return 1;
  183. }
  184. int timelib_valid_date(timelib_sll y, timelib_sll m, timelib_sll d)
  185. {
  186. if (m < 1 || m > 12 || d < 1 || d > timelib_days_in_month(y, m)) {
  187. return 0;
  188. }
  189. return 1;
  190. }
  191. #if 0
  192. int main(void)
  193. {
  194. printf("dow = %d\n", timelib_day_of_week(1978, 12, 22)); /* 5 */
  195. printf("dow = %d\n", timelib_day_of_week(2005, 2, 19)); /* 6 */
  196. }
  197. #endif