Commit e1a82e151da for php.net
commit e1a82e151daf114c30c693384e234fe7ad6b7c9d
Author: Weilin Du <weilindu@php.net>
Date: Fri Aug 7 15:03:05 2026 +0800
ext/intl: Add IntlDatePatternGenerator skeleton methods (#23078)
This add missing Skeleton functions similar to #23049 and #23017 for
IntlDatePatternGenerator. This adds IntlDatePatternGenerator::getSkeleton()
and IntlDatePatternGenerator::getBaseSkeleton()
Co-authored-by: David CARLIER <devnexen@gmail.com>
diff --git a/NEWS b/NEWS
index 7bad8e58adc..cc4ff914844 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,8 @@ PHP NEWS
. Added gmp_powm_sec(). (Weilin Du)
- Intl:
+ . Added static methods IntlDatePatternGenerator::getSkeleton() and
+ IntlDatePatternGenerator::getBaseSkeleton(). (Weilin Du)
. Fixed Collator::sort(), collator_sort(), Collator::asort(), and
collator_asort() to report UTF-8/UTF-16 conversion errors through the intl
error handler instead of emitting a warning and continuing with an empty
diff --git a/UPGRADING b/UPGRADING
index d6ed37ef49b..25a405e1521 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -327,6 +327,9 @@ PHP 8.6 UPGRADE NOTES
on official Windows builds using MPIR.
- Intl:
+ . Added the static methods IntlDatePatternGenerator::getSkeleton() and
+ IntlDatePatternGenerator::getBaseSkeleton() to generate the unique skeleton
+ and base skeleton for a date/time pattern.
. Added Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue(),
with the alias of locale_get_display_keyword() and
locale_get_display_keyword_value() respectively.
@@ -506,6 +509,8 @@ PHP 8.6 UPGRADE NOTES
- Intl:
. grapheme_strrev()
RFC: https://wiki.php.net/rfc/grapheme_strrev
+ . IntlDatePatternGenerator::getSkeleton()
+ . IntlDatePatternGenerator::getBaseSkeleton()
. Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue()
RFC: https://wiki.php.net/rfc/getdisplaykeyword_and_getdisplaykeywordvalue
. SpoofChecker::areBidiConfusable()
diff --git a/ext/intl/dateformat/datepatterngenerator.stub.php b/ext/intl/dateformat/datepatterngenerator.stub.php
index a9ce7c14631..b97e8d9a86a 100644
--- a/ext/intl/dateformat/datepatterngenerator.stub.php
+++ b/ext/intl/dateformat/datepatterngenerator.stub.php
@@ -10,4 +10,8 @@ public function __construct(?string $locale = null) {}
public static function create(?string $locale = null): ?IntlDatePatternGenerator {}
public function getBestPattern(string $skeleton): string|false {}
+
+ public static function getSkeleton(string $pattern): string|false {}
+
+ public static function getBaseSkeleton(string $pattern): string|false {}
}
diff --git a/ext/intl/dateformat/datepatterngenerator_arginfo.h b/ext/intl/dateformat/datepatterngenerator_arginfo.h
index 01debdbe5fa..acf6a469592 100644
Binary files a/ext/intl/dateformat/datepatterngenerator_arginfo.h and b/ext/intl/dateformat/datepatterngenerator_arginfo.h differ
diff --git a/ext/intl/dateformat/datepatterngenerator_methods.cpp b/ext/intl/dateformat/datepatterngenerator_methods.cpp
index f22be1c21fc..24943d4ec9b 100644
--- a/ext/intl/dateformat/datepatterngenerator_methods.cpp
+++ b/ext/intl/dateformat/datepatterngenerator_methods.cpp
@@ -118,7 +118,8 @@ U_CFUNC PHP_METHOD( IntlDatePatternGenerator, getBestPattern )
INTL_METHOD_CHECK_STATUS(dtpgo, "Skeleton is not a valid UTF-8 string");
- UnicodeString skeleton = dtpgo->dtpg->getSkeleton(skeleton_uncleaned, DTPATTERNGEN_ERROR_CODE(dtpgo));
+ UnicodeString skeleton = DateTimePatternGenerator::staticGetSkeleton(
+ skeleton_uncleaned, DTPATTERNGEN_ERROR_CODE(dtpgo));
INTL_METHOD_CHECK_STATUS(dtpgo, "Error getting cleaned skeleton");
@@ -132,3 +133,49 @@ U_CFUNC PHP_METHOD( IntlDatePatternGenerator, getBestPattern )
RETVAL_STR(u8str);
}
+
+template <typename F>
+static void dtpg_get_skeleton(INTERNAL_FUNCTION_PARAMETERS, F&& skeletonfn, const char *errmsg)
+{
+ zend_string *pattern_str;
+ UnicodeString pattern;
+ UErrorCode status = U_ZERO_ERROR;
+
+ intl_error_reset(NULL);
+
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_STR(pattern_str)
+ ZEND_PARSE_PARAMETERS_END();
+
+ intl_stringFromChar(pattern, ZSTR_VAL(pattern_str), ZSTR_LEN(pattern_str), &status);
+
+ INTL_CHECK_STATUS(status, "Pattern is not a valid UTF-8 string");
+
+ UnicodeString result = skeletonfn(pattern, status);
+
+ INTL_CHECK_STATUS(status, errmsg);
+
+ zend_string *u8str = intl_charFromString(result, &status);
+
+ INTL_CHECK_STATUS(status, "Error converting result to UTF-8");
+
+ RETVAL_STR(u8str);
+}
+
+U_CFUNC PHP_METHOD(IntlDatePatternGenerator, getSkeleton)
+{
+ dtpg_get_skeleton(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ [](const UnicodeString &pattern, UErrorCode &status) {
+ return DateTimePatternGenerator::staticGetSkeleton(pattern, status);
+ },
+ "Error getting skeleton");
+}
+
+U_CFUNC PHP_METHOD(IntlDatePatternGenerator, getBaseSkeleton)
+{
+ dtpg_get_skeleton(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ [](const UnicodeString &pattern, UErrorCode &status) {
+ return DateTimePatternGenerator::staticGetBaseSkeleton(pattern, status);
+ },
+ "Error getting base skeleton");
+}
diff --git a/ext/intl/tests/datepatterngenerator_get_skeleton.phpt b/ext/intl/tests/datepatterngenerator_get_skeleton.phpt
new file mode 100644
index 00000000000..de425fc1667
--- /dev/null
+++ b/ext/intl/tests/datepatterngenerator_get_skeleton.phpt
@@ -0,0 +1,48 @@
+--TEST--
+IntlDatePatternGenerator::getSkeleton() and getBaseSkeleton()
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+
+var_dump(IntlDatePatternGenerator::getSkeleton("dd/MMM"));
+var_dump(IntlDatePatternGenerator::getSkeleton("MMM-dd"));
+var_dump(IntlDatePatternGenerator::getBaseSkeleton("dd/MMM"));
+var_dump(IntlDatePatternGenerator::getBaseSkeleton("MMM-dd"));
+var_dump(IntlDatePatternGenerator::getSkeleton(""));
+var_dump(IntlDatePatternGenerator::getBaseSkeleton(""));
+
+$patterns = [
+ "'at' HH:mm",
+ "y年M月d日",
+ "yyyy-MM-dd",
+ "MMMMM",
+ "MMM",
+ "HH:mm:ss zzz dd/MM/y",
+ "'at HH:mm",
+];
+
+foreach ($patterns as $pattern) {
+ printf(
+ "%s => [%s] [%s]\n",
+ $pattern,
+ IntlDatePatternGenerator::getSkeleton($pattern),
+ IntlDatePatternGenerator::getBaseSkeleton($pattern),
+ );
+}
+
+?>
+--EXPECT--
+string(5) "MMMdd"
+string(5) "MMMdd"
+string(4) "MMMd"
+string(4) "MMMd"
+string(0) ""
+string(0) ""
+'at' HH:mm => [HHmm] [Hm]
+y年M月d日 => [yMd] [yMd]
+yyyy-MM-dd => [yyyyMMdd] [yMd]
+MMMMM => [MMMMM] [MMMMM]
+MMM => [MMM] [MMM]
+HH:mm:ss zzz dd/MM/y => [yMMddHHmmsszzz] [yMdHmsz]
+'at HH:mm => [] []
diff --git a/ext/intl/tests/datepatterngenerator_skeleton_error.phpt b/ext/intl/tests/datepatterngenerator_skeleton_error.phpt
new file mode 100644
index 00000000000..06a351ecd1b
--- /dev/null
+++ b/ext/intl/tests/datepatterngenerator_skeleton_error.phpt
@@ -0,0 +1,18 @@
+--TEST--
+IntlDatePatternGenerator::getSkeleton() and getBaseSkeleton(): errors
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+
+foreach (["getSkeleton", "getBaseSkeleton"] as $method) {
+ var_dump(IntlDatePatternGenerator::$method("dd/MMM\x80"));
+ echo intl_get_error_message(), "\n";
+}
+
+?>
+--EXPECT--
+bool(false)
+IntlDatePatternGenerator::getSkeleton(): Pattern is not a valid UTF-8 string: U_INVALID_CHAR_FOUND
+bool(false)
+IntlDatePatternGenerator::getBaseSkeleton(): Pattern is not a valid UTF-8 string: U_INVALID_CHAR_FOUND