diff options
-rw-r--r-- | ext/intl/calendar/calendar_methods.cpp | 3 | ||||
-rw-r--r-- | ext/intl/common/common_date.cpp | 250 | ||||
-rw-r--r-- | ext/intl/common/common_date.h | 40 | ||||
-rwxr-xr-x | ext/intl/config.m4 | 2 | ||||
-rwxr-xr-x | ext/intl/config.w32 | 2 | ||||
-rwxr-xr-x | ext/intl/dateformat/dateformat_class.c | 8 | ||||
-rwxr-xr-x | ext/intl/dateformat/dateformat_format.c | 177 | ||||
-rw-r--r-- | ext/intl/dateformat/dateformat_format_object.cpp | 230 | ||||
-rw-r--r-- | ext/intl/dateformat/dateformat_format_object.h | 19 | ||||
-rwxr-xr-x | ext/intl/msgformat/msgformat_helpers.cpp | 76 | ||||
-rwxr-xr-x | ext/intl/php_intl.c | 9 | ||||
-rwxr-xr-x | ext/intl/tests/dateformat_format.phpt | 10 | ||||
-rw-r--r-- | ext/intl/tests/dateformat_formatObject_calendar.phpt | 41 | ||||
-rw-r--r-- | ext/intl/tests/dateformat_formatObject_datetime.phpt | 34 | ||||
-rw-r--r-- | ext/intl/tests/dateformat_formatObject_error.phpt | 74 | ||||
-rw-r--r-- | ext/intl/tests/msgfmt_format_error5.phpt | 1 | ||||
-rw-r--r-- | ext/intl/timezone/timezone_class.cpp | 75 | ||||
-rw-r--r-- | ext/intl/timezone/timezone_class.h | 1 | ||||
-rw-r--r-- | ext/intl/timezone/timezone_methods.cpp | 3 |
19 files changed, 810 insertions, 245 deletions
diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp index 539b11a1f7..f2758fdcc8 100644 --- a/ext/intl/calendar/calendar_methods.cpp +++ b/ext/intl/calendar/calendar_methods.cpp @@ -23,7 +23,10 @@ #include <unicode/locid.h> #include <unicode/calendar.h> #include <unicode/ustring.h> + #include "../intl_convertcpp.h" +#include "../common/common_date.h" + extern "C" { #include "../php_intl.h" #define USE_TIMEZONE_POINTER 1 diff --git a/ext/intl/common/common_date.cpp b/ext/intl/common/common_date.cpp new file mode 100644 index 0000000000..ee998818d9 --- /dev/null +++ b/ext/intl/common/common_date.cpp @@ -0,0 +1,250 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gustavo Lopes <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "../intl_cppshims.h" + +#include <unicode/calendar.h> + +extern "C" { +#include "../php_intl.h" +#define USE_CALENDAR_POINTER 1 +#include "../calendar/calendar_class.h" +#include <ext/date/php_date.h> +} + +#ifndef INFINITY +#define INFINITY (DBL_MAX+DBL_MAX) +#endif + +#ifndef NAN +#define NAN (INFINITY-INFINITY) +#endif + +/* {{{ 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) +{ + 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 = slprintf(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 DateTimeZone 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; +} +/* }}} */ + +U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz, + intl_error *err, const char *func TSRMLS_DC) +{ + zval retval; + zval *zfuncname; + char *message; + + if (err && U_FAILURE(err->code)) { + return FAILURE; + } + + if (millis) { + *millis = NAN; + } + if (tz) { + *tz = NULL; + } + + if (millis) { + INIT_ZVAL(retval); + MAKE_STD_ZVAL(zfuncname); + ZVAL_STRING(zfuncname, "getTimestamp", 1); + if (call_user_function(NULL, &(z), zfuncname, &retval, 0, NULL TSRMLS_CC) + != SUCCESS || Z_TYPE(retval) != IS_LONG) { + spprintf(&message, 0, "%s: error calling ::getTimeStamp() on the " + "object", func); + intl_errors_set(err, U_INTERNAL_PROGRAM_ERROR, + message, 1 TSRMLS_CC); + efree(message); + zval_ptr_dtor(&zfuncname); + return FAILURE; + } + + *millis = U_MILLIS_PER_SECOND * (double)Z_LVAL(retval); + zval_ptr_dtor(&zfuncname); + } + + if (tz) { + php_date_obj *datetime; + datetime = (php_date_obj*)zend_object_store_get_object(z TSRMLS_CC); + if (!datetime->time) { + spprintf(&message, 0, "%s: the DateTime object is not properly " + "initialized", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return FAILURE; + } + if (!datetime->time->is_localtime) { + *tz = TimeZone::getGMT()->clone(); + } else { + *tz = timezone_convert_datetimezone(datetime->time->zone_type, + datetime, 1, NULL, func TSRMLS_CC); + if (*tz == NULL) { + spprintf(&message, 0, "%s: could not convert DateTime's " + "time zone", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return FAILURE; + } + } + } + + return SUCCESS; +} + +U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC) +{ + double rv = NAN; + long lv; + int type; + char *message; + + if (err && U_FAILURE(err->code)) { + return NAN; + } + + switch (Z_TYPE_P(z)) { + case IS_STRING: + type = is_numeric_string(Z_STRVAL_P(z), Z_STRLEN_P(z), &lv, &rv, 0); + if (type == IS_DOUBLE) { + rv *= U_MILLIS_PER_SECOND; + } else if (type == IS_LONG) { + rv = U_MILLIS_PER_SECOND * (double)lv; + } else { + spprintf(&message, 0, "%s: string '%s' is not numeric, " + "which would be required for it to be a valid date", func, + Z_STRVAL_P(z)); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + } + break; + case IS_LONG: + rv = U_MILLIS_PER_SECOND * (double)Z_LVAL_P(z); + break; + case IS_DOUBLE: + rv = U_MILLIS_PER_SECOND * Z_DVAL_P(z); + break; + case IS_OBJECT: + if (instanceof_function(Z_OBJCE_P(z), php_date_get_date_ce() TSRMLS_CC)) { + intl_datetime_decompose(z, &rv, NULL, err, func TSRMLS_CC); + } else if (instanceof_function(Z_OBJCE_P(z), Calendar_ce_ptr TSRMLS_CC)) { + Calendar_object *co = (Calendar_object *) + zend_object_store_get_object(z TSRMLS_CC ); + if (co->ucal == NULL) { + spprintf(&message, 0, "%s: IntlCalendar object is not properly " + "constructed", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + } else { + UErrorCode status = UErrorCode(); + rv = (double)co->ucal->getTime(status); + if (U_FAILURE(status)) { + spprintf(&message, 0, "%s: call to internal " + "Calendar::getTime() has failed", func); + intl_errors_set(err, status, message, 1 TSRMLS_CC); + efree(message); + } + } + } else { + /* TODO: try with cast(), get() to obtain a number */ + spprintf(&message, 0, "%s: invalid object type for date/time " + "(only IntlCalendar and DateTime permitted)", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + } + break; + default: + spprintf(&message, 0, "%s: invalid PHP type for date", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + break; + } + + return rv; +} + diff --git a/ext/intl/common/common_date.h b/ext/intl/common/common_date.h new file mode 100644 index 0000000000..d2396cbf5a --- /dev/null +++ b/ext/intl/common/common_date.h @@ -0,0 +1,40 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gustavo Lopes <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef COMMON_DATE_H +#define COMMON_DATE_H + +#include <unicode/umachine.h> + +U_CDECL_BEGIN +#include <php.h> +#include "../intl_error.h" +U_CDECL_END + +#ifdef __cplusplus + +#include <unicode/timezone.h> + +U_CFUNC TimeZone *timezone_convert_datetimezone(int type, void *object, int is_datetime, intl_error *outside_error, const char *func TSRMLS_DC); +U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz, + intl_error *err, const char *func TSRMLS_DC); + +#endif + +U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC); + +#endif /* COMMON_DATE_H */ + diff --git a/ext/intl/config.m4 b/ext/intl/config.m4 index d7eacbc0b4..7c95c130f2 100755 --- a/ext/intl/config.m4 +++ b/ext/intl/config.m4 @@ -33,6 +33,7 @@ if test "$PHP_INTL" != "no"; then collator/collator_error.c \ common/common_error.c \ common/common_enum.cpp \ + common/common_date.cpp \ formatter/formatter.c \ formatter/formatter_main.c \ formatter/formatter_class.c \ @@ -51,6 +52,7 @@ if test "$PHP_INTL" != "no"; then dateformat/dateformat_attr.c \ dateformat/dateformat_data.c \ dateformat/dateformat_format.c \ + dateformat/dateformat_format_object.cpp \ dateformat/dateformat_parse.c \ dateformat/dateformat_create.cpp \ dateformat/dateformat_attrcpp.cpp \ diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index a223505f8c..a49918794c 100755 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -24,6 +24,7 @@ if (PHP_INTL != "no") { ADD_SOURCES(configure_module_dirname + "/common", "\ common_error.c \ common_enum.cpp \ + common_date.cpp \ ", "intl"); ADD_SOURCES(configure_module_dirname + "/formatter", "\ formatter.c \ @@ -61,6 +62,7 @@ if (PHP_INTL != "no") { dateformat_class.c \ dateformat_attr.c \ dateformat_format.c \ + dateformat_format_object.cpp \ dateformat_parse.c \ dateformat_data.c \ dateformat_attrcpp.cpp \ diff --git a/ext/intl/dateformat/dateformat_class.c b/ext/intl/dateformat/dateformat_class.c index d250f75e80..fc4a8b8eb1 100755 --- a/ext/intl/dateformat/dateformat_class.c +++ b/ext/intl/dateformat/dateformat_class.c @@ -19,6 +19,7 @@ #include "php_intl.h" #include "dateformat_data.h" #include "dateformat_format.h" +#include "dateformat_format_object.h" #include "dateformat_parse.h" #include "dateformat.h" #include "dateformat_attr.h" @@ -121,6 +122,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_intldateformatter_format, 0, 0, 0) ZEND_ARG_INFO(0, array) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_intldateformatter_format_object, 0, 0, 1) + ZEND_ARG_INFO(0, object) + ZEND_ARG_INFO(0, format) + ZEND_ARG_INFO(0, locale) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO(arginfo_intldateformatter_getdatetype, 0) ZEND_END_ARG_INFO() @@ -171,6 +178,7 @@ static zend_function_entry IntlDateFormatter_class_functions[] = { PHP_NAMED_FE( setLenient, ZEND_FN( datefmt_set_lenient ), arginfo_intldateformatter_setlenient ) PHP_NAMED_FE( isLenient, ZEND_FN( datefmt_is_lenient ), arginfo_intldateformatter_getdatetype ) PHP_NAMED_FE( format, ZEND_FN( datefmt_format ), arginfo_intldateformatter_format ) + PHP_ME_MAPPING( formatObject, datefmt_format_object, arginfo_intldateformatter_format_object, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_NAMED_FE( parse, ZEND_FN( datefmt_parse), datefmt_parse_args ) PHP_NAMED_FE( localtime, ZEND_FN( datefmt_localtime ), datefmt_parse_args ) PHP_NAMED_FE( getErrorCode, ZEND_FN( datefmt_get_error_code ), arginfo_intldateformatter_getdatetype ) diff --git a/ext/intl/dateformat/dateformat_format.c b/ext/intl/dateformat/dateformat_format.c index 82f825f140..d5a17f91cd 100755 --- a/ext/intl/dateformat/dateformat_format.c +++ b/ext/intl/dateformat/dateformat_format.c @@ -21,15 +21,13 @@ #include <unicode/ustring.h> #include <unicode/ucal.h> -#include "php_intl.h" -#include "intl_convert.h" +#include "../php_intl.h" +#include "../intl_convert.h" +#include "../common/common_date.h" #include "dateformat.h" #include "dateformat_class.h" #include "dateformat_format.h" #include "dateformat_data.h" -/* avoid redefinition of int8_t, already defined in unicode/pwin32.h */ -#define _MSC_STDINT_H_ 1 -#include "ext/date/php_date.h" /* {{{ * Internal function which calls the udat_format @@ -61,20 +59,38 @@ static void internal_format(IntlDateFormatter_object *dfo, UDate timestamp, zval /* {{{ * Internal function which fetches an element from the passed array for the key_name passed */ -static double internal_get_arr_ele(IntlDateFormatter_object *dfo, HashTable* hash_arr, char* key_name TSRMLS_DC) +static int32_t internal_get_arr_ele(IntlDateFormatter_object *dfo, + HashTable* hash_arr, char* key_name, intl_error *err TSRMLS_DC) { - zval** ele_value = NULL; - UDate result = -1; - - if( zend_hash_find( hash_arr, key_name, strlen(key_name) + 1, (void **)&ele_value ) == SUCCESS ){ - if( Z_TYPE_PP(ele_value)!= IS_LONG ){ - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_format: parameter array does not contain a long element.", 0 TSRMLS_CC ); - }else{ - result = Z_LVAL_PP(ele_value); + zval **ele_value = NULL; + int32_t result = 0; + char *message; + + if (U_FAILURE(err->code)) { + return result; + } + + if (zend_hash_find(hash_arr, key_name, strlen(key_name) + 1, + (void **)&ele_value) == SUCCESS) { + if(Z_TYPE_PP(ele_value) != IS_LONG) { + spprintf(&message, 0, "datefmt_format: parameter array contains " + "a non-integer element for key '%s'", key_name); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + } else { + if (Z_LVAL_PP(ele_value) > INT32_MAX || + Z_LVAL_PP(ele_value) < INT32_MIN) { + spprintf(&message, 0, "datefmt_format: value %ld is out of " + "bounds for a 32-bit integer in key '%s'", + Z_LVAL_PP(ele_value), key_name); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, message, 1 TSRMLS_CC); + efree(message); + } else { + result = Z_LVAL_PP(ele_value); + } } } - /* printf("\n Inside internal_get_arr_ele key_name= %s, result = %g \n", key_name, result); */ + return result; } /* }}} */ @@ -82,41 +98,49 @@ static double internal_get_arr_ele(IntlDateFormatter_object *dfo, HashTable* has /* {{{ * Internal function which sets UCalendar from the passed array and retrieves timestamp */ -static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, HashTable* hash_arr TSRMLS_DC) +static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, + HashTable *hash_arr TSRMLS_DC) { - long year =0; - long month =0; - long hour =0; - long minute =0; - long second =0; - long wday =0; - long yday =0; - long mday =0; - UBool isInDST = FALSE; - const UCalendar *pcal; + int32_t year, + month, + hour, + minute, + second, + mday; + UCalendar *pcal; + intl_error *err = &dfo->datef_data.error; + +#define INTL_GET_ELEM(elem) \ + internal_get_arr_ele(dfo, hash_arr, (elem), err TSRMLS_CC) /* Fetch values from the incoming array */ - year = internal_get_arr_ele( dfo, hash_arr, CALENDAR_YEAR TSRMLS_CC) + 1900; /* tm_year is years since 1900 */ + year = INTL_GET_ELEM(CALENDAR_YEAR) + 1900; /* tm_year is years since 1900 */ /* Month in ICU and PHP starts from January =0 */ - month = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MON TSRMLS_CC); - hour = internal_get_arr_ele( dfo, hash_arr, CALENDAR_HOUR TSRMLS_CC); - minute = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MIN TSRMLS_CC); - second = internal_get_arr_ele( dfo, hash_arr, CALENDAR_SEC TSRMLS_CC); - wday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_WDAY TSRMLS_CC); - yday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_YDAY TSRMLS_CC); - isInDST = internal_get_arr_ele( dfo, hash_arr, CALENDAR_ISDST TSRMLS_CC); + month = INTL_GET_ELEM(CALENDAR_MON); + hour = INTL_GET_ELEM(CALENDAR_HOUR); + minute = INTL_GET_ELEM(CALENDAR_MIN); + second = INTL_GET_ELEM(CALENDAR_SEC); /* For the ucal_setDateTime() function, this is the 'date' value */ - mday = internal_get_arr_ele( dfo, hash_arr, CALENDAR_MDAY TSRMLS_CC); + mday = INTL_GET_ELEM(CALENDAR_MDAY); - pcal = udat_getCalendar(DATE_FORMAT_OBJECT(dfo)); - /* set the incoming values for the calendar */ - ucal_setDateTime( pcal, year, month, mday, hour, minute, second, &INTL_DATA_ERROR_CODE(dfo)); - if( INTL_DATA_ERROR_CODE(dfo) != U_ZERO_ERROR){ +#undef INTL_GET_ELEM + + pcal = ucal_clone(udat_getCalendar(DATE_FORMAT_OBJECT(dfo)), + &INTL_DATA_ERROR_CODE(dfo)); + + if (INTL_DATA_ERROR_CODE(dfo) != U_ZERO_ERROR) { + intl_errors_set(err, INTL_DATA_ERROR_CODE(dfo), "datefmt_format: " + "error cloning calendar", 0 TSRMLS_CC); return 0; } + + /* set the incoming values for the calendar */ + ucal_setDateTime(pcal, year, month, mday, hour, minute, second, &INTL_DATA_ERROR_CODE(dfo)); + /* actually, ucal_setDateTime cannot fail */ /* Fetch the timestamp from the UCalendar */ - return ucal_getMillis(pcal, &INTL_DATA_ERROR_CODE(dfo) ); + return ucal_getMillis(pcal, &INTL_DATA_ERROR_CODE(dfo)); + udat_close(pcal); } @@ -126,70 +150,39 @@ static UDate internal_get_timestamp(IntlDateFormatter_object *dfo, HashTable* ha * Format the time value as a string. }}}*/ PHP_FUNCTION(datefmt_format) { - UDate timestamp =0; - UDate p_timestamp =0; - HashTable* hash_arr = NULL; - zval* zarg = NULL; + UDate timestamp = 0; + HashTable *hash_arr = NULL; + zval *zarg = NULL; DATE_FORMAT_METHOD_INIT_VARS; /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", &object, IntlDateFormatter_ce_ptr,&zarg ) == FAILURE ) - { - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: unable to parse input params", 0 TSRMLS_CC ); + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", + &object, IntlDateFormatter_ce_ptr, &zarg) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: unable " + "to parse input params", 0 TSRMLS_CC ); RETURN_FALSE; } - /* Fetch the object. */ DATE_FORMAT_METHOD_FETCH_OBJECT; - switch(Z_TYPE_P(zarg) ){ - case IS_LONG: - p_timestamp = Z_LVAL_P(zarg) ; - timestamp = p_timestamp * 1000; - break; - case IS_DOUBLE: - /* timestamp*1000 since ICU expects it in milliseconds */ - p_timestamp = Z_DVAL_P(zarg) ; - timestamp = p_timestamp * 1000; - break; - case IS_ARRAY: - hash_arr = Z_ARRVAL_P(zarg); - if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) - RETURN_FALSE; - - timestamp = internal_get_timestamp(dfo, hash_arr TSRMLS_CC); - INTL_METHOD_CHECK_STATUS( dfo, "datefmt_format: Date formatting failed" ) - break; - case IS_OBJECT: { - zend_class_entry *date_ce = php_date_get_date_ce(); - zval retval; - zval *zfuncname; - if(!instanceof_function(Z_OBJCE_P(zarg), date_ce TSRMLS_CC)) { - intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: object must be an instance of DateTime", 0 TSRMLS_CC ); - RETURN_FALSE; - } - INIT_ZVAL(retval); - MAKE_STD_ZVAL(zfuncname); - ZVAL_STRING(zfuncname, "getTimestamp", 1); - if(call_user_function(NULL, &zarg, zfuncname, &retval, 0, NULL TSRMLS_CC) != SUCCESS || Z_TYPE(retval) != IS_LONG) { - intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format: cannot get timestamp", 0 TSRMLS_CC ); - zval_ptr_dtor(&zfuncname); - RETURN_FALSE; - } - zval_ptr_dtor(&zfuncname); - p_timestamp = Z_LVAL(retval); - timestamp = p_timestamp*1000; + if (Z_TYPE_P(zarg) == IS_ARRAY) { + hash_arr = Z_ARRVAL_P(zarg); + if (!hash_arr || zend_hash_num_elements(hash_arr) == 0) { + RETURN_FALSE; } - break; - default: - intl_errors_set( INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, - "datefmt_format: takes either an array or an integer timestamp value or a DateTime object", 0 TSRMLS_CC ); + + timestamp = internal_get_timestamp(dfo, hash_arr TSRMLS_CC); + INTL_METHOD_CHECK_STATUS(dfo, "datefmt_format: date formatting failed") + } else { + timestamp = intl_zval_to_millis(zarg, INTL_DATA_ERROR_P(dfo), + "datefmt_format" TSRMLS_CC); + if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { RETURN_FALSE; + } } - - internal_format( dfo, timestamp, return_value TSRMLS_CC); + internal_format( dfo, timestamp, return_value TSRMLS_CC); } /* }}} */ diff --git a/ext/intl/dateformat/dateformat_format_object.cpp b/ext/intl/dateformat/dateformat_format_object.cpp new file mode 100644 index 0000000000..e8981faa26 --- /dev/null +++ b/ext/intl/dateformat/dateformat_format_object.cpp @@ -0,0 +1,230 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gustavo Lopes <cataphract@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "../intl_cppshims.h" + +#include <unicode/calendar.h> +#include <unicode/gregocal.h> +#include <unicode/datefmt.h> +#include <unicode/smpdtfmt.h> +#include <unicode/locid.h> + +#include "../intl_convertcpp.h" + +extern "C" { +#include "../php_intl.h" +#include "../locale/locale.h" +#define USE_CALENDAR_POINTER 1 +#include "../calendar/calendar_class.h" +#include <ext/date/php_date.h> +#include "../common/common_date.h" +} + +static const DateFormat::EStyle valid_styles[] = { + DateFormat::kNone, + DateFormat::kFull, + DateFormat::kLong, + DateFormat::kMedium, + DateFormat::kShort, + DateFormat::kFullRelative, + DateFormat::kLongRelative, + DateFormat::kMediumRelative, + DateFormat::kShortRelative, +}; + +static bool valid_format(zval **z) { + if (Z_TYPE_PP(z) == IS_LONG) { + long lval = Z_LVAL_PP(z); + for (int i = 0; i < sizeof(valid_styles) / sizeof(*valid_styles); i++) { + if ((long)valid_styles[i] == lval) { + return true; + } + } + } + + return false; +} + +U_CFUNC PHP_FUNCTION(datefmt_format_object) +{ + zval *object, + **format = NULL; + const char *locale_str = NULL; + int locale_len; + bool pattern = false; + UDate date; + TimeZone *timeZone = NULL; + UErrorCode status = U_ZERO_ERROR; + DateFormat *df = NULL; + Calendar *cal = NULL; + DateFormat::EStyle dateStyle = DateFormat::kDefault, + timeStyle = DateFormat::kDefault; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|Zs!", + &object, &format, &locale_str, &locale_len) == FAILURE) { + RETURN_FALSE; + } + + if (!locale_str) { + locale_str = intl_locale_get_default(TSRMLS_C); + } + + if (format == NULL || Z_TYPE_PP(format) == IS_NULL) { + //nothing + } else if (Z_TYPE_PP(format) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_PP(format); + HashPosition pos = {0}; + zval **z; + if (zend_hash_num_elements(ht) != 2) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: bad format; if array, it must have " + "two elements", 0 TSRMLS_CC); + RETURN_FALSE; + } + + zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void**)&z, &pos); + if (!valid_format(z)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: bad format; the date format (first " + "element of the array) is not valid", 0 TSRMLS_CC); + RETURN_FALSE; + } + dateStyle = (DateFormat::EStyle)Z_LVAL_PP(z); + + zend_hash_move_forward_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void**)&z, &pos); + if (!valid_format(z)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: bad format; the time format (" + "second element of the array) is not valid", 0 TSRMLS_CC); + RETURN_FALSE; + } + timeStyle = (DateFormat::EStyle)Z_LVAL_PP(z); + } else if (Z_TYPE_PP(format) == IS_LONG) { + if (!valid_format(format)) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: the date/time format type is invalid", + 0 TSRMLS_CC); + RETURN_FALSE; + } + dateStyle = timeStyle = (DateFormat::EStyle)Z_LVAL_PP(format); + } else { + convert_to_string_ex(format); + if (Z_STRLEN_PP(format) == 0) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: the format is empty", 0 TSRMLS_CC); + RETURN_FALSE; + } + pattern = true; + } + + //there's no support for relative time in ICU yet + timeStyle = (DateFormat::EStyle)(timeStyle & ~DateFormat::kRelative); + + zend_class_entry *instance_ce = Z_OBJCE_P(object); + if (instanceof_function(instance_ce, Calendar_ce_ptr TSRMLS_CC)) { + Calendar *obj_cal = calendar_fetch_native_calendar(object TSRMLS_CC); + if (obj_cal == NULL) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format_object: bad IntlCalendar instance: " + "not initialized properly", 0 TSRMLS_CC); + RETURN_FALSE; + } + timeZone = obj_cal->getTimeZone().clone(); + date = obj_cal->getTime(status); + if (U_FAILURE(status)) { + intl_error_set(NULL, status, + "datefmt_format_object: error obtaining instant from " + "IntlCalendar", 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + cal = obj_cal->clone(); + } else if (instanceof_function(instance_ce, php_date_get_date_ce() TSRMLS_CC)) { + if (intl_datetime_decompose(object, &date, &timeZone, NULL, + "datefmt_format_object" TSRMLS_CC) == FAILURE) { + RETURN_FALSE; + } + cal = new GregorianCalendar(Locale::createFromName(locale_str), status); + if (U_FAILURE(status)) { + intl_error_set(NULL, status, + "datefmt_format_object: could not create GregorianCalendar", + 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + } else { + intl_error_set(NULL, status, "datefmt_format_object: the passed object " + "must be an instance of either IntlCalendar or DateTime", + 0 TSRMLS_CC); + RETURN_FALSE; + } + + if (pattern) { + df = new SimpleDateFormat( + UnicodeString(Z_STRVAL_PP(format), Z_STRLEN_PP(format), + UnicodeString::kInvariant), + Locale::createFromName(locale_str), + status); + + if (U_FAILURE(status)) { + intl_error_set(NULL, status, + "datefmt_format_object: could not create SimpleDateFormat", + 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + } else { + df = DateFormat::createDateTimeInstance(dateStyle, timeStyle, + Locale::createFromName(locale_str)); + + if (df == NULL) { /* according to ICU sources, this should never happen */ + intl_error_set(NULL, status, + "datefmt_format_object: could not create DateFormat", + 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + } + + //must be in this order (or have the cal adopt the tz) + df->adoptCalendar(cal); + cal = NULL; + df->adoptTimeZone(timeZone); + timeZone = NULL; + + { + UnicodeString result = UnicodeString(); + df->format(date, result); + + Z_TYPE_P(return_value) = IS_STRING; + if (intl_charFromString(result, &Z_STRVAL_P(return_value), + &Z_STRLEN_P(return_value), &status) == FAILURE) { + intl_error_set(NULL, status, + "datefmt_format_object: error converting result to UTF-8", + 0 TSRMLS_CC); + RETVAL_FALSE; + goto cleanup; + } + } + + +cleanup: + delete df; + delete timeZone; + delete cal; +} diff --git a/ext/intl/dateformat/dateformat_format_object.h b/ext/intl/dateformat/dateformat_format_object.h new file mode 100644 index 0000000000..d80ea87e0f --- /dev/null +++ b/ext/intl/dateformat/dateformat_format_object.h @@ -0,0 +1,19 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gustavo Lopes <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#include <php.h> + +PHP_FUNCTION(datefmt_format_object); diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index fd8df1a39c..9ee1cdcfb0 100755 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -31,6 +31,7 @@ #include <vector> #include "../intl_convertcpp.h" +#include "../common/common_date.h" extern "C" { #include "php_intl.h" @@ -38,23 +39,10 @@ extern "C" { #include "msgformat_format.h" #include "msgformat_helpers.h" #include "intl_convert.h" -#define USE_CALENDAR_POINTER 1 -#include "../calendar/calendar_class.h" -/* avoid redefinition of int8_t, already defined in unicode/pwin32.h */ -#define _MSC_STDINT_H_ 1 -#include "ext/date/php_date.h" #define USE_TIMEZONE_POINTER #include "../timezone/timezone_class.h" } -#ifndef INFINITY -#define INFINITY (DBL_MAX+DBL_MAX) -#endif - -#ifndef NAN -#define NAN (INFINITY-INFINITY) -#endif - #if U_ICU_VERSION_MAJOR_NUM * 10 + U_ICU_VERSION_MINOR_NUM >= 48 #define HAS_MESSAGE_PATTERN 1 #endif @@ -95,66 +83,6 @@ U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt) return fmt_count; } -static double umsg_helper_zval_to_millis(zval *z, UErrorCode *status TSRMLS_DC) { - double rv = NAN; - long lv; - int type; - - if (U_FAILURE(*status)) { - return NAN; - } - - switch (Z_TYPE_P(z)) { - case IS_STRING: - type = is_numeric_string(Z_STRVAL_P(z), Z_STRLEN_P(z), &lv, &rv, 0); - if (type == IS_DOUBLE) { - rv *= U_MILLIS_PER_SECOND; - } else if (type == IS_LONG) { - rv = U_MILLIS_PER_SECOND * (double)lv; - } else { - *status = U_ILLEGAL_ARGUMENT_ERROR; - } - break; - case IS_LONG: - rv = U_MILLIS_PER_SECOND * (double)Z_LVAL_P(z); - break; - case IS_DOUBLE: - rv = U_MILLIS_PER_SECOND * Z_DVAL_P(z); - break; - case IS_OBJECT: - if (instanceof_function(Z_OBJCE_P(z), php_date_get_date_ce() TSRMLS_CC)) { - zval retval; - zval *zfuncname; - INIT_ZVAL(retval); - MAKE_STD_ZVAL(zfuncname); - ZVAL_STRING(zfuncname, "getTimestamp", 1); - if (call_user_function(NULL, &(z), zfuncname, &retval, 0, NULL TSRMLS_CC) - != SUCCESS || Z_TYPE(retval) != IS_LONG) { - *status = U_INTERNAL_PROGRAM_ERROR; - } else { - rv = U_MILLIS_PER_SECOND * (double)Z_LVAL(retval); - } - zval_ptr_dtor(&zfuncname); - } else if (instanceof_function(Z_OBJCE_P(z), Calendar_ce_ptr TSRMLS_CC)) { - Calendar_object *co = (Calendar_object *) - zend_object_store_get_object(z TSRMLS_CC ); - if (co->ucal == NULL) { - *status = U_ILLEGAL_ARGUMENT_ERROR; - } else { - rv = (double)co->ucal->getTime(*status); - } - } else { - /* TODO: try with cast(), get() to obtain a number */ - *status = U_ILLEGAL_ARGUMENT_ERROR; - } - break; - default: - *status = U_ILLEGAL_ARGUMENT_ERROR; - } - - return rv; -} - static HashTable *umsg_get_numeric_types(MessageFormatter_object *mfo, intl_error& err TSRMLS_DC) { @@ -613,7 +541,7 @@ retry_kint64: } case Formattable::kDate: { - double dd = umsg_helper_zval_to_millis(*elem, &err.code TSRMLS_CC); + double dd = intl_zval_to_millis(*elem, &err, "msgfmt_format" TSRMLS_CC); if (U_FAILURE(err.code)) { char *message, *key_char; int key_len; diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c index 19896a7108..d7ed9dc6e5 100755 --- a/ext/intl/php_intl.c +++ b/ext/intl/php_intl.c @@ -62,6 +62,7 @@ #include "dateformat/dateformat_attr.h" #include "dateformat/dateformat_attrcpp.h" #include "dateformat/dateformat_format.h" +#include "dateformat/dateformat_format_object.h" #include "dateformat/dateformat_parse.h" #include "dateformat/dateformat_data.h" @@ -350,6 +351,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_format, 0, 0, 0) ZEND_ARG_INFO(0, array) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_format_object, 0, 0, 1) + ZEND_ARG_INFO(0, object) + ZEND_ARG_INFO(0, format) + ZEND_ARG_INFO(0, locale) +ZEND_END_ARG_INFO() + + ZEND_BEGIN_ARG_INFO_EX(arginfo_datefmt_create, 0, 0, 3) ZEND_ARG_INFO(0, locale) ZEND_ARG_INFO(0, date_type) @@ -706,6 +714,7 @@ zend_function_entry intl_functions[] = { PHP_FE( datefmt_is_lenient, arginfo_msgfmt_get_locale ) PHP_FE( datefmt_set_lenient, arginfo_msgfmt_get_locale ) PHP_FE( datefmt_format, arginfo_datefmt_format ) + PHP_FE( datefmt_format_object, arginfo_datefmt_format_object ) PHP_FE( datefmt_parse, datefmt_parse_args ) PHP_FE( datefmt_localtime , datefmt_parse_args ) PHP_FE( datefmt_get_error_code, arginfo_msgfmt_get_error_code ) diff --git a/ext/intl/tests/dateformat_format.phpt b/ext/intl/tests/dateformat_format.phpt index 98f9d34c03..8664eea319 100755 --- a/ext/intl/tests/dateformat_format.phpt +++ b/ext/intl/tests/dateformat_format.phpt @@ -399,24 +399,24 @@ Formatted DateTime is : 20001230 05:04 PM Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' ------------ Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' ------------ Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' ------------ Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' ------------ Date is: stdClass::__set_state(array( )) ------------ -Error while formatting as: 'datefmt_format: object must be an instance of DateTime: U_ILLEGAL_ARGUMENT_ERROR' +Error while formatting as: 'datefmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted): U_ILLEGAL_ARGUMENT_ERROR' diff --git a/ext/intl/tests/dateformat_formatObject_calendar.phpt b/ext/intl/tests/dateformat_formatObject_calendar.phpt new file mode 100644 index 0000000000..03371a91ab --- /dev/null +++ b/ext/intl/tests/dateformat_formatObject_calendar.phpt @@ -0,0 +1,41 @@ +--TEST--
+IntlDateFormatter::formatObject(): IntlCalendar tests
+--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", "pt_PT"); +ini_set("date.timezone", "Europe/Lisbon"); + +$cal = IntlCalendar::fromDateTime('2012-01-01 00:00:00'); //Europe/Lisbon +echo IntlDateFormatter::formatObject($cal), "\n"; +echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL), "\n"; +echo IntlDateFormatter::formatObject($cal, null, "en-US"), "\n"; +echo IntlDateFormatter::formatObject($cal, array(IntlDateFormatter::SHORT, IntlDateFormatter::FULL), "en-US"), "\n"; +echo IntlDateFormatter::formatObject($cal, 'E y-MM-d HH,mm,ss.SSS v', "en-US"), "\n"; + +$cal = IntlCalendar::fromDateTime('2012-01-01 05:00:00+03:00'); +echo datefmt_format_object($cal, IntlDateFormatter::FULL), "\n"; + +$cal = IntlCalendar::createInstance(null,'en-US@calendar=islamic-civil'); +$cal->setTime(strtotime('2012-01-01 00:00:00')*1000.); +echo IntlDateFormatter::formatObject($cal), "\n"; +echo IntlDateFormatter::formatObject($cal, IntlDateFormatter::FULL, "en-US"), "\n"; + +?> +==DONE== +
+--EXPECT--
+01/01/2012 00:00:00 +Domingo, 1 de Janeiro de 2012 0:00:00 Hora Padrão da Europa Ocidental +Jan 1, 2012 12:00:00 AM +1/1/12 12:00:00 AM Western European Standard Time +Sun 2012-01-1 00,00,00.000 Portugal Time (Lisbon) +Domingo, 1 de Janeiro de 2012 5:00:00 GMT+03:00 +06/02/1433 00:00:00 +Sunday, Safar 6, 1433 12:00:00 AM Western European Standard Time +==DONE== +
diff --git a/ext/intl/tests/dateformat_formatObject_datetime.phpt b/ext/intl/tests/dateformat_formatObject_datetime.phpt new file mode 100644 index 0000000000..bfc26cb80c --- /dev/null +++ b/ext/intl/tests/dateformat_formatObject_datetime.phpt @@ -0,0 +1,34 @@ +--TEST--
+IntlDateFormatter::formatObject(): DateTime tests
+--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", "pt_PT"); +ini_set("date.timezone", "Europe/Lisbon"); + +$dt = new DateTime('2012-01-01 00:00:00'); //Europe/Lisbon +echo IntlDateFormatter::formatObject($dt), "\n"; +echo IntlDateFormatter::formatObject($dt, IntlDateFormatter::FULL), "\n"; +echo IntlDateFormatter::formatObject($dt, null, "en-US"), "\n"; +echo IntlDateFormatter::formatObject($dt, array(IntlDateFormatter::SHORT, IntlDateFormatter::FULL), "en-US"), "\n"; +echo IntlDateFormatter::formatObject($dt, 'E y-MM-d HH,mm,ss.SSS v', "en-US"), "\n"; + +$dt = new DateTime('2012-01-01 05:00:00+03:00'); +echo IntlDateFormatter::formatObject($dt, IntlDateFormatter::FULL), "\n"; + +?> +==DONE== +
+--EXPECT--
+01/01/2012 00:00:00 +Domingo, 1 de Janeiro de 2012 0:00:00 Hora Padrão da Europa Ocidental +Jan 1, 2012 12:00:00 AM +1/1/12 12:00:00 AM Western European Standard Time +Sun 2012-01-1 00,00,00.000 Portugal Time (Lisbon) +Domingo, 1 de Janeiro de 2012 5:00:00 GMT+03:00 +==DONE== +
diff --git a/ext/intl/tests/dateformat_formatObject_error.phpt b/ext/intl/tests/dateformat_formatObject_error.phpt new file mode 100644 index 0000000000..7aaf69e54e --- /dev/null +++ b/ext/intl/tests/dateformat_formatObject_error.phpt @@ -0,0 +1,74 @@ +--TEST--
+IntlDateFormatter::formatObject(): error conditions
+--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", "pt_PT"); +ini_set("date.timezone", "Europe/Lisbon"); + +var_dump(IntlDateFormatter::formatObject()); +var_dump(IntlDateFormatter::formatObject(1)); +var_dump(IntlDateFormatter::formatObject(new stdclass)); + +class A extends IntlCalendar {function __construct(){}} +var_dump(IntlDateFormatter::formatObject(new A)); +class B extends DateTime {function __construct(){}} +var_dump(IntlDateFormatter::formatObject(new B)); + +$cal = IntlCalendar::createInstance(); +var_dump(IntlDateFormatter::formatObject($cal, -2)); +var_dump(IntlDateFormatter::formatObject($cal, array())); +var_dump(IntlDateFormatter::formatObject($cal, array(1,2,3))); +var_dump(IntlDateFormatter::formatObject($cal, array(array(), 1))); +var_dump(IntlDateFormatter::formatObject($cal, array(1, -2))); +var_dump(IntlDateFormatter::formatObject($cal, "")); +var_dump(IntlDateFormatter::formatObject($cal, "YYYY", array())); + +?> +==DONE== +
+--EXPECTF--
+ +Warning: IntlDateFormatter::formatObject() expects at least 1 parameter, 0 given in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject() expects parameter 1 to be object, integer given in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the passed object must be an instance of either IntlCalendar or DateTime in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad IntlCalendar instance: not initialized properly in %s on line %d +bool(false) + +Warning: DateTime::getTimestamp(): The DateTime object has not been correctly initialized by its constructor in %s on line %d + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: error calling ::getTimeStamp() on the object in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the date/time format type is invalid in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; if array, it must have two elements in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; if array, it must have two elements in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; the date format (first element of the array) is not valid in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad format; the time format (second element of the array) is not valid in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the format is empty in %s on line %d +bool(false) + +Warning: IntlDateFormatter::formatObject() expects parameter 3 to be string, array given in %s on line %d +bool(false) +==DONE== +
diff --git a/ext/intl/tests/msgfmt_format_error5.phpt b/ext/intl/tests/msgfmt_format_error5.phpt index 052d0efd11..ebbd4550e8 100644 --- a/ext/intl/tests/msgfmt_format_error5.phpt +++ b/ext/intl/tests/msgfmt_format_error5.phpt @@ -20,6 +20,7 @@ $mf = new MessageFormatter('en_US', $fmt); var_dump($mf->format(array("foo" => new stdclass()))); --EXPECTF-- +Warning: MessageFormatter::format(): msgfmt_format: invalid object type for date/time (only IntlCalendar and DateTime permitted) in %s on line %d Warning: MessageFormatter::format(): The argument for key 'foo' cannot be used as a date or time in %s on line %d bool(false) diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp index 6e62c34f6d..27cf41a4cf 100644 --- a/ext/intl/timezone/timezone_class.cpp +++ b/ext/intl/timezone/timezone_class.cpp @@ -25,6 +25,8 @@ #include <unicode/calendar.h> #include "../intl_convertcpp.h" +#include "../common/common_date.h" + extern "C" { #include "../intl_convert.h" #define USE_TIMEZONE_POINTER 1 @@ -54,79 +56,6 @@ 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) -{ - 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 = slprintf(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 DateTimeZone 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_convert_to_datetimezone * Convert from TimeZone to DateTimeZone object */ U_CFUNC zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, diff --git a/ext/intl/timezone/timezone_class.h b/ext/intl/timezone/timezone_class.h index 0d3c0edde4..a638f6dbf4 100644 --- a/ext/intl/timezone/timezone_class.h +++ b/ext/intl/timezone/timezone_class.h @@ -59,7 +59,6 @@ typedef struct { RETURN_FALSE; \ } -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); diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp index caf5dcdedc..9ca6b44c89 100644 --- a/ext/intl/timezone/timezone_methods.cpp +++ b/ext/intl/timezone/timezone_methods.cpp @@ -24,6 +24,9 @@ #include <unicode/timezone.h> #include <unicode/ustring.h> #include "intl_convertcpp.h" + +#include "../common/common_date.h" + extern "C" { #include "../php_intl.h" #define USE_TIMEZONE_POINTER 1 |