summaryrefslogtreecommitdiff
path: root/ext/intl
diff options
context:
space:
mode:
authorGustavo André dos Santos Lopes <cataphract@php.net>2012-04-06 21:50:08 +0200
committerGustavo André dos Santos Lopes <cataphract@php.net>2012-05-17 17:23:46 +0200
commit9a35d45a5b2226750e198042201e63a37c127f31 (patch)
tree404d3f5597f6edc32e3e6ef2b6c86ace6c068fb5 /ext/intl
parent51e3e51d3b574519869bf21d0136b25f48ca7a99 (diff)
downloadphp-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.cpp4
-rw-r--r--ext/intl/calendar/calendar_methods.cpp22
-rw-r--r--ext/intl/calendar/gregoriancalendar_methods.cpp2
-rwxr-xr-xext/intl/php_intl.c2
-rw-r--r--ext/intl/tests/calendar_setTimeZone_error2.phpt29
-rw-r--r--ext/intl/tests/calendar_setTimeZone_variation2.phpt30
-rw-r--r--ext/intl/timezone/timezone_class.cpp100
-rw-r--r--ext/intl/timezone/timezone_class.h3
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);