Coverage Report

Created: 2026-01-18 06:47

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
48.9k
{
63
48.9k
  timelib_time *t;
64
48.9k
  t = timelib_calloc(1, sizeof(timelib_time));
65
66
48.9k
  return t;
67
48.9k
}
68
69
void timelib_time_dtor(timelib_time* t)
70
48.9k
{
71
48.9k
  TIMELIB_TIME_FREE(t->tz_abbr);
72
48.9k
  TIMELIB_TIME_FREE(t);
73
48.9k
}
74
75
int timelib_time_compare(timelib_time *t1, timelib_time *t2)
76
0
{
77
0
  if (t1->sse == t2->sse) {
78
0
    if (t1->us == t2->us) {
79
0
      return 0;
80
0
    }
81
82
0
    return (t1->us < t2->us) ? -1 : 1;
83
0
  }
84
85
0
  return (t1->sse < t2->sse) ? -1 : 1;
86
0
}
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
166k
{
103
166k
  timelib_rel_time *t;
104
166k
  t = timelib_calloc(1, sizeof(timelib_rel_time));
105
106
166k
  return t;
107
166k
}
108
109
void timelib_rel_time_dtor(timelib_rel_time* t)
110
222k
{
111
222k
  TIMELIB_TIME_FREE(t);
112
222k
}
113
114
timelib_rel_time* timelib_rel_time_clone(timelib_rel_time *rel)
115
19
{
116
19
  timelib_rel_time *tmp = timelib_rel_time_ctor();
117
19
  memcpy(tmp, rel, sizeof(timelib_rel_time));
118
19
  return tmp;
119
19
}
120
121
void timelib_time_tz_abbr_update(timelib_time* tm, const char* tz_abbr)
122
22.9k
{
123
22.9k
  unsigned int i;
124
22.9k
  size_t tz_abbr_len = strlen(tz_abbr);
125
126
22.9k
  TIMELIB_TIME_FREE(tm->tz_abbr);
127
22.9k
  tm->tz_abbr = timelib_strdup(tz_abbr);
128
53.1k
  for (i = 0; i < tz_abbr_len; i++) {
129
30.2k
    tm->tz_abbr[i] = toupper(tz_abbr[i]);
130
30.2k
  }
131
22.9k
}
132
133
timelib_time_offset* timelib_time_offset_ctor(void)
134
0
{
135
0
  timelib_time_offset *t;
136
0
  t = timelib_calloc(1, sizeof(timelib_time_offset));
137
138
0
  return t;
139
0
}
140
141
void timelib_time_offset_dtor(timelib_time_offset* t)
142
0
{
143
0
  TIMELIB_TIME_FREE(t->abbr);
144
0
  TIMELIB_TIME_FREE(t);
145
0
}
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
48.9k
{
157
48.9k
  int i;
158
159
114k
  for (i = 0; i < errors->warning_count; i++) {
160
65.6k
    timelib_free(errors->warning_messages[i].message);
161
65.6k
  }
162
48.9k
  timelib_free(errors->warning_messages);
163
118M
  for (i = 0; i < errors->error_count; i++) {
164
118M
    timelib_free(errors->error_messages[i].message);
165
118M
  }
166
48.9k
  timelib_free(errors->error_messages);
167
48.9k
  timelib_free(errors);
168
48.9k
}
169
170
timelib_long timelib_date_to_int(timelib_time *d, int *error)
171
0
{
172
0
  timelib_sll ts;
173
174
0
  ts = d->sse;
175
176
0
  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
0
  if (error) {
183
0
    *error = 0;
184
0
  }
185
0
  return (timelib_long) d->sse;
186
0
}
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
0
{
220
0
  if (hour >= 0) {
221
0
    *h = ((double)hour + (double)min / MINS_PER_HOUR + (double)sec / SECS_PER_HOUR) + (double)us / USECS_PER_HOUR;
222
0
  } else {
223
0
    *h = ((double)hour - (double)min / MINS_PER_HOUR - (double)sec / SECS_PER_HOUR) - (double)us / USECS_PER_HOUR;
224
0
  }
225
0
}
226
227
timelib_sll timelib_hms_to_seconds(timelib_sll h, timelib_sll m, timelib_sll s)
228
0
{
229
0
  return (h * SECS_PER_HOUR) + (m * 60) + s;
230
0
}
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
199M
#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
91.9M
#define MIN(a, b)  (((a)<(b))?(a):(b))
256
257
int timelib_strcasecmp(const char *s1, const char *s2)
258
91.7M
{
259
91.7M
  size_t len;
260
91.7M
  size_t len1 = strlen(s1);
261
91.7M
  size_t len2 = strlen(s2);
262
91.7M
  int c1, c2;
263
264
91.7M
  if (s1 == s2) {
265
0
    return 0;
266
0
  }
267
268
91.7M
  len = MIN(len1, len2);
269
103M
  while (len--) {
270
99.7M
    c1 = timelib_tolower(*(unsigned char *)s1++);
271
99.7M
    c2 = timelib_tolower(*(unsigned char *)s2++);
272
99.7M
    if (c1 != c2) {
273
87.7M
      return c1 - c2;
274
87.7M
    }
275
99.7M
  }
276
277
4.09M
  return (int)(len1 - len2);
278
91.7M
}
279
280
int timelib_strncasecmp(const char *s1, const char *s2, size_t length)
281
186k
{
282
186k
  size_t len;
283
186k
  size_t len1 = strlen(s1);
284
186k
  size_t len2 = strlen(s2);
285
186k
  int c1, c2;
286
287
186k
  if (s1 == s2) {
288
0
    return 0;
289
0
  }
290
186k
  len = MIN(length, MIN(len1, len2));
291
193k
  while (len--) {
292
191k
    c1 = timelib_tolower(*(unsigned char *)s1++);
293
191k
    c2 = timelib_tolower(*(unsigned char *)s2++);
294
191k
    if (c1 != c2) {
295
184k
      return c1 - c2;
296
184k
    }
297
191k
  }
298
299
2.27k
  return (int)(MIN(length, len1) - MIN(length, len2));
300
186k
}
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
}