Coverage Report

Created: 2026-04-01 06:49

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