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