Coverage Report

Created: 2026-01-18 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
99.8k
{
63
99.8k
  timelib_time *t;
64
99.8k
  t = timelib_calloc(1, sizeof(timelib_time));
65
66
99.8k
  return t;
67
99.8k
}
68
69
void timelib_time_dtor(timelib_time* t)
70
99.8k
{
71
99.8k
  TIMELIB_TIME_FREE(t->tz_abbr);
72
99.8k
  TIMELIB_TIME_FREE(t);
73
99.8k
}
74
75
int timelib_time_compare(timelib_time *t1, timelib_time *t2)
76
1
{
77
1
  if (t1->sse == t2->sse) {
78
1
    if (t1->us == t2->us) {
79
0
      return 0;
80
0
    }
81
82
1
    return (t1->us < t2->us) ? -1 : 1;
83
1
  }
84
85
0
  return (t1->sse < t2->sse) ? -1 : 1;
86
1
}
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
0
{
103
0
  timelib_rel_time *t;
104
0
  t = timelib_calloc(1, sizeof(timelib_rel_time));
105
106
0
  return t;
107
0
}
108
109
void timelib_rel_time_dtor(timelib_rel_time* t)
110
1
{
111
1
  TIMELIB_TIME_FREE(t);
112
1
}
113
114
timelib_rel_time* timelib_rel_time_clone(timelib_rel_time *rel)
115
0
{
116
0
  timelib_rel_time *tmp = timelib_rel_time_ctor();
117
0
  memcpy(tmp, rel, sizeof(timelib_rel_time));
118
0
  return tmp;
119
0
}
120
121
void timelib_time_tz_abbr_update(timelib_time* tm, const char* tz_abbr)
122
62.6k
{
123
62.6k
  unsigned int i;
124
62.6k
  size_t tz_abbr_len = strlen(tz_abbr);
125
126
62.6k
  TIMELIB_TIME_FREE(tm->tz_abbr);
127
62.6k
  tm->tz_abbr = timelib_strdup(tz_abbr);
128
129k
  for (i = 0; i < tz_abbr_len; i++) {
129
66.9k
    tm->tz_abbr[i] = toupper(tz_abbr[i]);
130
66.9k
  }
131
62.6k
}
132
133
timelib_time_offset* timelib_time_offset_ctor(void)
134
2.26k
{
135
2.26k
  timelib_time_offset *t;
136
2.26k
  t = timelib_calloc(1, sizeof(timelib_time_offset));
137
138
2.26k
  return t;
139
2.26k
}
140
141
void timelib_time_offset_dtor(timelib_time_offset* t)
142
2.26k
{
143
2.26k
  TIMELIB_TIME_FREE(t->abbr);
144
2.26k
  TIMELIB_TIME_FREE(t);
145
2.26k
}
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
97.6k
{
157
97.6k
  int i;
158
159
233k
  for (i = 0; i < errors->warning_count; i++) {
160
136k
    timelib_free(errors->warning_messages[i].message);
161
136k
  }
162
97.6k
  timelib_free(errors->warning_messages);
163
215M
  for (i = 0; i < errors->error_count; i++) {
164
215M
    timelib_free(errors->error_messages[i].message);
165
215M
  }
166
97.6k
  timelib_free(errors->error_messages);
167
97.6k
  timelib_free(errors);
168
97.6k
}
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
94
{
229
94
  return (h * SECS_PER_HOUR) + (m * 60) + s;
230
94
}
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
226M
#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
112M
#define MIN(a, b)  (((a)<(b))?(a):(b))
256
257
int timelib_strcasecmp(const char *s1, const char *s2)
258
112M
{
259
112M
  size_t len;
260
112M
  size_t len1 = strlen(s1);
261
112M
  size_t len2 = strlen(s2);
262
112M
  int c1, c2;
263
264
112M
  if (s1 == s2) {
265
0
    return 0;
266
0
  }
267
268
112M
  len = MIN(len1, len2);
269
118M
  while (len--) {
270
113M
    c1 = timelib_tolower(*(unsigned char *)s1++);
271
113M
    c2 = timelib_tolower(*(unsigned char *)s2++);
272
113M
    if (c1 != c2) {
273
107M
      return c1 - c2;
274
107M
    }
275
113M
  }
276
277
5.13M
  return (int)(len1 - len2);
278
112M
}
279
280
int timelib_strncasecmp(const char *s1, const char *s2, size_t length)
281
140k
{
282
140k
  size_t len;
283
140k
  size_t len1 = strlen(s1);
284
140k
  size_t len2 = strlen(s2);
285
140k
  int c1, c2;
286
287
140k
  if (s1 == s2) {
288
0
    return 0;
289
0
  }
290
140k
  len = MIN(length, MIN(len1, len2));
291
140k
  while (len--) {
292
140k
    c1 = timelib_tolower(*(unsigned char *)s1++);
293
140k
    c2 = timelib_tolower(*(unsigned char *)s2++);
294
140k
    if (c1 != c2) {
295
140k
      return c1 - c2;
296
140k
    }
297
140k
  }
298
299
13
  return (int)(MIN(length, len1) - MIN(length, len2));
300
140k
}
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
}