Skip to content

[RFC] ext/intl: Implement IntlRelativeDateTimeFormatter - #23514

Open
LamentXU123 wants to merge 2 commits into
php:masterfrom
LamentXU123:reldateformatter
Open

LamentXU123 wants to merge 2 commits into
php:masterfrom
LamentXU123:reldateformatter

Conversation

@LamentXU123

@LamentXU123 LamentXU123 commented Aug 30, 2026 •

Copy link
Copy Markdown
Member

Implement: https://wiki.php.net/rfc/reldateformatter
Discussion: https://externals.io/message/132187

TODO:

  • Complete the RFC process
  • Better tests coverage
  • NEWS / UPGRADING after 8.6 branch out
  • A full and closer review by me weeks after this is written

After these, this PR is ready for reviews. However, I am glad to see any ideas code-wise anytime if possible :)

Comment thread ext/intl/reldateformatter/reldateformatter.stub.php Outdated
@LamentXU123
LamentXU123 marked this pull request as ready for review October 13, 2026 08:31
@LamentXU123

Copy link
Copy Markdown
Member Author

Okay this is now fine for reviews. Given the current voting status this should be accepted. https://wiki.php.net/rfc/reldateformatter

@LamentXU123
LamentXU123 requested a review from devnexen October 13, 2026 08:32
@LamentXU123 LamentXU123 changed the title [W.I.P] [RFC] ext/intl: Implement IntlRelativeDateTimeFormatter [RFC] ext/intl: Implement IntlRelativeDateTimeFormatter Oct 13, 2026
Comment thread ext/intl/reldateformatter/reldateformatter_class.cpp Outdated
using icu::Locale;
using icu::UnicodeString;

struct reldateformatter_data {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--- a/ext/intl/reldateformatter/reldateformatter_class.cpp
+++ b/ext/intl/reldateformatter/reldateformatter_class.cpp
@@
 struct reldateformatter_data {
+       Locale locale;
        std::unique_ptr<icu::RelativeDateTimeFormatter> formatter;
        std::unique_ptr<icu::BreakIterator> sentence_iterator;
 };
@@ static reldateformatter_data *reldateformatter_open(
-       Locale icu_locale(locale);
+       result->locale = Locale(locale);
        if (capitalization_context == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) {
                /* ICU can fail to create this iterator before adopting the number formatter. */
-               result->sentence_iterator.reset(icu::BreakIterator::createSentenceInstance(icu_locale, *status));
+               result->sentence_iterator.reset(icu::BreakIterator::createSentenceInstance(result->locale, *status));
@@
        result->formatter.reset(new icu::RelativeDateTimeFormatter(
-               icu_locale, number_formatter_clone.release(), style, capitalization_context, *status));
+               result->locale, number_formatter_clone.release(), style, capitalization_context, *status));
@@ static zend_string *reldateformatter_format_result(
-               result.toTitle(sentence_iterator, Locale(ZSTR_VAL(obj->locale)),
+               result.toTitle(sentence_iterator, RELDATEFORMATTER_OBJECT(obj)->locale,
                        U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);

@devnexen devnexen Oct 13, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apart of this looks ok even tough C++11 builds might worry me a little bit (maybe for nothing).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, Thank you!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C++11 builds might worry me a little bit

Well Actually only starting from C++17 we have define the order of release().

Ah, I think we should instead pass get() when contructing and after the return value of new is not empty we release. And check for ICU status code.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e.

--- a/ext/intl/reldateformatter/reldateformatter_class.cpp
+++ b/ext/intl/reldateformatter/reldateformatter_class.cpp
@@ -241,18 +241,20 @@ static reldateformatter_data *reldateformatter_open(
 		}
 	}
 
-	/* If allocation fails, the constructor arguments (including release()) are not evaluated.
-	 * With a valid style/context and no sentence iterator to create, ICU adopts the clone
-	 * before any initialization failure. */
+	/* C++11 may evaluate constructor arguments even if allocation fails, so keep
+	 * ownership of the clone until we know that the constructor ran. */
 	result->formatter.reset(new icu::RelativeDateTimeFormatter(
-		result->locale, number_formatter_clone.release(), style, capitalization_context, *status));
-	if (U_FAILURE(*status)) {
-		return nullptr;
-	}
+		result->locale, number_formatter_clone.get(), style, capitalization_context, *status));
 	if (result->formatter == nullptr) {
 		*status = U_MEMORY_ALLOCATION_ERROR;
 		return nullptr;
 	}
+	/* With a valid style/context and no sentence iterator to create, the constructor
+	 * adopts the clone even if initialization fails. Release it before checking status. */
+	number_formatter_clone.release();
+	if (U_FAILURE(*status)) {
+		return nullptr;
+	}
 
 	return result.release();
 }

Add locale-aware formatting of relative offsets, enum-based style,
capitalization and unit options, and custom NumberFormatter support.
Observe subsequent NumberFormatter configuration changes and cover
formatting, error handling, and object lifetime in tests.

RFC: https://wiki.php.net/rfc/reldateformatter

Co-authored-by: NickSdot <32384907+NickSdot@users.noreply.github.com>
Co-authored-by: David Carlier <devnexen@gmail.com>
#include <unicode/uchar.h>
#include <unicode/ucasemap.h>
#include <unicode/udisplaycontext.h>
#include <unicode/unum.h>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you still need it ?


zend_object_std_init(&obj->zo, class_type);
object_properties_init(&obj->zo, class_type);
obj->zo.handlers = &reldateformatter_handlers;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might not need this, see.

Drop the unused unum.h include and rely on zend_object_std_init() to
copy the class's default object handlers.

Co-authored-by: David Carlier <devnexen@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants