fix(I18n): compute correct date in Time::today(), yesterday(), and tomorrow() across timezones - #10532
Open
gr8man wants to merge 2 commits into
Open
fix(I18n): compute correct date in Time::today(), yesterday(), and tomorrow() across timezones#10532gr8man wants to merge 2 commits into
gr8man wants to merge 2 commits into
Conversation
…terday(), and tomorrow() - Compute start of day relative to the requested timezone instead of the server default timezone - Respect Time::setTestNow() mock instance in today(), yesterday(), and tomorrow() - Add unit tests covering date boundary transitions across different timezones - Add changelog entry in v4.7.5.rst
neznaika0
suggested changes
Sep 9, 2026
Co-authored-by: neznaika0 <ozornick.ks@gmail.com>
There was a problem hiding this comment.
🟡 Changes recommended
It introduces subclass compatibility changes, leaves an existing timezone test intermittent, and lacks coverage for TimeLegacy.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Fixes timezone-aware calendar calculations and mocked-time handling. Compatibility assessment assumes develop because the base branch was not provided.
Changes:
- Computes relative dates from timezone-aware
now(). - Adds timezone-boundary regression tests.
- Documents the fix in the changelog.
Validation: code inspection only; test execution remains for CI.
File summaries
| File | Description |
|---|---|
system/I18n/TimeTrait.php |
Updates date helper calculations. |
tests/system/I18n/TimeTest.php |
Adds boundary tests. |
user_guide_src/source/changelogs/v4.7.5.rst |
Adds changelog entry. |
Review details
Suppressed comments (3)
system/I18n/TimeTrait.php:161
- This newly routes inherited
yesterday()calls through an overridablenow(). A third-party subclass that overridesnow()but relies on the inherited calendar helper therefore changes behavior unexpectedly; construct withnulldirectly so the fix still honorssetTestNow()without coupling these extension points.
return static::now($timezone, $locale)->modify('-1 day')->setTime(0, 0, 0, 0);
system/I18n/TimeTrait.php:175
- This newly routes inherited
tomorrow()calls through an overridablenow(). A third-party subclass that overridesnow()but relies on the inherited calendar helper therefore changes behavior unexpectedly; construct withnulldirectly so the fix still honorssetTestNow()without coupling these extension points.
return static::now($timezone, $locale)->modify('+1 day')->setTime(0, 0, 0, 0);
system/I18n/TimeTrait.php:147
- The existing
testTodayLocalized()still comparesTime::today('Europe/London')with server-localdate(). With this fix, that assertion fails when London and the server are on different dates (for example, 23:30 UTC during BST). Freeze the clock and assert the London date, or build the expectation in the requested timezone.
return static::now($timezone, $locale)->setTime(0, 0, 0, 0);
- Files reviewed: 3/3 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| public static function today($timezone = null, ?string $locale = null) | ||
| { | ||
| return new static(date('Y-m-d 00:00:00'), $timezone, $locale); | ||
| return static::now($timezone, $locale)->setTime(0, 0, 0, 0); |
| $this->assertSame(date('Y-m-d 00:00:00', strtotime('+1 day')), $time->toDateTimeString()); | ||
| } | ||
|
|
||
| public function testTodayWithTimezoneAcrossDateBoundary(): void |
| - **Files:** Fixed a bug where ``File::move()`` and ``UploadedFile::move()`` set executable and overly permissive file permissions (``0777 & ~umask()`` instead of ``0666 & ~umask()``), and ``UploadedFile::move()`` targeted the parent directory instead of the destination file for ``chmod()``. | ||
| - **Helpers:** Fixed a bug where ``get_dir_file_info()`` returned incomplete entries for subdirectories and missing files instead of omitting them. | ||
| - **Honeypot:** Fixed a bug where bot detection returned an HTTP 500 response instead of 403 (Forbidden). | ||
| - **I18n:** Fixed a bug where ``Time::today()``, ``Time::yesterday()``, and ``Time::tomorrow()`` ignored the specified ``$timezone``, ``$locale`` and ``setTestNow()`` when calculating the day. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Time::today($timezone),Time::yesterday($timezone), andTime::tomorrow($timezone)previously used PHP's nativedate('Y-m-d 00:00:00')andstrtotime('-1 day')/strtotime('+1 day')to generate the date string passed to the constructor.Because
date()andstrtotime()evaluate in the server's default timezone (date_default_timezone_get()), the target$timezoneargument was ignored when determining the calendar day. For several hours each day (when the server timezone like UTC and the requested timezone likeAsia/TokyoorAmerica/New_Yorkare on different calendar days),today(),yesterday(), andtomorrow()produced the wrong calendar day in that timezone.Furthermore, passing a non-empty string from
date()intonew static(...)bypassedTime::setTestNow()in the constructor, preventingtoday(),yesterday(), andtomorrow()from respecting mocked test time.This PR fixes both issues by using
static::now($timezone, $locale)->setTime(0, 0, 0, 0)(andmodify('-1 day')/modify('+1 day')). This ensures:Time::setTestNow()mock instances are preserved and converted accurately.v4.7.5.rst.Checklist: