Coverage Report

Created: 2026-10-28 06:20

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
114k
{
71
114k
  timelib_time *t;
72
114k
  t = timelib_calloc(1, sizeof(timelib_time));
73
74
114k
  return t;
75
114k
}
76
77
void timelib_time_dtor(timelib_time* t)
78
114k
{
79
114k
  TIMELIB_TIME_FREE(t->tz_abbr);
80
114k
  TIMELIB_TIME_FREE(t);
81
114k
}
82
83
int timelib_time_compare(timelib_time *t1, timelib_time *t2)
84
0
{
85
0
  if (t1->sse == t2->sse) {
86
0
    if (t1->us == t2->us) {
87
0
      return 0;
88
0
    }
89
90
0
    return (t1->us < t2->us) ? -1 : 1;
91
0
  }
92
93
0
  return (t1->sse < t2->sse) ? -1 : 1;
94
0
}
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
241k
{
111
241k
  timelib_rel_time *t;
112
241k
  t = timelib_calloc(1, sizeof(timelib_rel_time));
113
114
241k
  return t;
115
241k
}
116
117
void timelib_rel_time_dtor(timelib_rel_time* t)
118
403k
{
119
403k
  TIMELIB_TIME_FREE(t);
120
403k
}
121
122
timelib_rel_time* timelib_rel_time_clone(timelib_rel_time *rel)
123
192
{
124
192
  timelib_rel_time *tmp = timelib_rel_time_ctor();
125
192
  memcpy(tmp, rel, sizeof(timelib_rel_time));
126
192
  return tmp;
127
192
}
128
129
void timelib_time_tz_abbr_update(timelib_time* tm, const char* tz_abbr)
130
66.8k
{
131
66.8k
  unsigned int i;
132
66.8k
  size_t tz_abbr_len = strlen(tz_abbr);
133
134
66.8k
  TIMELIB_TIME_FREE(tm->tz_abbr);
135
66.8k
  tm->tz_abbr = timelib_strdup(tz_abbr);
136
153k
  for (i = 0; i < tz_abbr_len; i++) {
137
86.5k
    tm->tz_abbr[i] = toupper((unsigned char)tz_abbr[i]);
138
86.5k
  }
139
66.8k
}
140
141
timelib_time_offset* timelib_time_offset_ctor(void)
142
583
{
143
583
  timelib_time_offset *t;
144
583
  t = timelib_calloc(1, sizeof(timelib_time_offset));
145
146
583
  return t;
147
583
}
148
149
void timelib_time_offset_dtor(timelib_time_offset* t)
150
583
{
151
583
  TIMELIB_TIME_FREE(t->abbr);
152
583
  TIMELIB_TIME_FREE(t);
153
583
}
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
114k
{
165
114k
  int i;
166
167
260k
  for (i = 0; i < errors->warning_count; i++) {
168
146k
    timelib_free(errors->warning_messages[i].message);
169
146k
  }
170
114k
  timelib_free(errors->warning_messages);
171
38.0M
  for (i = 0; i < errors->error_count; i++) {
172
37.9M
    timelib_free(errors->error_messages[i].message);
173
37.9M
  }
174
114k
  timelib_free(errors->error_messages);
175
114k
  timelib_free(errors);
176
114k
}
177
178
timelib_long timelib_date_to_int(timelib_time *d, int *error)
179
0
{
180
0
  timelib_sll ts;
181
182
0
  ts = d->sse;
183
184
0
  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
0
  if (error) {
191
0
    *error = 0;
192
0
  }
193
0
  return (timelib_long) d->sse;
194
0
}
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
0
{
228
0
  if (hour >= 0) {
229
0
    *h = ((double)hour + (double)min / MINS_PER_HOUR + (double)sec / SECS_PER_HOUR) + (double)us / USECS_PER_HOUR;
230
0
  } else {
231
0
    *h = ((double)hour - (double)min / MINS_PER_HOUR - (double)sec / SECS_PER_HOUR) - (double)us / USECS_PER_HOUR;
232
0
  }
233
0
}
234
235
timelib_sll timelib_hms_to_seconds(timelib_sll h, timelib_sll m, timelib_sll s)
236
180
{
237
180
  return (h * SECS_PER_HOUR) + (m * 60) + s;
238
180
}
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
564M
#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
298M
#define MIN(a, b)  (((a)<(b))?(a):(b))
264
265
int timelib_strcasecmp(const char *s1, const char *s2)
266
297M
{
267
297M
  size_t len;
268
297M
  size_t len1 = strlen(s1);
269
297M
  size_t len2 = strlen(s2);
270
297M
  int c1, c2;
271
272
297M
  if (s1 == s2) {
273
0
    return 0;
274
0
  }
275
276
297M
  len = MIN(len1, len2);
277
335M
  while (len--) {
278
281M
    c1 = timelib_tolower(*(unsigned char *)s1++);
279
281M
    c2 = timelib_tolower(*(unsigned char *)s2++);
280
281M
    if (c1 != c2) {
281
243M
      return c1 - c2;
282
243M
    }
283
281M
  }
284
285
53.8M
  return (int)(len1 - len2);
286
297M
}
287
288
int timelib_strncasecmp(const char *s1, const char *s2, size_t length)
289
482k
{
290
482k
  size_t len;
291
482k
  size_t len1 = strlen(s1);
292
482k
  size_t len2 = strlen(s2);
293
482k
  int c1, c2;
294
295
482k
  if (s1 == s2) {
296
0
    return 0;
297
0
  }
298
482k
  len = MIN(length, MIN(len1, len2));
299
513k
  while (len--) {
300
501k
    c1 = timelib_tolower(*(unsigned char *)s1++);
301
501k
    c2 = timelib_tolower(*(unsigned char *)s2++);
302
501k
    if (c1 != c2) {
303
469k
      return c1 - c2;
304
469k
    }
305
501k
  }
306
307
12.3k
  return (int)(MIN(length, len1) - MIN(length, len2));
308
482k
}
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
}