Coverage Report

Created: 2025-06-13 06:43

/src/php-src/ext/date/lib/dow.c
Line
Count
Source (jump to first uncovered line)
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
25
#include "timelib.h"
26
#include "timelib_private.h"
27
28
static int m_table_common[13] = { -1, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }; /* 1 = jan */
29
static int m_table_leap[13] =   { -1, 6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }; /* 1 = jan */
30
31
static timelib_sll positive_mod(timelib_sll x, timelib_sll y)
32
83.1k
{
33
83.1k
  timelib_sll tmp;
34
35
83.1k
  tmp = x % y;
36
83.1k
  if (tmp < 0) {
37
0
    tmp += y;
38
0
  }
39
40
83.1k
  return tmp;
41
83.1k
}
42
43
static timelib_sll century_value(timelib_sll j)
44
20.7k
{
45
20.7k
  return 6 - positive_mod(j, 4) * 2;
46
20.7k
}
47
48
static timelib_sll timelib_day_of_week_ex(timelib_sll y, timelib_sll m, timelib_sll d, int iso)
49
20.7k
{
50
20.7k
  timelib_sll c1, y1, m1, dow;
51
52
  /* Only valid for Gregorian calendar, commented out as we don't handle
53
   * Julian calendar. We just return the 'wrong' day of week to be
54
   * consistent. */
55
20.7k
  c1 = century_value(positive_mod(y, 400) / 100);
56
20.7k
  y1 = positive_mod(y, 100);
57
20.7k
  m1 = timelib_is_leap(y) ? m_table_leap[m] : m_table_common[m];
58
20.7k
  dow = positive_mod((c1 + y1 + m1 + (y1 / 4) + d), 7);
59
20.7k
  if (iso) {
60
782
    if (dow == 0) {
61
0
      dow = 7;
62
0
    }
63
782
  }
64
20.7k
  return dow;
65
20.7k
}
66
67
timelib_sll timelib_day_of_week(timelib_sll y, timelib_sll m, timelib_sll d)
68
19.9k
{
69
19.9k
  return timelib_day_of_week_ex(y, m, d, 0);
70
19.9k
}
71
72
timelib_sll timelib_iso_day_of_week(timelib_sll y, timelib_sll m, timelib_sll d)
73
782
{
74
782
  return timelib_day_of_week_ex(y, m, d, 1);
75
782
}
76
77
                                /*     jan  feb  mar  apr  may  jun  jul  aug  sep  oct  nov  dec */
78
static int d_table_common[13]  = {  0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334 };
79
static int d_table_leap[13]    = {  0,   0,  31,  60,  91, 121, 152, 182, 213, 244, 274, 305, 335 };
80
static int ml_table_common[13] = {  0,  31,  28,  31,  30,  31,  30,  31,  31,  30,  31,  30,  31 };
81
static int ml_table_leap[13]   = {  0,  31,  29,  31,  30,  31,  30,  31,  31,  30,  31,  30,  31 };
82
83
timelib_sll timelib_day_of_year(timelib_sll y, timelib_sll m, timelib_sll d)
84
779
{
85
779
  return (timelib_is_leap(y) ? d_table_leap[m] : d_table_common[m]) + d - 1;
86
779
}
87
88
timelib_sll timelib_days_in_month(timelib_sll y, timelib_sll m)
89
323k
{
90
323k
  return timelib_is_leap(y) ? ml_table_leap[m] : ml_table_common[m];
91
323k
}
92
93
void timelib_isoweek_from_date(timelib_sll y, timelib_sll m, timelib_sll d, timelib_sll *iw, timelib_sll *iy)
94
232
{
95
232
  int y_leap, prev_y_leap, doy, jan1weekday, weekday;
96
97
232
  y_leap = timelib_is_leap(y);
98
232
  prev_y_leap = timelib_is_leap(y-1);
99
232
  doy = timelib_day_of_year(y, m, d) + 1;
100
232
  if (y_leap && m > 2) {
101
9
    doy++;
102
9
  }
103
232
  jan1weekday = timelib_day_of_week(y, 1, 1);
104
232
  weekday = timelib_day_of_week(y, m, d);
105
232
  if (weekday == 0) weekday = 7;
106
232
  if (jan1weekday == 0) jan1weekday = 7;
107
  /* Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53 */
108
232
  if (doy <= (8 - jan1weekday) && jan1weekday > 4) {
109
0
    *iy = y - 1;
110
0
    if (jan1weekday == 5 || (jan1weekday == 6 && prev_y_leap)) {
111
0
      *iw = 53;
112
0
    } else {
113
0
      *iw = 52;
114
0
    }
115
232
  } else {
116
232
    *iy = y;
117
232
  }
118
  /* 8. Find if Y M D falls in YearNumber Y+1, WeekNumber 1 */
119
232
  if (*iy == y) {
120
232
    int i;
121
122
232
    i = y_leap ? 366 : 365;
123
232
    if ((i - (doy - y_leap)) < (4 - weekday)) {
124
0
      *iy = y + 1;
125
0
      *iw = 1;
126
0
      return;
127
0
    }
128
232
  }
129
  /* 9. Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53 */
130
232
  if (*iy == y) {
131
232
    int j;
132
133
232
    j = doy + (7 - weekday) + (jan1weekday - 1);
134
232
    *iw = j / 7;
135
232
    if (jan1weekday > 4) {
136
4
      *iw -= 1;
137
4
    }
138
232
  }
139
232
}
140
141
void timelib_isodate_from_date(timelib_sll y, timelib_sll m, timelib_sll d, timelib_sll *iy, timelib_sll *iw, timelib_sll *id)
142
0
{
143
0
  timelib_isoweek_from_date(y, m, d, iw, iy);
144
0
  *id = timelib_day_of_week_ex(y, m, d, 1);
145
0
}
146
147
timelib_sll timelib_daynr_from_weeknr(timelib_sll iy, timelib_sll iw, timelib_sll id)
148
11.5k
{
149
11.5k
  timelib_sll dow, day;
150
151
  /* Figure out the dayofweek for y-1-1 */
152
11.5k
  dow = timelib_day_of_week(iy, 1, 1);
153
  /* then use that to figure out the offset for day 1 of week 1 */
154
11.5k
  day = 0 - (dow > 4 ? dow - 7 : dow);
155
156
  /* Add weeks and days */
157
11.5k
  return day + ((iw - 1) * 7) + id;
158
11.5k
}
159
160
void timelib_date_from_isodate(timelib_sll iy, timelib_sll iw, timelib_sll id, timelib_sll *y, timelib_sll *m, timelib_sll *d)
161
0
{
162
0
  timelib_sll daynr = timelib_daynr_from_weeknr(iy, iw, id) + 1;
163
0
  int *table;
164
0
  bool is_leap_year;
165
166
  // Invariant: is_leap_year == timelib_is_leap(*y)
167
0
  *y = iy;
168
0
  is_leap_year = timelib_is_leap(*y);
169
170
  // Establish invariant that daynr >= 0
171
0
  while (daynr <= 0) {
172
0
    *y -= 1;
173
0
    daynr += (is_leap_year = timelib_is_leap(*y)) ? 366 : 365;
174
0
  }
175
176
  // Establish invariant that daynr <= number of days in *yr
177
0
  while (daynr > (is_leap_year ? 366 : 365)) {
178
0
    daynr -= is_leap_year ? 366 : 365;
179
0
    *y += 1;
180
0
    is_leap_year = timelib_is_leap(*y);
181
0
  }
182
183
0
  table = is_leap_year ? ml_table_leap : ml_table_common;
184
185
  // Establish invariant that daynr <= number of days in *m
186
0
  *m = 1;
187
0
  while (daynr > table[*m]) {
188
0
    daynr -= table[*m];
189
0
    *m += 1;
190
0
  }
191
192
0
  *d = daynr;
193
0
}
194
195
int timelib_valid_time(timelib_sll h, timelib_sll i, timelib_sll s)
196
526k
{
197
526k
  if (h < 0 || h > 23 || i < 0 || i > 59 || s < 0 || s > 59) {
198
9.54k
    return 0;
199
9.54k
  }
200
516k
  return 1;
201
526k
}
202
203
int timelib_valid_date(timelib_sll y, timelib_sll m, timelib_sll d)
204
542k
{
205
542k
  if (m < 1 || m > 12 || d < 1 || d > timelib_days_in_month(y, m)) {
206
301k
    return 0;
207
301k
  }
208
240k
  return 1;
209
542k
}
210
#if 0
211
int main(void)
212
{
213
  printf("dow = %d\n", timelib_day_of_week(1978, 12, 22)); /* 5 */
214
  printf("dow = %d\n", timelib_day_of_week(2005,  2, 19)); /* 6 */
215
}
216
#endif