diff --git a/ext/intl/calendar/calendar_class.cpp b/ext/intl/calendar/calendar_class.cpp index ea5339d836f..9f5db6f29cf 100644 --- a/ext/intl/calendar/calendar_class.cpp +++ b/ext/intl/calendar/calendar_class.cpp @@ -351,6 +351,10 @@ ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_setLenient, 0, 0, 1) ZEND_ARG_INFO(0, isLenient) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_from_date_time, 0, 0, 1) + ZEND_ARG_INFO(0, dateTime) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_wall_time_option, 0, 0, 1) ZEND_ARG_INFO(0, wallTimeOption) ZEND_END_ARG_INFO() @@ -426,6 +430,7 @@ static const zend_function_entry Calendar_class_functions[] = { PHP_ME_MAPPING(setRepeatedWallTimeOption,intlcal_set_repeated_wall_time_option,ainfo_cal_wall_time_option,ZEND_ACC_PUBLIC) PHP_ME_MAPPING(setSkippedWallTimeOption,intlcal_set_skipped_wall_time_option,ainfo_cal_wall_time_option,ZEND_ACC_PUBLIC) #endif + PHP_ME_MAPPING(fromDateTime, intlcal_from_date_time, ainfo_cal_from_date_time, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getErrorCode, intlcal_get_error_code, ainfo_cal_void, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getErrorMessage, intlcal_get_error_message, ainfo_cal_void, ZEND_ACC_PUBLIC) PHP_FE_END diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp index 0c6450fce7c..e9565fc1210 100644 --- a/ext/intl/calendar/calendar_methods.cpp +++ b/ext/intl/calendar/calendar_methods.cpp @@ -1108,6 +1108,97 @@ U_CFUNC PHP_FUNCTION(intlcal_set_skipped_wall_time_option) #endif +U_CFUNC PHP_FUNCTION(intlcal_from_date_time) +{ + zval **zv_arg, + *zv_datetime = NULL, + *zv_timestamp = NULL; + php_date_obj *datetime; + char *locale_str = NULL; + int locale_str_len; + TimeZone *timeZone; + UErrorCode status = U_ZERO_ERROR; + intl_error_reset(NULL TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s!", + &zv_arg, &locale_str, &locale_str_len) == FAILURE) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_from_date_time: bad arguments", 0 TSRMLS_CC); + RETURN_NULL(); + } + + if (!(Z_TYPE_PP(zv_arg) == IS_OBJECT && instanceof_function( + Z_OBJCE_PP(zv_arg), php_date_get_date_ce() TSRMLS_CC))) { + ALLOC_INIT_ZVAL(zv_datetime); + object_init_ex(zv_datetime, php_date_get_date_ce()); + zend_call_method_with_1_params(&zv_datetime, NULL, NULL, "__construct", + NULL, *zv_arg); + if (EG(exception)) { + zend_object_store_ctor_failed(zv_datetime TSRMLS_CC); + goto error; + } + } else { + zv_datetime = *zv_arg; + } + + datetime = (php_date_obj*)zend_object_store_get_object(zv_datetime TSRMLS_CC); + if (!datetime) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_from_date_time: DateTime object is unconstructed", + 0 TSRMLS_CC); + goto error; + } + + zend_call_method_with_0_params(&zv_datetime, php_date_get_date_ce(), + NULL, "gettimestamp", &zv_timestamp); + if (!zv_timestamp || Z_TYPE_P(zv_timestamp) != IS_LONG) { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intlcal_from_date_time: bad DateTime; call to " + "DateTime::getTimestamp() failed", 0 TSRMLS_CC); + goto error; + } + + if (!datetime->time->is_localtime) { + timeZone = TimeZone::getGMT()->clone(); + } else { + timeZone = timezone_convert_datetimezone(datetime->time->zone_type, + datetime, 1, NULL, "intlcal_from_date_time" TSRMLS_CC); + if (timeZone == NULL) { + goto error; + } + } + + if (!locale_str) { + locale_str = const_cast(intl_locale_get_default(TSRMLS_C)); + } + + Calendar *cal = Calendar::createInstance(timeZone, + Locale::createFromName(locale_str), status); + if (cal == NULL) { + delete timeZone; + intl_error_set(NULL, status, "intlcal_from_date_time: " + "error creating ICU Calendar object", 0 TSRMLS_CC); + goto error; + } + cal->setTime(((UDate)Z_LVAL_P(zv_timestamp)) * 1000., status); + if (U_FAILURE(status)) { + delete cal; + intl_error_set(NULL, status, "intlcal_from_date_time: " + "error creating ICU Calendar::setTime()", 0 TSRMLS_CC); + goto error; + } + + calendar_object_create(return_value, cal TSRMLS_CC); + +error: + if (zv_datetime != *zv_arg) { + zval_ptr_dtor(&zv_datetime); + } + if (zv_timestamp) { + zval_ptr_dtor(&zv_timestamp); + } +} + U_CFUNC PHP_FUNCTION(intlcal_get_error_code) { CALENDAR_METHOD_INIT_VARS; diff --git a/ext/intl/calendar/calendar_methods.h b/ext/intl/calendar/calendar_methods.h index 95ff5375b52..e0055711ae8 100644 --- a/ext/intl/calendar/calendar_methods.h +++ b/ext/intl/calendar/calendar_methods.h @@ -101,6 +101,8 @@ PHP_FUNCTION(intlcal_set_repeated_wall_time_option); PHP_FUNCTION(intlcal_set_skipped_wall_time_option); +PHP_FUNCTION(intlcal_from_date_time); + PHP_FUNCTION(intlcal_get_error_code); PHP_FUNCTION(intlcal_get_error_message); diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c index aca3590e011..51aece69d55 100755 --- a/ext/intl/php_intl.c +++ b/ext/intl/php_intl.c @@ -556,6 +556,10 @@ ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_set_lenient, 0, 0, 2 ) ZEND_ARG_INFO( 0, isLenient ) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(ainfo_cal_from_date_time, 0, 0, 1) + ZEND_ARG_INFO(0, dateTime) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX( ainfo_cal_wall_time_option, 0, 0, 2 ) ZEND_ARG_OBJ_INFO( 0, calendar, IntlCalendar, 0 ) ZEND_ARG_INFO( 0, wallTimeOption ) @@ -785,6 +789,7 @@ zend_function_entry intl_functions[] = { PHP_FE( intlcal_set_first_day_of_week, ainfo_cal_dow ) PHP_FE( intlcal_set_lenient, ainfo_cal_set_lenient ) PHP_FE( intlcal_equals, ainfo_cal_other_cal ) + PHP_FE( intlcal_from_date_time, ainfo_cal_from_date_time ) #if U_ICU_VERSION_MAJOR_NUM >= 49 PHP_FE( intlcal_get_repeated_wall_time_option, ainfo_cal_only_cal ) PHP_FE( intlcal_get_skipped_wall_time_option, ainfo_cal_only_cal ) diff --git a/ext/intl/tests/calendar_fromDateTime_basic.phpt b/ext/intl/tests/calendar_fromDateTime_basic.phpt new file mode 100644 index 00000000000..1863b7815c9 --- /dev/null +++ b/ext/intl/tests/calendar_fromDateTime_basic.phpt @@ -0,0 +1,52 @@ +--TEST-- +IntlCalendar::fromDateTime(): basic test +--SKIPIF-- +getTime(), + strtotime('2012-01-01 00:00:00 Europe/Rome') * 1000., + $cal->getTimeZone()->getID(), + $cal->getLocale(1) +); +echo "\n"; + +$cal = IntlCalendar::fromDateTime(new DateTime('2012-01-01 00:00:00 PST'), "pt_PT"); +var_dump( + $cal->getTime(), + strtotime('2012-01-01 00:00:00 PST') * 1000., + $cal->getTimeZone()->getID(), + $cal->getLocale(1) +); + +echo "\n"; + +$cal = intlcal_from_date_time(new DateTime('2012-01-01 00:00:00 +03:40')); +var_dump( + $cal->getTime(), + strtotime('2012-01-01 00:00:00 +03:40') * 1000., + $cal->getTimeZone()->getID() +); + +--EXPECTF-- +float(1325372400000) +float(1325372400000) +string(11) "Europe/Rome" +string(5) "nl_NL" + +float(1325404800000) +float(1325404800000) +string(3) "PST" +string(5) "pt_PT" + +float(1325362800000) +float(1325362800000) +string(%d) "GMT+03%S40" diff --git a/ext/intl/tests/calendar_fromDateTime_error.phpt b/ext/intl/tests/calendar_fromDateTime_error.phpt new file mode 100644 index 00000000000..b3cb22a6ca9 --- /dev/null +++ b/ext/intl/tests/calendar_fromDateTime_error.phpt @@ -0,0 +1,61 @@ +--TEST-- +IntlCalendar::fromDateTime(): errors +--SKIPIF-- +