mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
ext/intl: IntlDateFormatter::parseToCalendar addition.
Unlike IntlDateFormatter::parse, the timezone is updated accordingly. Close GH-13779
This commit is contained in:
1
NEWS
1
NEWS
@@ -86,6 +86,7 @@ PHP NEWS
|
||||
. ResourceBundle::get() now has a tentative return type of:
|
||||
ResourceBundle|array|string|int|null
|
||||
. Added the new Grapheme function grapheme_str_split. (youkidearitai)
|
||||
. Addewd IntlDateFormatter::parseToCalendar. (David Carlier)
|
||||
|
||||
- LDAP:
|
||||
. Added LDAP_OPT_X_TLS_PROTOCOL_MAX/LDAP_OPT_X_TLS_PROTOCOL_TLS1_3
|
||||
|
||||
@@ -469,6 +469,8 @@ PHP 8.4 UPGRADE NOTES
|
||||
the IANA identifier from a given timezone.
|
||||
. Added grapheme_str_split which allow to support emoji and Variation
|
||||
Selectors.
|
||||
. Added IntlDateFormatter::parseToCalendar which behaves like
|
||||
IntlDateFormatter::parse except the time zone is updated.
|
||||
|
||||
- MBString:
|
||||
. Added mb_trim, mb_ltrim and mb_rtrim functions.
|
||||
|
||||
@@ -159,6 +159,11 @@ class IntlDateFormatter
|
||||
*/
|
||||
public function parse(string $string, &$offset = null): int|float|false {}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*/
|
||||
public function parseToCalendar(string $string, &$offset = null): int|float|false {}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @return array<string, int>|false
|
||||
|
||||
9
ext/intl/dateformat/dateformat_arginfo.h
generated
9
ext/intl/dateformat/dateformat_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 91f1dbe4843fd1d4dff7266e814a3c8f9aed882a */
|
||||
* Stub hash: 56b66b1b51220ddbff698ec4c9a6ae60f3e0bfb0 */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDateFormatter___construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1)
|
||||
@@ -75,6 +75,11 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatte
|
||||
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_parseToCalendar, 0, 1, MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)
|
||||
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_localtime, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)
|
||||
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, offset, "null")
|
||||
@@ -104,6 +109,7 @@ ZEND_FUNCTION(datefmt_is_lenient);
|
||||
ZEND_FUNCTION(datefmt_format);
|
||||
ZEND_FUNCTION(datefmt_format_object);
|
||||
ZEND_FUNCTION(datefmt_parse);
|
||||
ZEND_METHOD(IntlDateFormatter, parseToCalendar);
|
||||
ZEND_FUNCTION(datefmt_localtime);
|
||||
ZEND_FUNCTION(datefmt_get_error_code);
|
||||
ZEND_FUNCTION(datefmt_get_error_message);
|
||||
@@ -127,6 +133,7 @@ static const zend_function_entry class_IntlDateFormatter_methods[] = {
|
||||
ZEND_RAW_FENTRY("format", zif_datefmt_format, arginfo_class_IntlDateFormatter_format, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_RAW_FENTRY("formatObject", zif_datefmt_format_object, arginfo_class_IntlDateFormatter_formatObject, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, NULL)
|
||||
ZEND_RAW_FENTRY("parse", zif_datefmt_parse, arginfo_class_IntlDateFormatter_parse, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_ME(IntlDateFormatter, parseToCalendar, arginfo_class_IntlDateFormatter_parseToCalendar, ZEND_ACC_PUBLIC)
|
||||
ZEND_RAW_FENTRY("localtime", zif_datefmt_localtime, arginfo_class_IntlDateFormatter_localtime, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_RAW_FENTRY("getErrorCode", zif_datefmt_get_error_code, arginfo_class_IntlDateFormatter_getErrorCode, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_RAW_FENTRY("getErrorMessage", zif_datefmt_get_error_message, arginfo_class_IntlDateFormatter_getErrorMessage, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* if set to 1 - store any error encountered in the parameter parse_error
|
||||
* if set to 0 - no need to store any error encountered in the parameter parse_error
|
||||
*/
|
||||
static void internal_parse_to_timestamp(IntlDateFormatter_object *dfo, char* text_to_parse, size_t text_len, int32_t *parse_pos, zval *return_value)
|
||||
static void internal_parse_to_timestamp(IntlDateFormatter_object *dfo, char* text_to_parse, size_t text_len, int32_t *parse_pos, bool update_calendar, zval *return_value)
|
||||
{
|
||||
double result = 0;
|
||||
UDate timestamp =0;
|
||||
@@ -42,13 +42,22 @@ static void internal_parse_to_timestamp(IntlDateFormatter_object *dfo, char* tex
|
||||
intl_convert_utf8_to_utf16(&text_utf16, &text_utf16_len, text_to_parse, text_len, &INTL_DATA_ERROR_CODE(dfo));
|
||||
INTL_METHOD_CHECK_STATUS(dfo, "Error converting timezone to UTF-16" );
|
||||
|
||||
timestamp = udat_parse( DATE_FORMAT_OBJECT(dfo), text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo));
|
||||
if( text_utf16 ){
|
||||
efree(text_utf16);
|
||||
if (UNEXPECTED(update_calendar)) {
|
||||
UCalendar *parsed_calendar = (UCalendar *)udat_getCalendar(DATE_FORMAT_OBJECT(dfo));
|
||||
udat_parseCalendar(DATE_FORMAT_OBJECT(dfo), parsed_calendar, text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo));
|
||||
if (text_utf16) {
|
||||
efree(text_utf16);
|
||||
}
|
||||
INTL_METHOD_CHECK_STATUS( dfo, "Calendar parsing failed" );
|
||||
timestamp = ucal_getMillis( parsed_calendar, &INTL_DATA_ERROR_CODE(dfo));
|
||||
} else {
|
||||
timestamp = udat_parse(DATE_FORMAT_OBJECT(dfo), text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo));
|
||||
if (text_utf16) {
|
||||
efree(text_utf16);
|
||||
}
|
||||
}
|
||||
|
||||
INTL_METHOD_CHECK_STATUS( dfo, "Date parsing failed" );
|
||||
|
||||
/* Since return is in sec. */
|
||||
result = (double)timestamp / U_MILLIS_PER_SECOND;
|
||||
if (result > (double)LONG_MAX || result < (double)LONG_MIN) {
|
||||
@@ -145,18 +154,63 @@ PHP_FUNCTION(datefmt_parse)
|
||||
RETURN_FALSE;
|
||||
}
|
||||
parse_pos = (int32_t)long_parse_pos;
|
||||
if((size_t)parse_pos > text_len) {
|
||||
if ((size_t)parse_pos > text_len) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, return_value);
|
||||
if(z_parse_pos) {
|
||||
internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos ? &parse_pos : NULL, false, return_value);
|
||||
if (z_parse_pos) {
|
||||
zval_ptr_dtor(z_parse_pos);
|
||||
ZVAL_LONG(z_parse_pos, parse_pos);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(IntlDateFormatter, parseToCalendar)
|
||||
{
|
||||
zend_string *text_to_parse = NULL;
|
||||
zval* z_parse_pos = NULL;
|
||||
int32_t parse_pos = -1;
|
||||
|
||||
DATE_FORMAT_METHOD_INIT_VARS;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 2)
|
||||
Z_PARAM_STR(text_to_parse)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(z_parse_pos)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
object = ZEND_THIS;
|
||||
|
||||
/* Fetch the object. */
|
||||
DATE_FORMAT_METHOD_FETCH_OBJECT;
|
||||
|
||||
if (z_parse_pos) {
|
||||
zend_long long_parse_pos;
|
||||
ZVAL_DEREF(z_parse_pos);
|
||||
bool failed = false;
|
||||
long_parse_pos = zval_try_get_long(z_parse_pos, &failed);
|
||||
if (failed) {
|
||||
zend_argument_type_error(2, "must be of type int, %s given", zend_zval_value_name(z_parse_pos));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
if (ZEND_LONG_INT_OVFL(long_parse_pos)) {
|
||||
intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
|
||||
intl_error_set_custom_msg(NULL, "String index is out of valid range.", 0);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
parse_pos = (int32_t)long_parse_pos;
|
||||
if (parse_pos != -1 && (size_t)parse_pos > ZSTR_LEN(text_to_parse)) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
internal_parse_to_timestamp( dfo, ZSTR_VAL(text_to_parse), ZSTR_LEN(text_to_parse), z_parse_pos ? &parse_pos : NULL, true, return_value);
|
||||
if (z_parse_pos) {
|
||||
zval_ptr_dtor(z_parse_pos);
|
||||
ZVAL_LONG(z_parse_pos, parse_pos);
|
||||
}
|
||||
}
|
||||
|
||||
/* {{{ Parse the string $value to a localtime array */
|
||||
PHP_FUNCTION(datefmt_localtime)
|
||||
{
|
||||
|
||||
35
ext/intl/tests/gh13766.phpt
Normal file
35
ext/intl/tests/gh13766.phpt
Normal file
@@ -0,0 +1,35 @@
|
||||
--TEST--
|
||||
IntlDateFormatter::parse update its calendar
|
||||
--EXTENSIONS--
|
||||
intl
|
||||
--FILE--
|
||||
<?php
|
||||
$oIntlDateFormatter = new IntlDateFormatter("en_GB");
|
||||
$oIntlDateFormatter->setTimeZone('Europe/Berlin');
|
||||
$oIntlDateFormatter->setPattern('VV');
|
||||
|
||||
var_dump($oIntlDateFormatter->parse('America/Los_Angeles', $offset1));
|
||||
var_dump($oIntlDateFormatter->getTimeZone()->getID());
|
||||
var_dump($oIntlDateFormatter->parseToCalendar('America/Los_Angeles', $offset2));
|
||||
var_dump($oIntlDateFormatter->getTimeZone()->getID());
|
||||
$offset3 = "offset";
|
||||
|
||||
try {
|
||||
$oIntlDateFormatter->parseToCalendar('America/Los_Angeles', $offset3);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
$offset3 = PHP_INT_MAX * 16;
|
||||
try {
|
||||
$oIntlDateFormatter->parseToCalendar('America/Los_Angeles', $offset3);
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
--EXPECTF--
|
||||
int(%d)
|
||||
string(13) "Europe/Berlin"
|
||||
int(%d)
|
||||
string(19) "America/Los_Angeles"
|
||||
IntlDateFormatter::parseToCalendar(): Argument #2 ($offset) must be of type int, string given
|
||||
|
||||
Deprecated: Implicit conversion from float 1.4757395258967641E+20 to int loses precision in %s on line %d
|
||||
Reference in New Issue
Block a user