1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | http://www.php.net/license/3_01.txt                                  |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Gustavo Lopes <cataphract@php.net>                          |
14    +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "../intl_cppshims.h"
22 
23 #include <unicode/locid.h>
24 #include <unicode/timezone.h>
25 #include <unicode/ustring.h>
26 #include <unicode/calendar.h>
27 #include "intl_convertcpp.h"
28 
29 #include "../common/common_date.h"
30 
31 extern "C" {
32 #include "../php_intl.h"
33 #define USE_TIMEZONE_POINTER 1
34 #include "timezone_class.h"
35 #include "intl_convert.h"
36 #include <zend_exceptions.h>
37 #include <ext/date/php_date.h>
38 }
39 #include "common/common_enum.h"
40 
41 using icu::Locale;
42 using icu::Calendar;
43 
PHP_METHOD(IntlTimeZone,__construct)44 U_CFUNC PHP_METHOD(IntlTimeZone, __construct)
45 {
46 	zend_throw_exception( NULL,
47 		"An object of this type cannot be created with the new operator",
48 		0 );
49 }
50 
PHP_FUNCTION(intltz_create_time_zone)51 U_CFUNC PHP_FUNCTION(intltz_create_time_zone)
52 {
53 	char	*str_id;
54 	size_t	 str_id_len;
55 	intl_error_reset(NULL);
56 
57 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str_id, &str_id_len) == FAILURE) {
58 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
59 			"intltz_create_time_zone: bad arguments", 0);
60 		RETURN_NULL();
61 	}
62 
63 	UErrorCode status = UErrorCode();
64 	UnicodeString id = UnicodeString();
65 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
66 		intl_error_set(NULL, status,
67 			"intltz_create_time_zone: could not convert time zone id to UTF-16", 0);
68 		RETURN_NULL();
69 	}
70 
71 	//guaranteed non-null; GMT if timezone cannot be understood
72 	TimeZone *tz = TimeZone::createTimeZone(id);
73 	timezone_object_construct(tz, return_value, 1);
74 }
75 
PHP_FUNCTION(intltz_from_date_time_zone)76 U_CFUNC PHP_FUNCTION(intltz_from_date_time_zone)
77 {
78 	zval				*zv_timezone;
79 	TimeZone			*tz;
80 	php_timezone_obj	*tzobj;
81 	intl_error_reset(NULL);
82 
83 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O",
84 			&zv_timezone, php_date_get_timezone_ce()) == FAILURE) {
85 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
86 			"intltz_from_date_time_zone: bad arguments", 0);
87 		RETURN_NULL();
88 	}
89 
90 	tzobj = Z_PHPTIMEZONE_P(zv_timezone);
91 	if (!tzobj->initialized) {
92 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
93 			"intltz_from_date_time_zone: DateTimeZone object is unconstructed",
94 			0);
95 		RETURN_NULL();
96 	}
97 
98 	tz = timezone_convert_datetimezone(tzobj->type, tzobj, FALSE, NULL,
99 		"intltz_from_date_time_zone");
100 	if (tz == NULL) {
101 		RETURN_NULL();
102 	}
103 
104 	timezone_object_construct(tz, return_value, 1);
105 }
106 
PHP_FUNCTION(intltz_create_default)107 U_CFUNC PHP_FUNCTION(intltz_create_default)
108 {
109 	intl_error_reset(NULL);
110 
111 	if (zend_parse_parameters_none() == FAILURE) {
112 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
113 			"intltz_create_default: bad arguments", 0);
114 		RETURN_NULL();
115 	}
116 
117 	TimeZone *tz = TimeZone::createDefault();
118 	timezone_object_construct(tz, return_value, 1);
119 }
120 
PHP_FUNCTION(intltz_get_gmt)121 U_CFUNC PHP_FUNCTION(intltz_get_gmt)
122 {
123 	intl_error_reset(NULL);
124 
125 	if (zend_parse_parameters_none() == FAILURE) {
126 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
127 			"intltz_get_gmt: bad arguments", 0);
128 		RETURN_NULL();
129 	}
130 
131 	timezone_object_construct(TimeZone::getGMT(), return_value, 0);
132 }
133 
PHP_FUNCTION(intltz_get_unknown)134 U_CFUNC PHP_FUNCTION(intltz_get_unknown)
135 {
136 	intl_error_reset(NULL);
137 
138 	if (zend_parse_parameters_none() == FAILURE) {
139 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
140 			"intltz_get_unknown: bad arguments", 0);
141 		RETURN_NULL();
142 	}
143 
144 	timezone_object_construct(&TimeZone::getUnknown(), return_value, 0);
145 }
146 
PHP_FUNCTION(intltz_create_enumeration)147 U_CFUNC PHP_FUNCTION(intltz_create_enumeration)
148 {
149 	zval				*arg = NULL;
150 	StringEnumeration	*se	  = NULL;
151 	intl_error_reset(NULL);
152 
153 	/* double indirection to have the zend engine destroy the new zval that
154 	 * results from separation */
155 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg) == FAILURE) {
156 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
157 			"intltz_create_enumeration: bad arguments", 0);
158 		RETURN_FALSE;
159 	}
160 
161 	if (arg == NULL || Z_TYPE_P(arg) == IS_NULL) {
162 		se = TimeZone::createEnumeration();
163 	} else if (Z_TYPE_P(arg) == IS_LONG) {
164 int_offset:
165 		if (Z_LVAL_P(arg) < (zend_long)INT32_MIN ||
166 				Z_LVAL_P(arg) > (zend_long)INT32_MAX) {
167 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
168 				"intltz_create_enumeration: value is out of range", 0);
169 			RETURN_FALSE;
170 		} else {
171 			se = TimeZone::createEnumeration((int32_t) Z_LVAL_P(arg));
172 		}
173 	} else if (Z_TYPE_P(arg) == IS_DOUBLE) {
174 double_offset:
175 		convert_to_long_ex(arg);
176 		goto int_offset;
177 	} else if (Z_TYPE_P(arg) == IS_OBJECT || Z_TYPE_P(arg) == IS_STRING) {
178 		zend_long lval;
179 		double dval;
180 		if (!try_convert_to_string(arg)) {
181 			return;
182 		}
183 		switch (is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), &lval, &dval, 0)) {
184 		case IS_DOUBLE:
185 			zval_ptr_dtor(arg);
186 			ZVAL_DOUBLE(arg, dval);
187 			goto double_offset;
188 		case IS_LONG:
189 			zval_ptr_dtor(arg);
190 			ZVAL_LONG(arg, lval);
191 			goto int_offset;
192 		}
193 		/* else call string version */
194 		se = TimeZone::createEnumeration(Z_STRVAL_P(arg));
195 	} else {
196 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
197 			"intltz_create_enumeration: invalid argument type", 0);
198 		RETURN_FALSE;
199 	}
200 
201 	if (se) {
202 		IntlIterator_from_StringEnumeration(se, return_value);
203 	} else {
204 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
205 			"intltz_create_enumeration: error obtaining enumeration", 0);
206 		RETVAL_FALSE;
207 	}
208 }
209 
PHP_FUNCTION(intltz_count_equivalent_ids)210 U_CFUNC PHP_FUNCTION(intltz_count_equivalent_ids)
211 {
212 	char	*str_id;
213 	size_t	 str_id_len;
214 	intl_error_reset(NULL);
215 
216 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
217 			&str_id, &str_id_len) == FAILURE) {
218 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
219 			"intltz_count_equivalent_ids: bad arguments", 0);
220 		RETURN_FALSE;
221 	}
222 
223 	UErrorCode status = UErrorCode();
224 	UnicodeString id = UnicodeString();
225 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
226 		intl_error_set(NULL, status,
227 			"intltz_count_equivalent_ids: could not convert time zone id to UTF-16", 0);
228 		RETURN_FALSE;
229 	}
230 
231 	int32_t result = TimeZone::countEquivalentIDs(id);
232 	RETURN_LONG((zend_long)result);
233 }
234 
PHP_FUNCTION(intltz_create_time_zone_id_enumeration)235 U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration)
236 {
237 	zend_long zoneType,
238 			  offset_arg;
239 	char	 *region		= NULL;
240 	size_t	  region_len	= 0;
241 	int32_t	  offset,
242 			 *offsetp	= NULL;
243 	zend_bool arg3isnull = 1;
244 
245 	intl_error_reset(NULL);
246 
247 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|s!l!",
248 			&zoneType, &region, &region_len, &offset_arg, &arg3isnull) == FAILURE) {
249 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
250 			"intltz_create_time_zone_id_enumeration: bad arguments", 0);
251 		RETURN_FALSE;
252 	}
253 
254 	if (zoneType != UCAL_ZONE_TYPE_ANY && zoneType != UCAL_ZONE_TYPE_CANONICAL
255 			&& zoneType != UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
256 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
257 			"intltz_create_time_zone_id_enumeration: bad zone type", 0);
258 		RETURN_FALSE;
259 	}
260 
261 	if (!arg3isnull) {
262 		if (offset_arg < (zend_long)INT32_MIN || offset_arg > (zend_long)INT32_MAX) {
263 			intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
264 				"intltz_create_time_zone_id_enumeration: offset out of bounds", 0);
265 			RETURN_FALSE;
266 		}
267 		offset = (int32_t)offset_arg;
268 		offsetp = &offset;
269 	} //else leave offsetp NULL
270 
271 	StringEnumeration *se;
272 	UErrorCode uec = UErrorCode();
273 	se = TimeZone::createTimeZoneIDEnumeration((USystemTimeZoneType)zoneType,
274 		region, offsetp, uec);
275 	INTL_CHECK_STATUS(uec, "intltz_create_time_zone_id_enumeration: "
276 		"Error obtaining time zone id enumeration")
277 
278 	IntlIterator_from_StringEnumeration(se, return_value);
279 }
280 
PHP_FUNCTION(intltz_get_canonical_id)281 U_CFUNC PHP_FUNCTION(intltz_get_canonical_id)
282 {
283 	char	*str_id;
284 	size_t	 str_id_len;
285 	zval	*is_systemid = NULL;
286 	intl_error_reset(NULL);
287 
288 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z",
289 			&str_id, &str_id_len, &is_systemid) == FAILURE) {
290 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
291 			"intltz_get_canonical_id: bad arguments", 0);
292 		RETURN_FALSE;
293 	}
294 
295 	UErrorCode status = UErrorCode();
296 	UnicodeString id;
297 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
298 		intl_error_set(NULL, status,
299 			"intltz_get_canonical_id: could not convert time zone id to UTF-16", 0);
300 		RETURN_FALSE;
301 	}
302 
303 	UnicodeString result;
304 	UBool isSystemID;
305 	TimeZone::getCanonicalID(id, result, isSystemID, status);
306 	INTL_CHECK_STATUS(status, "intltz_get_canonical_id: error obtaining canonical ID");
307 
308 	zend_string *u8str =intl_convert_utf16_to_utf8(result.getBuffer(), result.length(), &status);
309 	INTL_CHECK_STATUS(status,
310 		"intltz_get_canonical_id: could not convert time zone id to UTF-16");
311 	RETVAL_NEW_STR(u8str);
312 
313 	if (is_systemid) { /* by-ref argument passed */
314 		ZVAL_DEREF(is_systemid);
315 		zval_ptr_dtor(is_systemid);
316 		ZVAL_BOOL(is_systemid, isSystemID);
317 	}
318 }
319 
PHP_FUNCTION(intltz_get_region)320 U_CFUNC PHP_FUNCTION(intltz_get_region)
321 {
322 	char	*str_id;
323 	size_t	 str_id_len;
324 	char	 outbuf[3];
325 	intl_error_reset(NULL);
326 
327 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
328 			&str_id, &str_id_len) == FAILURE) {
329 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
330 			"intltz_get_region: bad arguments", 0);
331 		RETURN_FALSE;
332 	}
333 
334 	UErrorCode status = UErrorCode();
335 	UnicodeString id;
336 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
337 		intl_error_set(NULL, status,
338 			"intltz_get_region: could not convert time zone id to UTF-16", 0);
339 		RETURN_FALSE;
340 	}
341 
342 	int32_t region_len = TimeZone::getRegion(id, outbuf, sizeof(outbuf), status);
343 	INTL_CHECK_STATUS(status, "intltz_get_region: Error obtaining region");
344 
345 	RETURN_STRINGL(outbuf, region_len);
346 }
347 
PHP_FUNCTION(intltz_get_tz_data_version)348 U_CFUNC PHP_FUNCTION(intltz_get_tz_data_version)
349 {
350 	intl_error_reset(NULL);
351 
352 	if (zend_parse_parameters_none() == FAILURE) {
353 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
354 			"intltz_get_tz_data_version: bad arguments", 0);
355 		RETURN_FALSE;
356 	}
357 
358 	UErrorCode status = UErrorCode();
359 	const char *res = TimeZone::getTZDataVersion(status);
360 	INTL_CHECK_STATUS(status, "intltz_get_tz_data_version: "
361 		"Error obtaining time zone data version");
362 
363 	RETURN_STRING(res);
364 }
365 
PHP_FUNCTION(intltz_get_equivalent_id)366 U_CFUNC PHP_FUNCTION(intltz_get_equivalent_id)
367 {
368 	char	   *str_id;
369 	size_t		str_id_len;
370 	zend_long	index;
371 	intl_error_reset(NULL);
372 
373 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl",
374 			&str_id, &str_id_len, &index) == FAILURE ||
375 			index < (zend_long)INT32_MIN || index > (zend_long)INT32_MAX) {
376 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
377 			"intltz_get_equivalent_id: bad arguments", 0);
378 		RETURN_FALSE;
379 	}
380 
381 	UErrorCode status = UErrorCode();
382 	UnicodeString id;
383 	if (intl_stringFromChar(id, str_id, str_id_len, &status) == FAILURE) {
384 		intl_error_set(NULL, status,
385 			"intltz_get_equivalent_id: could not convert time zone id to UTF-16", 0);
386 		RETURN_FALSE;
387 	}
388 
389 	const UnicodeString result = TimeZone::getEquivalentID(id, (int32_t)index);
390 	zend_string *u8str;
391 
392 	u8str = intl_convert_utf16_to_utf8(result.getBuffer(), result.length(), &status);
393 	INTL_CHECK_STATUS(status, "intltz_get_equivalent_id: "
394 		"could not convert resulting time zone id to UTF-16");
395 	RETVAL_NEW_STR(u8str);
396 }
397 
PHP_FUNCTION(intltz_get_id)398 U_CFUNC PHP_FUNCTION(intltz_get_id)
399 {
400 	TIMEZONE_METHOD_INIT_VARS;
401 
402 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
403 			&object, TimeZone_ce_ptr) == FAILURE) {
404 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
405 			"intltz_get_id: bad arguments", 0);
406 		RETURN_FALSE;
407 	}
408 
409 	TIMEZONE_METHOD_FETCH_OBJECT;
410 
411 	UnicodeString id_us;
412 	to->utimezone->getID(id_us);
413 
414 	zend_string *u8str;
415 
416 	u8str = intl_convert_utf16_to_utf8(
417 		id_us.getBuffer(), id_us.length(), TIMEZONE_ERROR_CODE_P(to));
418 	INTL_METHOD_CHECK_STATUS(to, "intltz_get_id: Could not convert id to UTF-8");
419 
420 	RETVAL_NEW_STR(u8str);
421 }
422 
PHP_FUNCTION(intltz_use_daylight_time)423 U_CFUNC PHP_FUNCTION(intltz_use_daylight_time)
424 {
425 	TIMEZONE_METHOD_INIT_VARS;
426 
427 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
428 			&object, TimeZone_ce_ptr) == FAILURE) {
429 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
430 			"intltz_use_daylight_time: bad arguments", 0);
431 		RETURN_FALSE;
432 	}
433 
434 	TIMEZONE_METHOD_FETCH_OBJECT;
435 
436 	RETURN_BOOL(to->utimezone->useDaylightTime());
437 }
438 
PHP_FUNCTION(intltz_get_offset)439 U_CFUNC PHP_FUNCTION(intltz_get_offset)
440 {
441 	double		date;
442 	zend_bool	local;
443 	zval		*rawOffsetArg,
444 				*dstOffsetArg;
445 	int32_t		rawOffset,
446 				dstOffset;
447 	TIMEZONE_METHOD_INIT_VARS;
448 
449 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
450 			"Odbz/z/", &object, TimeZone_ce_ptr, &date, &local, &rawOffsetArg,
451 			&dstOffsetArg) == FAILURE) {
452 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
453 			"intltz_get_offset: bad arguments", 0);
454 		RETURN_FALSE;
455 	}
456 
457 	TIMEZONE_METHOD_FETCH_OBJECT;
458 
459 	to->utimezone->getOffset((UDate) date, (UBool) local, rawOffset, dstOffset,
460 		TIMEZONE_ERROR_CODE(to));
461 
462 	INTL_METHOD_CHECK_STATUS(to, "intltz_get_offset: error obtaining offset");
463 
464 	zval_ptr_dtor(rawOffsetArg);
465 	ZVAL_LONG(rawOffsetArg, rawOffset);
466 	zval_ptr_dtor(dstOffsetArg);
467 	ZVAL_LONG(dstOffsetArg, dstOffset);
468 
469 	RETURN_TRUE;
470 }
471 
PHP_FUNCTION(intltz_get_raw_offset)472 U_CFUNC PHP_FUNCTION(intltz_get_raw_offset)
473 {
474 	TIMEZONE_METHOD_INIT_VARS;
475 
476 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
477 			"O", &object, TimeZone_ce_ptr) == FAILURE) {
478 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
479 			"intltz_get_raw_offset: bad arguments", 0);
480 		RETURN_FALSE;
481 	}
482 
483 	TIMEZONE_METHOD_FETCH_OBJECT;
484 
485 	RETURN_LONG(to->utimezone->getRawOffset());
486 }
487 
PHP_FUNCTION(intltz_has_same_rules)488 U_CFUNC PHP_FUNCTION(intltz_has_same_rules)
489 {
490 	zval			*other_object;
491 	TimeZone_object	*other_to;
492 	TIMEZONE_METHOD_INIT_VARS;
493 
494 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
495 			"OO", &object, TimeZone_ce_ptr, &other_object, TimeZone_ce_ptr)
496 			== FAILURE) {
497 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
498 			"intltz_has_same_rules: bad arguments", 0);
499 		RETURN_FALSE;
500 	}
501 	TIMEZONE_METHOD_FETCH_OBJECT;
502 	other_to = Z_INTL_TIMEZONE_P(other_object);
503 	if (other_to->utimezone == NULL) {
504 		intl_errors_set(&to->err, U_ILLEGAL_ARGUMENT_ERROR,
505 			"intltz_has_same_rules: The second IntlTimeZone is unconstructed", 0);
506 		RETURN_FALSE;
507 	}
508 
509 	RETURN_BOOL(to->utimezone->hasSameRules(*other_to->utimezone));
510 }
511 
512 static const TimeZone::EDisplayType display_types[] = {
513 	TimeZone::SHORT,				TimeZone::LONG,
514 	TimeZone::SHORT_GENERIC,		TimeZone::LONG_GENERIC,
515 	TimeZone::SHORT_GMT,			TimeZone::LONG_GMT,
516 	TimeZone::SHORT_COMMONLY_USED,	TimeZone::GENERIC_LOCATION
517 };
518 
PHP_FUNCTION(intltz_get_display_name)519 U_CFUNC PHP_FUNCTION(intltz_get_display_name)
520 {
521 	zend_bool	daylight		= 0;
522 	zend_long	display_type	= TimeZone::LONG;
523 	const char *locale_str		= NULL;
524 	size_t		dummy			= 0;
525 	TIMEZONE_METHOD_INIT_VARS;
526 
527 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
528 			"O|bls!", &object, TimeZone_ce_ptr, &daylight, &display_type,
529 			&locale_str, &dummy) == FAILURE) {
530 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
531 			"intltz_get_display_name: bad arguments", 0);
532 		RETURN_FALSE;
533 	}
534 
535 	bool found = false;
536 	for (int i = 0; !found && i < sizeof(display_types)/sizeof(*display_types); i++) {
537 		if (display_types[i] == display_type)
538 			found = true;
539 	}
540 	if (!found) {
541 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
542 			"intltz_get_display_name: wrong display type", 0);
543 		RETURN_FALSE;
544 	}
545 
546 	if (!locale_str) {
547 		locale_str = intl_locale_get_default();
548 	}
549 
550 	TIMEZONE_METHOD_FETCH_OBJECT;
551 
552 	UnicodeString result;
553 	to->utimezone->getDisplayName((UBool)daylight, (TimeZone::EDisplayType)display_type,
554 		Locale::createFromName(locale_str), result);
555 
556 	zend_string *u8str = intl_convert_utf16_to_utf8(result.getBuffer(), result.length(), TIMEZONE_ERROR_CODE_P(to));
557 	INTL_METHOD_CHECK_STATUS(to, "intltz_get_display_name: "
558 		"could not convert resulting time zone id to UTF-16");
559 
560 	RETVAL_NEW_STR(u8str);
561 }
562 
PHP_FUNCTION(intltz_get_dst_savings)563 U_CFUNC PHP_FUNCTION(intltz_get_dst_savings)
564 {
565 	TIMEZONE_METHOD_INIT_VARS;
566 
567 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
568 			"O", &object, TimeZone_ce_ptr) == FAILURE) {
569 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
570 			"intltz_get_dst_savings: bad arguments", 0);
571 		RETURN_FALSE;
572 	}
573 
574 	TIMEZONE_METHOD_FETCH_OBJECT;
575 
576 	RETURN_LONG((zend_long)to->utimezone->getDSTSavings());
577 }
578 
PHP_FUNCTION(intltz_to_date_time_zone)579 U_CFUNC PHP_FUNCTION(intltz_to_date_time_zone)
580 {
581 	zval tmp;
582 	TIMEZONE_METHOD_INIT_VARS;
583 
584 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
585 			"O", &object, TimeZone_ce_ptr) == FAILURE) {
586 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
587 			"intltz_to_date_time_zone: bad arguments", 0);
588 		RETURN_FALSE;
589 	}
590 
591 	TIMEZONE_METHOD_FETCH_OBJECT;
592 
593 	zval *ret = timezone_convert_to_datetimezone(to->utimezone,
594 		&TIMEZONE_ERROR(to), "intltz_to_date_time_zone", &tmp);
595 
596 	if (ret) {
597 		ZVAL_COPY_VALUE(return_value, ret);
598 	} else {
599 		RETURN_FALSE;
600 	}
601 }
602 
PHP_FUNCTION(intltz_get_error_code)603 U_CFUNC PHP_FUNCTION(intltz_get_error_code)
604 {
605 	TIMEZONE_METHOD_INIT_VARS
606 
607 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
608 			&object, TimeZone_ce_ptr) == FAILURE) {
609 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
610 			"intltz_get_error_code: bad arguments", 0);
611 		RETURN_FALSE;
612 	}
613 
614 	/* Fetch the object (without resetting its last error code ). */
615 	to = Z_INTL_TIMEZONE_P(object);
616 	if (to == NULL)
617 		RETURN_FALSE;
618 
619 	RETURN_LONG((zend_long)TIMEZONE_ERROR_CODE(to));
620 }
621 
PHP_FUNCTION(intltz_get_error_message)622 U_CFUNC PHP_FUNCTION(intltz_get_error_message)
623 {
624 	zend_string* message = NULL;
625 	TIMEZONE_METHOD_INIT_VARS
626 
627 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
628 			&object, TimeZone_ce_ptr) == FAILURE) {
629 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
630 			"intltz_get_error_message: bad arguments", 0 );
631 		RETURN_FALSE;
632 	}
633 
634 
635 	/* Fetch the object (without resetting its last error code ). */
636 	to = Z_INTL_TIMEZONE_P(object);
637 	if (to == NULL)
638 		RETURN_FALSE;
639 
640 	/* Return last error message. */
641 	message = intl_error_get_message(TIMEZONE_ERROR_P(to));
642 	RETURN_STR(message);
643 }
644 
645 #if U_ICU_VERSION_MAJOR_NUM >= 52
646 /* {{{ proto string IntlTimeZone::getWindowsID(string $timezone)
647        proto string intltz_get_windows_id(string $timezone)
648 Translate a system timezone (e.g. "America/Los_Angeles" into a
649 Windows Timezone (e.g. "Pacific Standard Time")
650  */
PHP_FUNCTION(intltz_get_windows_id)651 U_CFUNC PHP_FUNCTION(intltz_get_windows_id)
652 {
653 	zend_string *id, *winID;
654 	UnicodeString uID, uWinID;
655 	UErrorCode error;
656 
657 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &id) == FAILURE) {
658 		return;
659 	}
660 
661 	error = U_ZERO_ERROR;
662 	if (intl_stringFromChar(uID, id->val, id->len, &error) == FAILURE) {
663 		intl_error_set(NULL, error,
664 		               "intltz_get_windows_id: could not convert time zone id to UTF-16", 0);
665 		RETURN_FALSE;
666 	}
667 
668 	error = U_ZERO_ERROR;
669 	TimeZone::getWindowsID(uID, uWinID, error);
670 	INTL_CHECK_STATUS(error, "intltz_get_windows_id: Unable to get timezone from windows ID");
671 	if (uWinID.length() == 0) {
672 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
673 		               "intltz_get_windows_id: Unknown system timezone", 0);
674 		RETURN_FALSE;
675 	}
676 
677 	error = U_ZERO_ERROR;
678 	winID = intl_convert_utf16_to_utf8(uWinID.getBuffer(), uWinID.length(), &error);
679 	INTL_CHECK_STATUS(error, "intltz_get_windows_id: could not convert time zone id to UTF-8");
680 	RETURN_STR(winID);
681 }
682 /* }}} */
683 
684 /* {{{ proto string IntlTimeZone::getIDForWindowsID(string $timezone[, string $region = NULL])
685        proto string intltz_get_id_for_windows_id(string $timezone[, string $region = NULL])
686 Translate a windows timezone (e.g. "Pacific Time Zone" into a
687 System Timezone (e.g. "America/Los_Angeles")
688  */
PHP_FUNCTION(intltz_get_id_for_windows_id)689 U_CFUNC PHP_FUNCTION(intltz_get_id_for_windows_id)
690 {
691 	zend_string *winID, *region = NULL, *id;
692 	UnicodeString uWinID, uID;
693 	UErrorCode error;
694 
695 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|S", &winID, &region) == FAILURE) {
696 		return;
697 	}
698 
699 	error = U_ZERO_ERROR;
700 	if (intl_stringFromChar(uWinID, winID->val, winID->len, &error) == FAILURE) {
701 		intl_error_set(NULL, error,
702 		               "intltz_get_id_for_windows_id: could not convert time zone id to UTF-16", 0);
703 		RETURN_FALSE;
704 	}
705 
706 	error = U_ZERO_ERROR;
707 	TimeZone::getIDForWindowsID(uWinID, region ? region->val : NULL, uID, error);
708 	INTL_CHECK_STATUS(error, "intltz_get_id_for_windows_id: Unable to get windows ID for timezone");
709 	if (uID.length() == 0) {
710 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
711 		               "intltz_get_windows_id: Unknown windows timezone", 0);
712 		RETURN_FALSE;
713 	}
714 
715 	error = U_ZERO_ERROR;
716 	id = intl_convert_utf16_to_utf8(uID.getBuffer(), uID.length(), &error);
717 	INTL_CHECK_STATUS(error, "intltz_get_id_for_windows_id: could not convert time zone id to UTF-8");
718 	RETURN_STR(id);
719 }
720 /* }}} */
721 #endif
722