diff options
author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2012-04-06 21:50:08 +0200 |
---|---|---|
committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2012-05-17 17:23:46 +0200 |
commit | 9a35d45a5b2226750e198042201e63a37c127f31 (patch) | |
tree | 404d3f5597f6edc32e3e6ef2b6c86ace6c068fb5 /ext/intl | |
parent | 51e3e51d3b574519869bf21d0136b25f48ca7a99 (diff) | |
download | php-git-9a35d45a5b2226750e198042201e63a37c127f31.tar.gz |
Accept DateTimeZone where time zones are expected.
Also unified timezone handling in IntlCalendar::setTimeZone()
to that in the IntlCalendar and IntlGregorianCalendar constructors.
Diffstat (limited to 'ext/intl')
-rw-r--r-- | ext/intl/calendar/calendar_class.cpp | 4 | ||||
-rw-r--r-- | ext/intl/calendar/calendar_methods.cpp | 22 | ||||
-rw-r--r-- | ext/intl/calendar/gregoriancalendar_methods.cpp | 2 | ||||
-rwxr-xr-x | ext/intl/php_intl.c | 2 | ||||
-rw-r--r-- | ext/intl/tests/calendar_setTimeZone_error2.phpt | 29 | ||||
-rw-r--r-- | ext/intl/tests/calendar_setTimeZone_variation2.phpt | 30 | ||||
-rw-r--r-- | ext/intl/timezone/timezone_class.cpp | 100 | ||||
-rw-r--r-- | ext/intl/timezone/timezone_class.h | 3 |
8 files changed, 164 insertions, 28 deletions
diff --git a/ext/intl/calendar/calendar_class.cpp b/ext/intl/calendar/calendar_class.cpp index 1a477396dd..ea5339d836 100644 --- a/ext/intl/calendar/calendar_class.cpp +++ b/ext/intl/calendar/calendar_class.cpp @@ -316,8 +316,8 @@ ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_add, 0, 0, 2) ZEND_ARG_INFO(0, amount) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_setTimeZone, 0, 0, 2) - ZEND_ARG_OBJ_INFO(0, timeZone, IntlTimeZone, 1) +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_setTimeZone, 0, 0, 1) + ZEND_ARG_INFO(0, timeZone) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_set, 0, 0, 2) diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp index f8d977c428..0c6450fce7 100644 --- a/ext/intl/calendar/calendar_methods.cpp +++ b/ext/intl/calendar/calendar_methods.cpp @@ -30,6 +30,9 @@ extern "C" { #include "../intl_convert.h" #include "../locale/locale.h" #include <zend_exceptions.h> +#include <zend_interfaces.h> +#define _MSC_STDINT_H_ /* avoid redefinitions */ +#include <ext/date/php_date.h> } #include "../common/common_enum.h" @@ -56,7 +59,7 @@ U_CFUNC PHP_FUNCTION(intlcal_create_instance) RETURN_NULL(); } - timeZone = timezone_process_timezone_argument(zv_timezone, + timeZone = timezone_process_timezone_argument(zv_timezone, NULL, "intlcal_create_instance" TSRMLS_CC); if (timeZone == NULL) { RETURN_NULL(); @@ -323,11 +326,10 @@ U_CFUNC PHP_FUNCTION(intlcal_set_time_zone) { zval *zv_timezone; TimeZone *timeZone; - TimeZone_object *tzo; CALENDAR_METHOD_INIT_VARS; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), - "OO!", &object, Calendar_ce_ptr, &zv_timezone, TimeZone_ce_ptr) == FAILURE) { + "Oz!", &object, Calendar_ce_ptr, &zv_timezone) == FAILURE) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intlcal_set_time_zone: bad arguments", 0 TSRMLS_CC); RETURN_FALSE; @@ -338,18 +340,10 @@ U_CFUNC PHP_FUNCTION(intlcal_set_time_zone) if (zv_timezone == NULL) { RETURN_TRUE; /* the method does nothing if passed null */ } - - tzo = static_cast<TimeZone_object*>( - zend_object_store_get_object(zv_timezone TSRMLS_CC)); - if (tzo->utimezone == NULL) { - intl_errors_set(&co->err, U_ILLEGAL_ARGUMENT_ERROR, - "intlcal_set_time_zone: found unsconstructed IntlTimeZone", 0 TSRMLS_CC); - RETURN_FALSE; - } - timeZone = tzo->utimezone->clone(); + + timeZone = timezone_process_timezone_argument(&zv_timezone, + CALENDAR_ERROR_P(co), "intlcal_set_time_zone" TSRMLS_CC); if (timeZone == NULL) { - intl_errors_set(&co->err, U_MEMORY_ALLOCATION_ERROR, - "intlcal_set_time_zone: error cloning ICU TimeZone", 0 TSRMLS_CC); RETURN_FALSE; } diff --git a/ext/intl/calendar/gregoriancalendar_methods.cpp b/ext/intl/calendar/gregoriancalendar_methods.cpp index 31fb8a8991..4f26cc5945 100644 --- a/ext/intl/calendar/gregoriancalendar_methods.cpp +++ b/ext/intl/calendar/gregoriancalendar_methods.cpp @@ -88,7 +88,7 @@ static void _php_intlgregcal_constructor_body(INTERNAL_FUNCTION_PARAMETERS) if (variant <= 2) { // From timezone and locale (0 to 2 arguments) - TimeZone *tz = timezone_process_timezone_argument(tz_object, + TimeZone *tz = timezone_process_timezone_argument(tz_object, NULL, "intlgregcal_create_instance" TSRMLS_CC); if (tz == NULL) { RETURN_NULL(); diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c index f160f9dda2..aca3590e01 100755 --- a/ext/intl/php_intl.c +++ b/ext/intl/php_intl.c @@ -516,7 +516,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set_time_zone, 0, 0, 2 ) ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) - ZEND_ARG_OBJ_INFO( 0, timeZone, IntlTimeZone, 1 ) + ZEND_ARG_INFO( 0, timeZone ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set, 0, 0, 3 ) diff --git a/ext/intl/tests/calendar_setTimeZone_error2.phpt b/ext/intl/tests/calendar_setTimeZone_error2.phpt new file mode 100644 index 0000000000..aa1eaba209 --- /dev/null +++ b/ext/intl/tests/calendar_setTimeZone_error2.phpt @@ -0,0 +1,29 @@ +--TEST-- +IntlCalendar::setTimeZone(): valid time zones for DateTime but not ICU +--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/Amsterdam'); + +$intlcal = new IntlGregorianCalendar(); + +$pstdate = new DateTime('2012-01-01 00:00:00 WEST'); +$intlcal->setTimeZone($pstdate->getTimeZone()); +var_dump($intlcal->getTimeZone()->getID()); + +$pstdate = new DateTime('2012-01-01 00:00:00 +24:00'); +$intlcal->setTimeZone($pstdate->getTimeZone()); +var_dump($intlcal->getTimeZone()->getID()); + +--EXPECTF-- + +Warning: IntlCalendar::setTimeZone(): intlcal_set_time_zone: time zone id 'WEST' extracted from ext/date DateTimeZone not recognized in %s on line %d +string(16) "Europe/Amsterdam" + +Warning: IntlCalendar::setTimeZone(): intlcal_set_time_zone: object has an time zone offset that's too large in %s on line %d +string(16) "Europe/Amsterdam" diff --git a/ext/intl/tests/calendar_setTimeZone_variation2.phpt b/ext/intl/tests/calendar_setTimeZone_variation2.phpt new file mode 100644 index 0000000000..26aaf725ab --- /dev/null +++ b/ext/intl/tests/calendar_setTimeZone_variation2.phpt @@ -0,0 +1,30 @@ +--TEST-- +IntlCalendar::setTimeZone(): different ways to specify time zone +--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/Amsterdam'); + +$intlcal = new IntlGregorianCalendar(); +$intlcal->setTimeZone('Europe/Paris'); +var_dump($intlcal->getTimeZone()->getID()); +$intlcal->setTimeZone(new DateTimeZone('Europe/Madrid')); +var_dump($intlcal->getTimeZone()->getID()); + +$pstdate = new DateTime('2012-01-01 00:00:00 PST'); +$intlcal->setTimeZone($pstdate->getTimeZone()); +var_dump($intlcal->getTimeZone()->getID()); + +$offsetdate = new DateTime('2012-01-01 00:00:00 -02:30'); +$intlcal->setTimeZone($offsetdate->getTimeZone()); +var_dump($intlcal->getTimeZone()->getID()); +--EXPECT-- +string(12) "Europe/Paris" +string(13) "Europe/Madrid" +string(3) "PST" +string(8) "GMT-0230" diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp index ad9e6fd839..7032368737 100644 --- a/ext/intl/timezone/timezone_class.cpp +++ b/ext/intl/timezone/timezone_class.cpp @@ -53,10 +53,84 @@ U_CFUNC void timezone_object_construct(const TimeZone *zone, zval *object, int o } /* }}} */ +/* {{{ timezone_convert_datetimezone + * The timezone in DateTime and DateTimeZone is not unified. */ +U_CFUNC TimeZone *timezone_convert_datetimezone(int type, + void *object, + int is_datetime, + intl_error *outside_error, + const char *func TSRMLS_DC) +{ + const char *id = NULL, + offset_id[] = "GMT+00:00"; + int id_len = 0; + char *message; + TimeZone *timeZone; + + switch (type) { + case TIMELIB_ZONETYPE_ID: + id = is_datetime + ? ((php_date_obj*)object)->time->tz_info->name + : ((php_timezone_obj*)object)->tzi.tz->name; + id_len = strlen(id); + break; + case TIMELIB_ZONETYPE_OFFSET: { + int offset_mins = is_datetime + ? -((php_date_obj*)object)->time->z + : -(int)((php_timezone_obj*)object)->tzi.utc_offset, + hours = offset_mins / 60, + minutes = offset_mins - hours * 60; + minutes *= minutes > 0 ? 1 : -1; + + if (offset_mins <= -24 * 60 || offset_mins >= 24 * 60) { + spprintf(&message, 0, "%s: object has an time zone offset " + "that's too large", func); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return NULL; + } + + id = offset_id; + id_len = spprintf((char**)&id, sizeof(offset_id), "GMT%+03d:%02d", + hours, minutes); + break; + } + case TIMELIB_ZONETYPE_ABBR: + id = is_datetime + ? ((php_date_obj*)object)->time->tz_abbr + : ((php_timezone_obj*)object)->tzi.z.abbr; + id_len = strlen(id); + break; + } + + UnicodeString s = UnicodeString(id, id_len, US_INV); + timeZone = TimeZone::createTimeZone(s); +#if U_ICU_VERSION_MAJOR_NUM >= 49 + if (timeZone == TimeZone::getUnknown()) { +#else + UnicodeString resultingId; + timeZone->getID(resultingId); + if (resultingId == UnicodeString("Etc/Unknown", -1, US_INV) + || resultingId == UnicodeString("GMT", -1, US_INV)) { +#endif + spprintf(&message, 0, "%s: time zone id '%s' " + "extracted from ext/date TimeZone not recognized", func, id); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + delete timeZone; + return NULL; + } + return timeZone; +} +/* }}} */ + /* {{{ timezone_process_timezone_argument - * TimeZone argument processor for constructor like functions (sets the global - * error). */ -TimeZone *timezone_process_timezone_argument(zval **zv_timezone, const char *func TSRMLS_DC) + * TimeZone argument processor. outside_error may be NULL (for static functions/constructors) */ +U_CFUNC TimeZone *timezone_process_timezone_argument(zval **zv_timezone, + intl_error *outside_error, + const char *func TSRMLS_DC) { zval local_zv_tz = zval_used_for_init, *local_zv_tz_p = &local_zv_tz; @@ -77,7 +151,7 @@ TimeZone *timezone_process_timezone_argument(zval **zv_timezone, const char *fun spprintf(&message, 0, "%s: passed IntlTimeZone is not " "properly constructed", func); if (message) { - intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); efree(message); } return NULL; @@ -86,22 +160,30 @@ TimeZone *timezone_process_timezone_argument(zval **zv_timezone, const char *fun if (timeZone == NULL) { spprintf(&message, 0, "%s: could not clone TimeZone", func); if (message) { - intl_error_set(NULL, U_MEMORY_ALLOCATION_ERROR, message, 1 TSRMLS_CC); + intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1 TSRMLS_CC); efree(message); } return NULL; } + } else if (Z_TYPE_PP(zv_timezone) == IS_OBJECT && + instanceof_function(Z_OBJCE_PP(zv_timezone), php_date_get_timezone_ce() TSRMLS_CC)) { + + php_timezone_obj *tzobj = (php_timezone_obj *)zend_objects_get_address( + *zv_timezone TSRMLS_CC); + + return timezone_convert_datetimezone(tzobj->type, tzobj, 0, + outside_error, func TSRMLS_CC); } else { UnicodeString id, gottenId; - UErrorCode status = U_ZERO_ERROR; + UErrorCode status = U_ZERO_ERROR; /* outside_error may be NULL */ convert_to_string_ex(zv_timezone); if (intl_stringFromChar(id, Z_STRVAL_PP(zv_timezone), Z_STRLEN_PP(zv_timezone), &status) == FAILURE) { spprintf(&message, 0, "%s: Time zone identifier given is not a " "valid UTF-8 string", func); if (message) { - intl_error_set(NULL, status, message, 1 TSRMLS_CC); + intl_errors_set(outside_error, status, message, 1 TSRMLS_CC); efree(message); } return NULL; @@ -110,7 +192,7 @@ TimeZone *timezone_process_timezone_argument(zval **zv_timezone, const char *fun if (timeZone == NULL) { spprintf(&message, 0, "%s: could not create time zone", func); if (message) { - intl_error_set(NULL, U_MEMORY_ALLOCATION_ERROR, message, 1 TSRMLS_CC); + intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1 TSRMLS_CC); efree(message); } return NULL; @@ -119,7 +201,7 @@ TimeZone *timezone_process_timezone_argument(zval **zv_timezone, const char *fun spprintf(&message, 0, "%s: no such time zone: '%s'", func, Z_STRVAL_PP(zv_timezone)); if (message) { - intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); efree(message); } delete timeZone; diff --git a/ext/intl/timezone/timezone_class.h b/ext/intl/timezone/timezone_class.h index 89d694621f..d5fabb9280 100644 --- a/ext/intl/timezone/timezone_class.h +++ b/ext/intl/timezone/timezone_class.h @@ -59,7 +59,8 @@ typedef struct { RETURN_FALSE; \ } -TimeZone *timezone_process_timezone_argument(zval **zv_timezone, const char *func TSRMLS_DC); +TimeZone *timezone_convert_datetimezone(int type, void *object, int is_datetime, 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); |