Skip to content

Commit 3a81f90

Browse files
committed
Added IntlCalendar::toDateTime()
1 parent 49b1f58 commit 3a81f90

7 files changed

+152
-1
lines changed

ext/intl/calendar/calendar_class.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ static const zend_function_entry Calendar_class_functions[] = {
431431
PHP_ME_MAPPING(setSkippedWallTimeOption,intlcal_set_skipped_wall_time_option,ainfo_cal_wall_time_option,ZEND_ACC_PUBLIC)
432432
#endif
433433
PHP_ME_MAPPING(fromDateTime, intlcal_from_date_time, ainfo_cal_from_date_time, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
434+
PHP_ME_MAPPING(toDateTime, intlcal_to_date_time, ainfo_cal_void, ZEND_ACC_PUBLIC)
434435
PHP_ME_MAPPING(getErrorCode, intlcal_get_error_code, ainfo_cal_void, ZEND_ACC_PUBLIC)
435436
PHP_ME_MAPPING(getErrorMessage, intlcal_get_error_message, ainfo_cal_void, ZEND_ACC_PUBLIC)
436437
PHP_FE_END

ext/intl/calendar/calendar_methods.cpp

+80
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,86 @@ U_CFUNC PHP_FUNCTION(intlcal_from_date_time)
12001200
}
12011201
}
12021202

1203+
U_CFUNC PHP_FUNCTION(intlcal_to_date_time)
1204+
{
1205+
zval *retval = NULL;
1206+
CALENDAR_METHOD_INIT_VARS;
1207+
1208+
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
1209+
&object, Calendar_ce_ptr) == FAILURE) {
1210+
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
1211+
"intlcal_to_date_time: bad arguments", 0 TSRMLS_CC);
1212+
RETURN_FALSE;
1213+
}
1214+
1215+
CALENDAR_METHOD_FETCH_OBJECT;
1216+
1217+
/* There are no exported functions in ext/date to this
1218+
* in a more native fashion */
1219+
double date = co->ucal->getTime(CALENDAR_ERROR_CODE(co)) / 1000.;
1220+
int64_t ts;
1221+
char ts_str[sizeof("@-9223372036854775808")];
1222+
int ts_str_len;
1223+
zval ts_zval = zval_used_for_init;
1224+
1225+
INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed");
1226+
1227+
if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) {
1228+
intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1229+
"intlcal_to_date_time: The calendar date is out of the "
1230+
"range for a 64-bit integer", 0 TSRMLS_CC);
1231+
RETURN_FALSE;
1232+
}
1233+
1234+
ts = (int64_t)date;
1235+
1236+
ts_str_len = slprintf(ts_str, sizeof(ts_str), "@%I64d", ts);
1237+
ZVAL_STRINGL(&ts_zval, ts_str, ts_str_len, 0);
1238+
1239+
/* Now get the time zone */
1240+
const TimeZone& tz = co->ucal->getTimeZone();
1241+
zval *timezone_zval = timezone_convert_to_datetimezone(
1242+
&tz, CALENDAR_ERROR_P(co), "intlcal_to_date_time" TSRMLS_CC);
1243+
if (timezone_zval == NULL) {
1244+
RETURN_FALSE;
1245+
}
1246+
1247+
/* resources allocated from now on */
1248+
1249+
/* Finally, instantiate object and call constructor */
1250+
object_init_ex(return_value, php_date_get_date_ce());
1251+
zend_call_method_with_2_params(&return_value, NULL, NULL, "__construct",
1252+
NULL, &ts_zval, timezone_zval);
1253+
if (EG(exception)) {
1254+
intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1255+
"intlcal_to_date_time: DateTime constructor has thrown exception",
1256+
1 TSRMLS_CC);
1257+
zend_object_store_ctor_failed(return_value TSRMLS_CC);
1258+
zval_ptr_dtor(&return_value);
1259+
1260+
RETVAL_FALSE;
1261+
goto error;
1262+
}
1263+
1264+
/* due to bug #40743, we have to set the time zone again */
1265+
zend_call_method_with_1_params(&return_value, NULL, NULL, "settimezone",
1266+
&retval, timezone_zval);
1267+
if (retval == NULL || Z_TYPE_P(retval) == IS_BOOL) {
1268+
intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR,
1269+
"intlcal_to_date_time: call to DateTime::setTimeZone has failed",
1270+
1 TSRMLS_CC);
1271+
zval_ptr_dtor(&return_value);
1272+
RETVAL_FALSE;
1273+
goto error;
1274+
}
1275+
1276+
error:
1277+
zval_ptr_dtor(&timezone_zval);
1278+
if (retval != NULL) {
1279+
zval_ptr_dtor(&retval);
1280+
}
1281+
}
1282+
12031283
U_CFUNC PHP_FUNCTION(intlcal_get_error_code)
12041284
{
12051285
CALENDAR_METHOD_INIT_VARS;

ext/intl/calendar/calendar_methods.h

+2
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ PHP_FUNCTION(intlcal_set_skipped_wall_time_option);
103103

104104
PHP_FUNCTION(intlcal_from_date_time);
105105

106+
PHP_FUNCTION(intlcal_to_date_time);
107+
106108
PHP_FUNCTION(intlcal_get_error_code);
107109

108110
PHP_FUNCTION(intlcal_get_error_message);

ext/intl/php_intl.c

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@ zend_function_entry intl_functions[] = {
796796
PHP_FE( intlcal_set_lenient, ainfo_cal_set_lenient )
797797
PHP_FE( intlcal_equals, ainfo_cal_other_cal )
798798
PHP_FE( intlcal_from_date_time, ainfo_cal_from_date_time )
799+
PHP_FE( intlcal_to_date_time, ainfo_cal_only_cal )
799800
#if U_ICU_VERSION_MAJOR_NUM >= 49
800801
PHP_FE( intlcal_get_repeated_wall_time_option, ainfo_cal_only_cal )
801802
PHP_FE( intlcal_get_skipped_wall_time_option, ainfo_cal_only_cal )

ext/intl/tests/badargs.phpt

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ foreach($funcs as $func) {
1313
if($rfunc->getNumberOfRequiredParameters() == 0) {
1414
continue;
1515
}
16-
$res = $func($arg);
16+
17+
try {
18+
$res = $func($arg);
19+
} catch (Exception $e) { continue; }
1720
if($res != false) {
1821
echo "$func: ";
1922
var_dump($res);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
IntlCalendar::toDateTime(): basic test
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('intl'))
6+
die('skip intl extension not enabled');
7+
--FILE--
8+
<?php
9+
ini_set("intl.error_level", E_WARNING);
10+
//ini_set("intl.default_locale", "nl");
11+
ini_set('date.timezone', 'Europe/Lisbon');
12+
13+
$cal = new IntlGregorianCalendar(2012,04,17,17,35,36);
14+
15+
$dt = $cal->toDateTime();
16+
17+
var_dump($dt->format("c"), $dt->getTimeZone()->getName());
18+
?>
19+
==DONE==
20+
--EXPECT--
21+
string(25) "2012-05-17T17:35:36+01:00"
22+
string(13) "Europe/Lisbon"
23+
==DONE==
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
IntlCalendar::toDateTime(): bad arguments
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('intl'))
6+
die('skip intl extension not enabled');
7+
--FILE--
8+
<?php
9+
ini_set("intl.error_level", E_WARNING);
10+
ini_set('date.timezone', 'Europe/Lisbon');
11+
12+
$cal = new IntlGregorianCalendar();
13+
var_dump($cal->toDateTime(3));
14+
15+
var_dump(intlcal_to_date_time($cal, 3));
16+
17+
$cal = new IntlGregorianCalendar("Etc/Unknown");
18+
try {
19+
var_dump($cal->toDateTime());
20+
} catch (Exception $e) {
21+
var_dump("exception: {$e->getMessage()}");
22+
}
23+
24+
var_dump(intlcal_to_date_time(3));
25+
26+
--EXPECTF--
27+
28+
Warning: IntlCalendar::toDateTime() expects exactly 0 parameters, 1 given in %s on line %d
29+
30+
Warning: IntlCalendar::toDateTime(): intlcal_to_date_time: bad arguments in %s on line %d
31+
bool(false)
32+
33+
Warning: intlcal_to_date_time() expects exactly 1 parameter, 2 given in %s on line %d
34+
35+
Warning: intlcal_to_date_time(): intlcal_to_date_time: bad arguments in %s on line %d
36+
bool(false)
37+
38+
Warning: IntlCalendar::toDateTime(): intlcal_to_date_time: DateTimeZone constructor threw exception in %s on line %d
39+
string(77) "exception: DateTimeZone::__construct(): Unknown or bad timezone (Etc/Unknown)"
40+
41+
Catchable fatal error: Argument 1 passed to intlcal_to_date_time() must be an instance of IntlCalendar, integer given in %s on line %d

0 commit comments

Comments
 (0)