Coverage Report

Created: 2026-09-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/date/lib/timelib.c
Line
Count
Source
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
 * Portions copyright (c) 1998-2017 Zend Technologies Ltd.
25
 *
26
 * The timelib_strcasecmp and timelib_strncasecmp are taken from PHP's
27
 * Zend/zend_operators.[hc] source files.
28
 *
29
 */
30
31
#include "timelib.h"
32
#include "timelib_private.h"
33
#include <ctype.h>
34
#include <math.h>
35
36
0
#define TIMELIB_LLABS(y) (y < 0 ? (y * -1) : y)
37
38
const char *timelib_error_messages[18] = {
39
  "No error",
40
  "Cannot allocate buffer for parsing",
41
  "Corrupt tzfile: The transitions in the file don't always increase",
42
  "Corrupt tzfile: The expected 64-bit preamble is missing",
43
  "Corrupt tzfile: No abbreviation could be found for a transition",
44
  "The version used in this timezone identifier is unsupported",
45
  "No timezone with this name could be found",
46
  "A 'slim' timezone file has been detected",
47
  "The embedded POSIX string is not valid",
48
  "The embedded POSIX string is empty",
49
  "Seconds value out of range",
50
  "Nanoseconds value out of range",
51
  "Division by zero",
52
  "Integer Overflow",
53
  "The ISO 8601 duration string may only contain the period (P) aspect",
54
  "The ISO 8601 duration string is missing the period (P) aspect",
55
  "The ISO 8601 duration string may only contain the time (T) aspect",
56
  "The ISO 8601 duration string could not be parsed",
57
};
58
59
const char *timelib_get_error_message(int error_code)
60
0
{
61
0
  int entries = sizeof(timelib_error_messages) / sizeof(char*);
62
63
0
  if (error_code >= 0 && error_code < entries) {
64
0
    return timelib_error_messages[error_code];
65
0
  }
66
0
  return "Unknown error code";
67
0
}
68
69
timelib_time* timelib_time_ctor(void)
70
375k
{
71
375k
  timelib_time *t;
72
375k
  t = timelib_calloc(1, sizeof(timelib_time));
73
74
375k
  return t;
75
375k
}
76
77
void timelib_time_dtor(timelib_time* t)
78
375k
{
79
375k
  TIMELIB_TIME_FREE(t->tz_abbr);
80
375k
  TIMELIB_TIME_FREE(t);
81
375k
}
82
83
int timelib_time_compare(timelib_time *t1, timelib_time *t2)
84
10
{
85
10
  if (t1->sse == t2->sse) {
86
10
    if (t1->us == t2->us) {
87
0
      return 0;
88
0
    }
89
90
10
    return (t1->us < t2->us) ? -1 : 1;
91
10
  }
92
93
0
  return (t1->sse < t2->sse) ? -1 : 1;
94
10
}
95
96
timelib_time* timelib_time_clone(timelib_time *orig)
97
0
{
98
0
  timelib_time *tmp = timelib_time_ctor();
99
0
  memcpy(tmp, orig, sizeof(timelib_time));
100
0
  if (orig->tz_abbr) {
101
0
    tmp->tz_abbr = timelib_strdup(orig->tz_abbr);
102
0
  }
103
0
  if (orig->tz_info) {
104
0
    tmp->tz_info = orig->tz_info;
105
0
  }
106
0
  return tmp;
107
0
}
108
109
timelib_rel_time* timelib_rel_time_ctor(void)
110
238k
{
111
238k
  timelib_rel_time *t;
112
238k
  t = timelib_calloc(1, sizeof(timelib_rel_time));
113
114
238k
  return t;
115
238k
}
116
117
void timelib_rel_time_dtor(timelib_rel_time* t)
118
351k
{
119
351k
  TIMELIB_TIME_FREE(t);
120
351k
}
121
122
timelib_rel_time* timelib_rel_time_clone(timelib_rel_time *rel)
123
106
{
124
106
  timelib_rel_time *tmp = timelib_rel_time_ctor();
125
106
  memcpy(tmp, rel, sizeof(timelib_rel_time));
126
106
  return tmp;
127
106
}
128
129
void timelib_time_tz_abbr_update(timelib_time* tm, const char* tz_abbr)
130
273k
{
131
273k
  unsigned int i;
132
273k
  size_t tz_abbr_len = strlen(tz_abbr);
133
134
273k
  TIMELIB_TIME_FREE(tm->tz_abbr);
135
273k
  tm->tz_abbr = timelib_strdup(tz_abbr);
136
700k
  for (i = 0; i < tz_abbr_len; i++) {
137
426k
    tm->tz_abbr[i] = toupper((unsigned char)tz_abbr[i]);
138
426k
  }
139
273k
}
140
141
timelib_time_offset* timelib_time_offset_ctor(void)
142
4.67k
{
143
4.67k
  timelib_time_offset *t;
144
4.67k
  t = timelib_calloc(1, sizeof(timelib_time_offset));
145
146
4.67k
  return t;
147
4.67k
}
148
149
void timelib_time_offset_dtor(timelib_time_offset* t)
150
4.67k
{
151
4.67k
  TIMELIB_TIME_FREE(t->abbr);
152
4.67k
  TIMELIB_TIME_FREE(t);
153
4.67k
}
154
155
char *timelib_get_tz_abbr_ptr(timelib_time *t)
156
0
{
157
0
  if (!t->sse_uptodate) {
158
0
    timelib_update_ts(t, NULL);
159
0
  };
160
0
  return t->tz_abbr;
161
0
}
162
163
void timelib_error_container_dtor(timelib_error_container *errors)
164
371k
{
165
371k
  int i;
166
167
889k
  for (i = 0; i < errors->warning_count; i++) {
168
517k
    timelib_free(errors->warning_messages[i].message);
169
517k
  }
170
371k
  timelib_free(errors->warning_messages);
171
987M
  for (i = 0; i < errors->error_count; i++) {
172
987M
    timelib_free(errors->error_messages[i].message);
173
987M
  }
174
371k
  timelib_free(errors->error_messages);
175
371k
  timelib_free(errors);
176
371k
}
177
178
timelib_long timelib_date_to_int(timelib_time *d, int *error)
179
7
{
180
7
  timelib_sll ts;
181
182
7
  ts = d->sse;
183
184
7
  if (ts < TIMELIB_LONG_MIN || ts > TIMELIB_LONG_MAX) {
185
0
    if (error) {
186
0
      *error = 1;
187
0
    }
188
0
    return 0;
189
0
  }
190
7
  if (error) {
191
7
    *error = 0;
192
7
  }
193
7
  return (timelib_long) d->sse;
194
7
}
195
196
void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec)
197
0
{
198
0
  bool swap = false;
199
0
  int seconds;
200
201
0
  if (h < 0) {
202
0
    swap = true;
203
0
    h = fabs(h);
204
0
  }
205
206
0
  *hour = floor(h);
207
0
  seconds = floor((h - *hour) * 3600);
208
209
0
  *min = seconds / 60;
210
0
  *sec = seconds % 60;
211
212
0
  if (swap) {
213
0
    *hour = 0 - *hour;
214
0
  }
215
0
}
216
217
void timelib_hms_to_decimal_hour(int hour, int min, int sec, double *h)
218
0
{
219
0
  if (hour >= 0) {
220
0
    *h = ((double)hour + (double)min / 60 + (double)sec / 3600);
221
0
  } else {
222
0
    *h = ((double)hour - (double)min / 60 - (double)sec / 3600);
223
0
  }
224
0
}
225
226
void timelib_hmsf_to_decimal_hour(int hour, int min, int sec, int us, double *h)
227
20
{
228
20
  if (hour >= 0) {
229
20
    *h = ((double)hour + (double)min / MINS_PER_HOUR + (double)sec / SECS_PER_HOUR) + (double)us / USECS_PER_HOUR;
230
20
  } else {
231
0
    *h = ((double)hour - (double)min / MINS_PER_HOUR - (double)sec / SECS_PER_HOUR) - (double)us / USECS_PER_HOUR;
232
0
  }
233
20
}
234
235
timelib_sll timelib_hms_to_seconds(timelib_sll h, timelib_sll m, timelib_sll s)
236
361
{
237
361
  return (h * SECS_PER_HOUR) + (m * 60) + s;
238
361
}
239
240
static const unsigned char timelib_tolower_map[256] = {
241
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
242
  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
243
  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
244
  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
245
  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
246
  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
247
  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
248
  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
249
  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
250
  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
251
  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
252
  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
253
  0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
254
  0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
255
  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
256
  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
257
};
258
259
1.17G
#define timelib_tolower(c) (timelib_tolower_map[(unsigned char)(c)])
260
#undef MIN
261
#undef MAX
262
#define MAX(a, b)  (((a)>(b))?(a):(b))
263
597M
#define MIN(a, b)  (((a)<(b))?(a):(b))
264
265
int timelib_strcasecmp(const char *s1, const char *s2)
266
596M
{
267
596M
  size_t len;
268
596M
  size_t len1 = strlen(s1);
269
596M
  size_t len2 = strlen(s2);
270
596M
  int c1, c2;
271
272
596M
  if (s1 == s2) {
273
0
    return 0;
274
0
  }
275
276
596M
  len = MIN(len1, len2);
277
650M
  while (len--) {
278
586M
    c1 = timelib_tolower(*(unsigned char *)s1++);
279
586M
    c2 = timelib_tolower(*(unsigned char *)s2++);
280
586M
    if (c1 != c2) {
281
533M
      return c1 - c2;
282
533M
    }
283
586M
  }
284
285
63.8M
  return (int)(len1 - len2);
286
596M
}
287
288
int timelib_strncasecmp(const char *s1, const char *s2, size_t length)
289
1.00M
{
290
1.00M
  size_t len;
291
1.00M
  size_t len1 = strlen(s1);
292
1.00M
  size_t len2 = strlen(s2);
293
1.00M
  int c1, c2;
294
295
1.00M
  if (s1 == s2) {
296
0
    return 0;
297
0
  }
298
1.00M
  len = MIN(length, MIN(len1, len2));
299
1.03M
  while (len--) {
300
1.02M
    c1 = timelib_tolower(*(unsigned char *)s1++);
301
1.02M
    c2 = timelib_tolower(*(unsigned char *)s2++);
302
1.02M
    if (c1 != c2) {
303
994k
      return c1 - c2;
304
994k
    }
305
1.02M
  }
306
307
10.5k
  return (int)(MIN(length, len1) - MIN(length, len2));
308
1.00M
}
309
310
#undef MIN
311
#undef MAX
312
313
void timelib_dump_date(timelib_time *d, int options)
314
0
{
315
0
  if ((options & 2) == 2) {
316
0
    printf("TYPE: %d ", d->zone_type);
317
0
  }
318
0
  printf("TS: %lld | %s%04lld-%02lld-%02lld %02lld:%02lld:%02lld",
319
0
    d->sse, d->y < 0 ? "-" : "", TIMELIB_LLABS(d->y), d->m, d->d, d->h, d->i, d->s);
320
0
  if (d->us > 0) {
321
0
    printf(" 0.%06lld", d->us);
322
0
  }
323
324
0
  if (d->is_localtime) {
325
0
    switch (d->zone_type) {
326
0
      case TIMELIB_ZONETYPE_OFFSET: /* Only offset */
327
0
        printf(" GMT %05d%s", d->z, d->dst == 1 ? " (DST)" : "");
328
0
        break;
329
0
      case TIMELIB_ZONETYPE_ID: /* Timezone struct */
330
        /* Show abbreviation if wanted */
331
0
        if (d->tz_abbr) {
332
0
          printf(" %s", d->tz_abbr);
333
0
        }
334
        /* Do we have a TimeZone struct? */
335
0
        if (d->tz_info) {
336
0
          printf(" %s", d->tz_info->name);
337
0
        }
338
0
        break;
339
0
      case TIMELIB_ZONETYPE_ABBR:
340
0
        printf(" %s", d->tz_abbr);
341
0
        printf(" %05d%s", d->z, d->dst == 1 ? " (DST)" : "");
342
0
        break;
343
0
    }
344
0
  }
345
346
0
  if ((options & 1) == 1) {
347
0
    if (d->have_relative) {
348
0
      printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS",
349
0
        d->relative.y, d->relative.m, d->relative.d, d->relative.h, d->relative.i, d->relative.s);
350
0
      if (d->relative.us) {
351
0
        printf(" 0.%06lld", d->relative.us);
352
0
      }
353
0
      if (d->relative.first_last_day_of != 0) {
354
0
        switch (d->relative.first_last_day_of) {
355
0
          case 1:
356
0
            printf(" / first day of");
357
0
            break;
358
0
          case 2:
359
0
            printf(" / last day of");
360
0
            break;
361
0
        }
362
0
      }
363
0
      if (d->relative.have_weekday_relative) {
364
0
        printf(" / %d.%d", d->relative.weekday, d->relative.weekday_behavior);
365
0
      }
366
0
      if (d->relative.have_special_relative) {
367
0
        switch (d->relative.special.type) {
368
0
          case TIMELIB_SPECIAL_WEEKDAY:
369
0
            printf(" / %lld weekday", d->relative.special.amount);
370
0
            break;
371
0
          case TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH:
372
0
            printf(" / x y of z month");
373
0
            break;
374
0
          case TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH:
375
0
            printf(" / last y of z month");
376
0
            break;
377
0
        }
378
0
      }
379
0
    }
380
0
  }
381
0
  printf("\n");
382
0
}
383
384
void timelib_dump_rel_time(timelib_rel_time *d)
385
0
{
386
0
  printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS (days: %lld)%s",
387
0
    d->y, d->m, d->d, d->h, d->i, d->s, d->days, d->invert ? " inverted" : "");
388
0
  if (d->first_last_day_of != 0) {
389
0
    switch (d->first_last_day_of) {
390
0
      case 1:
391
0
        printf(" / first day of");
392
0
        break;
393
0
      case 2:
394
0
        printf(" / last day of");
395
0
        break;
396
0
    }
397
0
  }
398
0
  printf("\n");
399
0
}