]> granicus.if.org Git - php/commitdiff
Accept DateTimeZone where time zones are expected.
authorGustavo André dos Santos Lopes <cataphract@php.net>
Fri, 6 Apr 2012 19:50:08 +0000 (21:50 +0200)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Thu, 17 May 2012 15:23:46 +0000 (17:23 +0200)
Also unified timezone handling in IntlCalendar::setTimeZone()
to that in the IntlCalendar and IntlGregorianCalendar constructors.

ext/intl/calendar/calendar_class.cpp
ext/intl/calendar/calendar_methods.cpp
ext/intl/calendar/gregoriancalendar_methods.cpp
ext/intl/php_intl.c
ext/intl/tests/calendar_setTimeZone_error2.phpt [new file with mode: 0644]
ext/intl/tests/calendar_setTimeZone_variation2.phpt [new file with mode: 0644]
ext/intl/timezone/timezone_class.cpp
ext/intl/timezone/timezone_class.h

index 1a477396ddd08d0b8ba609b52faa9d15488a5f2e..ea5339d836fdb54e4e3688b88cd51081504d2a7e 100644 (file)
@@ -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)
index f8d977c4289d0d7fe68a9ef681d6418c28ff7683..0c6450fce7c057a483b03543a09dc53adc8ffd72 100644 (file)
@@ -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;
        }
 
index 31fb8a8991457c48e34225d5314d7328af85be13..4f26cc59457acf8c6979a6266c9f4ba6d3212f9c 100644 (file)
@@ -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();
index f160f9dda204a32674d284b89cb71fac29684cfd..aca3590e0111b668391467a32bc748419317436a 100755 (executable)
@@ -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 (file)
index 0000000..aa1eaba
--- /dev/null
@@ -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 (file)
index 0000000..26aaf72
--- /dev/null
@@ -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"
index ad9e6fd8397c4f238c8d8497afb694d8c3c99d0f..70323687379e4eb9daa901649df4db95250c7cf9 100644 (file)
@@ -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;
index 89d694621f9bb6c4efd9de4b0583f7ec51288f7e..d5fabb92805999186f8ae35e75c253fb027139ac 100644 (file)
@@ -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);