Skip to content

Date-only fields show wrong date in CP collection table for timezones ahead of UTC #14413

@lorenzomorici

Description

@lorenzomorici

Bug description

When using a date field without time (time_enabled: false, format Y-m-d) and the application timezone is set to a
timezone ahead of UTC (e.g. Europe/Rome, GMT+1), the Control Panel collection table displays dates one day
behind the actual stored value.

Stored value (content file) -> 2026-03-14
CP entry publish form -> 14/03/2026
CP collection table -> 13/03/2026 (wrong)
Frontend (Antlers/Blade) -> 14/03/2026

Root cause

The issue is in src/Fieldtypes/Date.php, in the parseSaved() method (line ~333):

private function parseSaved($value)
{
$hasTime = false;

if (is_int($value)) {
    $hasTime = true;                                                                                         
} elseif (DateFormat::containsTime($this->saveFormat())) {
    $hasTime = true;                                                                                         
}
                                                                                                               
$carbon = $this->parseSavedToCarbon($value);                                                                 

if (! $hasTime) {                                                                                            
    $carbon = $carbon->startOfDay();
}                                                                                                            

return $carbon->utc();  // ? this is the problem                                                             

}

For a date-only value like 2026-03-14:

  1. parseSavedToCarbon() creates 2026-03-14 00:00:00 Europe/Rome
  2. startOfDay() keeps it at 2026-03-14 00:00:00 Europe/Rome
  3. ->utc() converts it to 2026-03-13 23:00:00 UTC

Then in preProcessIndex(), this gets serialized via ->toIso8601ZuluString('millisecond') as
2026-03-13T23:00:00.000Z.

The Vue component DateIndexFieldtype.vue passes this Zulu string to new Date(props.value.date), and
DateFormatter.js renders it using Intl.DateTimeFormat with the browser's locale ? which correctly interprets the
UTC timestamp but shows March 13 because the date was already shifted back by the UTC conversion.

Why the frontend works correctly

On the frontend (Blade/Antlers), dates go through a different code path. In our case, we use a display_date()
helper that calls ->setTimezone(Statamic::displayTimezone()) on the augmented Carbon value, which correctly
converts it back to Europe/Rome. The augment() method also works differently from preProcessIndex() ? it doesn't
lose the date-only semantic.

However, the CP collection table uses preProcessIndex() ? Zulu string ? JavaScript Date ? Intl.DateTimeFormat,
which has no awareness that this was originally a date-only value and should not be affected by timezone
conversion.

Expected behavior

Date-only fields (without time component) should display the same date in the CP collection table as the value
stored in the content file, regardless of the application timezone. A date like 2026-03-14 should always render
as March 14 in the table.

Suggested fix

When hasTime is false in parseSaved(), the UTC conversion should be skipped or the date should be normalized to
noon (12:00) before converting, to prevent the day from shifting across the midnight boundary:

if (! $hasTime) {
$carbon = $carbon->startOfDay()->setTime(12, 0);
}

return $carbon->utc();

Alternatively, preProcessIndex() could pass the raw date string (without UTC conversion) when time_enabled is
false, since the JavaScript side doesn't need timezone-aware rendering for date-only values.

How to reproduce

  1. Set the application timezone to any timezone ahead of UTC (e.g. Europe/Rome, Asia/Tokyo):
    APP_TIMEZONE=Europe/Rome
    // config/statamic/system.php
    'display_timezone' => 'Europe/Rome',
  2. Create a collection with a date field (time_enabled: false):
    handle: date
    field:
    type: date
    time_enabled: false
    format: Y-m-d
  3. Create an entry and set the date to any value (e.g. 2026-03-14)
  4. Open the collection listing in the Control Panel ? the date column shows 13/03/2026 instead of 14/03/2026
  5. Open the entry's publish form ? the date picker correctly shows 14/03/2026
  6. Render the date on the frontend (Antlers or Blade) ? it correctly shows 14/03/2026

Note: The issue only affects timezones ahead of UTC (positive offset). Timezones behind UTC (e.g.
America/New_York) would not exhibit this problem, since subtracting hours from midnight would still land on the
same calendar date or shift forward instead of backward.

Logs

Environment

Environment
Laravel Version: 13.2.0
PHP Version: 8.4.18
Composer Version: 2.9.5
Environment: local
Debug Mode: ENABLED
Maintenance Mode: OFF
Timezone: Europe/Rome
Locale: it

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: file
Database: mariadb
Logs: daily
Mail: smtp
Queue: database
Session: file

Storage
public/storage: LINKED

Sentry
Enabled: MISSING DSN
Environment: local
Laravel SDK Version: 4.24.0
PHP SDK Version: 4.23.1
Release: NOT SET
Sample Rate Errors: 100%
Sample Rate Performance Monitoring: NOT SET
Sample Rate Profiling: NOT SET
Send Default PII: DISABLED

Statamic
Addons: 4
Sites: 5 (Italiano, Inglese, Francese, Tedesco, Spagnolo)
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 6.8.0 PRO

Statamic Addons
rias/statamic-redirect: 4.1.7
statamic-rad-pack/runway: 9.3.2
statamic/eloquent-driver: 5.5.0
statamic/seo-pro: 7.3.0

Statamic Eloquent Driver
Addon Settings: file
Asset Containers: file
Assets: file
Blueprints: file
Collection Trees: file
Collections: file
Entries: file
Fieldsets: file
Form Submissions: eloquent
Forms: file
Global Sets: file
Global Variables: file
Navigation Trees: file
Navigations: file
Revisions: file
Sites: file
Taxonomies: file
Terms: file
Tokens: file

Installation

Starter Kit using via CLI

Additional details

I'm new to using github issues, so feel free to tell me if and where i'm wrong.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions