diff options
| author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2012-04-30 15:15:09 +0200 |
|---|---|---|
| committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2012-05-17 17:23:51 +0200 |
| commit | 4cfd9995daf249c02f4d8a23f96288d1b2a2f4c0 (patch) | |
| tree | 9a05442b20a264bcb2d3f8157b585c6686d911ab /ext/intl | |
| parent | 22f4a307481f1667bdc95f7ec7c43538427b73ab (diff) | |
| download | php-git-4cfd9995daf249c02f4d8a23f96288d1b2a2f4c0.tar.gz | |
Added IntlTimeZone::fromDateTimeZone() and ::toDateTimeZone.
IntlTimeZone::fromDateTimeZone(DateTimeZone $dtz) converts from an
ext/date TimeZone to an IntlTimeZone. The conversion is done by feeding
the time zone name (essentially what would be given by
DateTimeZone::getName()) to ICU's TimeZone::createTimeZone except if it's
an offset time zone. In that case, the offset is read from the ext/date
time zone object structure and an appopriate id (of the form
GMT<+|-><HH:MM>) is given to ICU's TimeZone::createTimeZone. Not all
ext/date time zones are recognized for ICU. For instance, WEST is not.
Note that these kind of abbreviations, as far as I can tell, can only be
created via ext/date DateTime, not directly through DateTimeZone's
constructor.
For IntlTimeZone::toDateTimeZone(), the behavior is symmetrical.
We instantiate a DateTimeZone and then call its constructor if we don't
have an offset time zone, otherwise we mess with its structure. If the
timezone is not valid for ext/date, then we allow the exception of
DateTimeZone constructor to propagate.
Diffstat (limited to 'ext/intl')
| -rwxr-xr-x | ext/intl/php_intl.c | 6 | ||||
| -rw-r--r-- | ext/intl/tests/timezone_fromDateTimeZone_basic.phpt | 41 | ||||
| -rw-r--r-- | ext/intl/tests/timezone_fromDateTimeZone_error.phpt | 48 | ||||
| -rw-r--r-- | ext/intl/tests/timezone_toDateTimeZone_basic.phpt | 38 | ||||
| -rw-r--r-- | ext/intl/tests/timezone_toDateTimeZone_error.phpt | 38 | ||||
| -rw-r--r-- | ext/intl/timezone/timezone_class.cpp | 77 | ||||
| -rw-r--r-- | ext/intl/timezone/timezone_class.h | 1 | ||||
| -rw-r--r-- | ext/intl/timezone/timezone_methods.cpp | 57 | ||||
| -rw-r--r-- | ext/intl/timezone/timezone_methods.h | 4 |
9 files changed, 308 insertions, 2 deletions
diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c index 51aece69d5..4924fdef39 100755 --- a/ext/intl/php_intl.c +++ b/ext/intl/php_intl.c @@ -414,6 +414,10 @@ ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_idarg_static, 0, 0, 1 ) ZEND_ARG_INFO( 0, zoneId ) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_from_date_time_zone, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, dateTimeZone, IntlDateTimeZone, 0 ) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX( arginfo_tz_create_enumeration, 0, 0, 0 ) ZEND_ARG_INFO( 0, countryOrRawOffset ) ZEND_END_ARG_INFO() @@ -719,6 +723,7 @@ zend_function_entry intl_functions[] = { /* TimeZone functions */ PHP_FE( intltz_create_time_zone, arginfo_tz_idarg_static ) + PHP_FE( intltz_from_date_time_zone, arginfo_tz_from_date_time_zone ) PHP_FE( intltz_create_default, arginfo_tz_void ) PHP_FE( intltz_get_id, arginfo_tz_only_tz ) PHP_FE( intltz_get_gmt, arginfo_tz_void ) @@ -742,6 +747,7 @@ zend_function_entry intl_functions[] = { PHP_FE( intltz_has_same_rules, arginfo_tz_has_same_rules ) PHP_FE( intltz_get_display_name, arginfo_tz_get_display_name ) PHP_FE( intltz_get_dst_savings, arginfo_tz_only_tz ) + PHP_FE( intltz_to_date_time_zone, arginfo_tz_only_tz ) PHP_FE( intltz_get_error_code, arginfo_tz_only_tz ) PHP_FE( intltz_get_error_message, arginfo_tz_only_tz ) diff --git a/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt b/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt new file mode 100644 index 0000000000..10e2621ae4 --- /dev/null +++ b/ext/intl/tests/timezone_fromDateTimeZone_basic.phpt @@ -0,0 +1,41 @@ +--TEST-- +IntlTimeZone::fromDateTimeZone(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); +date_default_timezone_set('Europe/Lisbon'); + +$tz = IntlTimeZone::fromDateTimeZone(new DateTimeZone('Europe/Amsterdam')); +var_dump($tz->getID(), $tz->getRawOffset()); + + +$dt = new DateTime('2012-01-01 00:00:00 CET'); +$dtz = $dt->getTimeZone(); +/* this is different from new DateTimeZone('CET'), + * which gives a Europe/Berlin timezone */ +var_dump($dtz->getName()); +$tz = IntlTimeZone::fromDateTimeZone($dtz); +var_dump($tz->getID(), $tz->getRawOffset()); + + +$dt = new DateTime('2012-01-01 00:00:00 +0340'); +$dtz = $dt->getTimeZone(); +/* I don't think this timezone can be generated without a DateTime object */ +var_dump($dtz->getName()); +$tz = IntlTimeZone::fromDateTimeZone($dtz); +var_dump($tz->getID(), $tz->getRawOffset() /* (3*60+40)*60000 */); + +--EXPECTF-- +string(16) "Europe/Amsterdam" +int(3600000) +string(3) "CET" +string(3) "CET" +int(3600000) +string(6) "+03:40" +string(%d) "GMT+03%s0" +int(13200000) diff --git a/ext/intl/tests/timezone_fromDateTimeZone_error.phpt b/ext/intl/tests/timezone_fromDateTimeZone_error.phpt new file mode 100644 index 0000000000..4d6c153bd2 --- /dev/null +++ b/ext/intl/tests/timezone_fromDateTimeZone_error.phpt @@ -0,0 +1,48 @@ +--TEST-- +IntlTimeZone::fromDateTimeZone(): argument errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +var_dump(IntlTimeZone::fromDateTimeZone()); +var_dump(IntlTimeZone::fromDateTimeZone(1,2)); +var_dump(IntlTimeZone::fromDateTimeZone('sdfds')); +var_dump(IntlTimeZone::fromDateTimeZone(new stdclass)); +$dt = new DateTime('2012-08-01 00:00:00 WEST'); +var_dump(IntlTimeZone::fromDateTimeZone($dt->getTimeZone())); + +var_dump(intltz_from_date_time_zone()); + +--EXPECTF-- + +Warning: IntlTimeZone::fromDateTimeZone() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::fromDateTimeZone() expects exactly 1 parameter, 2 given in %s on line %d + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::fromDateTimeZone() expects parameter 1 to be DateTimeZone, string given in %s on line %d + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::fromDateTimeZone() expects parameter 1 to be DateTimeZone, object given in %s on line %d + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL + +Warning: IntlTimeZone::fromDateTimeZone(): intltz_from_date_time_zone: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d +NULL + +Warning: intltz_from_date_time_zone() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: intltz_from_date_time_zone(): intltz_from_date_time_zone: bad arguments in %s on line %d +NULL diff --git a/ext/intl/tests/timezone_toDateTimeZone_basic.phpt b/ext/intl/tests/timezone_toDateTimeZone_basic.phpt new file mode 100644 index 0000000000..d22aa689dc --- /dev/null +++ b/ext/intl/tests/timezone_toDateTimeZone_basic.phpt @@ -0,0 +1,38 @@ +--TEST-- +IntlTimeZone::toDateTimeZone(): basic test +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); +ini_set("intl.default_locale", "nl"); +date_default_timezone_set('Europe/Lisbon'); + +function do_test(IntlTimeZone $tz, $proc = false) { + var_dump($tz->getID(), $tz->getRawOffset()); + if (!$proc) + $dtz = $tz->toDateTimeZone(); + else + $dtz = intltz_to_date_time_zone($tz); + var_dump($dtz->getName(), $dtz->getOffset(new DateTime('2012-01-01 00:00:00'))); +} + +do_test(IntlTimeZone::createTimeZone('CET')); +do_test(IntlTimeZone::createTimeZone('Europe/Amsterdam')); +do_test(IntlTimeZone::createTimeZone('GMT+0405'), true); + +--EXPECTF-- +string(3) "CET" +int(3600000) +string(13) "Europe/Berlin" +int(3600) +string(16) "Europe/Amsterdam" +int(3600000) +string(16) "Europe/Amsterdam" +int(3600) +string(%s) "GMT+04%s5" +int(14700000) +string(6) "+04:05" +int(14700) diff --git a/ext/intl/tests/timezone_toDateTimeZone_error.phpt b/ext/intl/tests/timezone_toDateTimeZone_error.phpt new file mode 100644 index 0000000000..e48d7aca92 --- /dev/null +++ b/ext/intl/tests/timezone_toDateTimeZone_error.phpt @@ -0,0 +1,38 @@ +--TEST-- +IntlTimeZone::toDateTimeZone(): errors +--SKIPIF-- +<?php +if (!extension_loaded('intl')) + die('skip intl extension not enabled'); +--FILE-- +<?php +ini_set("intl.error_level", E_WARNING); + +$tz = IntlTimeZone::createTimeZone('Etc/Unknown'); + +var_dump($tz->toDateTimeZone('')); +try { + var_dump($tz->toDateTimeZone()); +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +var_dump(intltz_to_date_time_zone()); +var_dump(intltz_to_date_time_zone(1)); + +--EXPECTF-- + +Warning: IntlTimeZone::toDateTimeZone() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: IntlTimeZone::toDateTimeZone(): intltz_to_date_time_zone: bad arguments in %s on line %d +bool(false) + +Warning: IntlTimeZone::toDateTimeZone(): intltz_to_date_time_zone: DateTimeZone constructor threw exception in %s on line %d +string(66) "DateTimeZone::__construct(): Unknown or bad timezone (Etc/Unknown)" + +Warning: intltz_to_date_time_zone() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: intltz_to_date_time_zone(): intltz_to_date_time_zone: bad arguments in %s on line %d +bool(false) + +Catchable fatal error: Argument 1 passed to intltz_to_date_time_zone() must be an instance of IntlTimeZone, integer given in %s on line %d diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp index 7032368737..31893fe491 100644 --- a/ext/intl/timezone/timezone_class.cpp +++ b/ext/intl/timezone/timezone_class.cpp @@ -29,6 +29,7 @@ extern "C" { #include "timezone_class.h" #include "timezone_methods.h" #include <zend_exceptions.h> +#include <zend_interfaces.h> /* avoid redefinition of int8_t, already defined in unicode/pwin32.h */ #define _MSC_STDINT_H_ 1 #include <ext/date/php_date.h> @@ -107,7 +108,7 @@ U_CFUNC TimeZone *timezone_convert_datetimezone(int type, UnicodeString s = UnicodeString(id, id_len, US_INV); timeZone = TimeZone::createTimeZone(s); #if U_ICU_VERSION_MAJOR_NUM >= 49 - if (timeZone == TimeZone::getUnknown()) { + if (*timeZone == TimeZone::getUnknown()) { #else UnicodeString resultingId; timeZone->getID(resultingId); @@ -115,7 +116,7 @@ U_CFUNC TimeZone *timezone_convert_datetimezone(int type, || resultingId == UnicodeString("GMT", -1, US_INV)) { #endif spprintf(&message, 0, "%s: time zone id '%s' " - "extracted from ext/date TimeZone not recognized", func, id); + "extracted from ext/date DateTimeZone not recognized", func, id); intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); efree(message); @@ -126,6 +127,72 @@ U_CFUNC TimeZone *timezone_convert_datetimezone(int type, } /* }}} */ +/* {{{ timezone_convert_to_datetimezone + * Convert from TimeZone to DateTimeZone object */ +U_CFUNC zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, + intl_error *outside_error, + const char *func TSRMLS_DC) +{ + zval *ret = NULL; + UnicodeString id; + char *message = NULL; + php_timezone_obj *tzobj; + + timeZone->getID(id); + if (id.isBogus()) { + spprintf(&message, 0, "%s: could not obtain TimeZone id", func); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + goto error; + } + + MAKE_STD_ZVAL(ret); + object_init_ex(ret, php_date_get_timezone_ce()); + tzobj = (php_timezone_obj *)zend_objects_get_address(ret TSRMLS_CC); + + if (id.compare(0, 3, UnicodeString("GMT", sizeof("GMT")-1, US_INV)) == 0) { + /* The DateTimeZone constructor doesn't support offset time zones, + * so we must mess with DateTimeZone structure ourselves */ + tzobj->initialized = 1; + tzobj->type = TIMELIB_ZONETYPE_OFFSET; + //convert offset from milliseconds to minutes + tzobj->tzi.utc_offset = -1 * timeZone->getRawOffset() / (60 * 1000); + } else { + /* Call the constructor! */ + zval arg = zval_used_for_init; + Z_TYPE(arg) = IS_STRING; + if (intl_charFromString(id, &Z_STRVAL(arg), &Z_STRLEN(arg), + &INTL_ERROR_CODE(*outside_error)) == FAILURE) { + spprintf(&message, 0, "%s: could not convert id to UTF-8", func); + intl_errors_set(outside_error, INTL_ERROR_CODE(*outside_error), + message, 1 TSRMLS_CC); + goto error; + } + zend_call_method_with_1_params(&ret, NULL, NULL, "__construct", + NULL, &arg); + if (EG(exception)) { + spprintf(&message, 0, + "%s: DateTimeZone constructor threw exception", func); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + zend_object_store_ctor_failed(ret TSRMLS_CC); + goto error; + } + } + + return ret; + +error: + if (message) { + efree(message); + } + if (ret) { + zval_ptr_dtor(&ret); + } + return NULL; +} +/* }}} */ + /* {{{ timezone_process_timezone_argument * TimeZone argument processor. outside_error may be NULL (for static functions/constructors) */ U_CFUNC TimeZone *timezone_process_timezone_argument(zval **zv_timezone, @@ -400,6 +467,10 @@ ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_idarg, 0, 0, 1) ZEND_ARG_INFO(0, zoneId) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_fromDateTimeZone, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, otherTimeZone, IntlTimeZone, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(ainfo_tz_createEnumeration, 0, 0, 0) ZEND_ARG_INFO(0, countryOrRawOffset) ZEND_END_ARG_INFO() @@ -451,6 +522,7 @@ ZEND_END_ARG_INFO() */ static zend_function_entry TimeZone_class_functions[] = { PHP_ME_MAPPING(createTimeZone, intltz_create_time_zone, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME_MAPPING(fromDateTimeZone, intltz_from_date_time_zone, ainfo_tz_idarg, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME_MAPPING(createDefault, intltz_create_default, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME_MAPPING(getGMT, intltz_get_gmt, ainfo_tz_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) #if U_ICU_VERSION_MAJOR_NUM >= 49 @@ -475,6 +547,7 @@ static zend_function_entry TimeZone_class_functions[] = { PHP_ME_MAPPING(hasSameRules, intltz_has_same_rules, ainfo_tz_hasSameRules, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getDisplayName, intltz_get_display_name, ainfo_tz_getDisplayName, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getDSTSavings, intltz_get_dst_savings, ainfo_tz_void, ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(toDateTimeZone, intltz_to_date_time_zone, ainfo_tz_void, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getErrorCode, intltz_get_error_code, ainfo_tz_void, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getErrorMessage, intltz_get_error_message, ainfo_tz_void, ZEND_ACC_PUBLIC) PHP_FE_END diff --git a/ext/intl/timezone/timezone_class.h b/ext/intl/timezone/timezone_class.h index d5fabb9280..0d3c0edde4 100644 --- a/ext/intl/timezone/timezone_class.h +++ b/ext/intl/timezone/timezone_class.h @@ -60,6 +60,7 @@ typedef struct { } TimeZone *timezone_convert_datetimezone(int type, void *object, int is_datetime, intl_error *outside_error, const char *func TSRMLS_DC); +zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, intl_error *outside_error, const char *func TSRMLS_DC); TimeZone *timezone_process_timezone_argument(zval **zv_timezone, intl_error *error, const char *func TSRMLS_DC); void timezone_object_construct(const TimeZone *zone, zval *object, int owned TSRMLS_DC); diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp index eaa6b46e39..e596cc5174 100644 --- a/ext/intl/timezone/timezone_methods.cpp +++ b/ext/intl/timezone/timezone_methods.cpp @@ -28,6 +28,9 @@ extern "C" { #include "intl_convert.h" #include "../locale/locale.h" #include <zend_exceptions.h> +/* avoid redefinition of int8_t, already defined in unicode/pwin32.h */ +#define _MSC_STDINT_H_ 1 +#include <ext/date/php_date.h> } #include "common/common_enum.h" @@ -57,6 +60,37 @@ U_CFUNC PHP_FUNCTION(intltz_create_time_zone) timezone_object_construct(tz, return_value, 1 TSRMLS_CC); } +U_CFUNC PHP_FUNCTION(intltz_from_date_time_zone) +{ + zval *zv_timezone; + TimeZone *tz; + php_timezone_obj *tzobj; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", + &zv_timezone, php_date_get_timezone_ce()) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_from_date_time_zone: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + tzobj = (php_timezone_obj *)zend_objects_get_address(zv_timezone TSRMLS_CC); + if (!tzobj->initialized) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_from_date_time_zone: DateTimeZone object is unconstructed", + 0 TSRMLS_CC); + RETURN_NULL(); + } + + tz = timezone_convert_datetimezone(tzobj->type, tzobj, FALSE, NULL, + "intltz_from_date_time_zone" TSRMLS_CC); + if (tz == NULL) { + RETURN_NULL(); + } + + timezone_object_construct(tz, return_value, 1 TSRMLS_CC); +} + U_CFUNC PHP_FUNCTION(intltz_create_default) { intl_error_reset(NULL TSRMLS_CC); @@ -549,6 +583,29 @@ U_CFUNC PHP_FUNCTION(intltz_get_dst_savings) RETURN_LONG((long)to->utimezone->getDSTSavings()); } +U_CFUNC PHP_FUNCTION(intltz_to_date_time_zone) +{ + TIMEZONE_METHOD_INIT_VARS; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), + "O", &object, TimeZone_ce_ptr) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intltz_to_date_time_zone: bad arguments", 0 TSRMLS_CC); + RETURN_FALSE; + } + + TIMEZONE_METHOD_FETCH_OBJECT; + + zval *ret = timezone_convert_to_datetimezone(to->utimezone, + &TIMEZONE_ERROR(to), "intltz_to_date_time_zone" TSRMLS_CC); + + if (ret) { + RETURN_ZVAL(ret, 1, 1); + } else { + RETURN_FALSE; + } +} + U_CFUNC PHP_FUNCTION(intltz_get_error_code) { TIMEZONE_METHOD_INIT_VARS diff --git a/ext/intl/timezone/timezone_methods.h b/ext/intl/timezone/timezone_methods.h index 207caa3cb0..824f72a0d2 100644 --- a/ext/intl/timezone/timezone_methods.h +++ b/ext/intl/timezone/timezone_methods.h @@ -21,6 +21,8 @@ PHP_FUNCTION(intltz_create_time_zone); +PHP_FUNCTION(intltz_from_date_time_zone); + PHP_FUNCTION(intltz_create_default); PHP_FUNCTION(intltz_get_id); @@ -55,6 +57,8 @@ PHP_FUNCTION(intltz_get_display_name); PHP_FUNCTION(intltz_get_dst_savings); +PHP_FUNCTION(intltz_to_date_time_zone); + PHP_FUNCTION(intltz_get_error_code); PHP_FUNCTION(intltz_get_error_message); |
