-
Notifications
You must be signed in to change notification settings - Fork 10.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[12.x] fix: update postgres grammar date format #51363
base: master
Are you sure you want to change the base?
Conversation
72d3ec3
to
567bc3f
Compare
Can we make this change on a patch release? Seems breaking? |
Postgres only converts the datetime to UTC when the field contains a timezone (e.g.,
Thus, the conversion should only affect fields with timezones, which if people are using then they would already have to be manually converting the Carbon instances to UTC or their datetimes would be incorrect. Also, if the timestamp precision is not 6, then Postgres will round up the microseconds (per typical rounding rules) to the appropriate precision:
This should be fine in Production, however, this might cause some tests to fail by a second difference if they're, say, comparing a I suppose to be on the safe side it would be better to merge to 12.x. |
I also think the best is to target this at 12.x |
567bc3f
to
e5373fb
Compare
Updated target to 12.x |
Make sure to mark this PR as ready if you need another review. |
I encountered the issue before too but changing it by default resulted in bc breaks in edge cases. As microseconds and timezones are not used often, I am not sure whether we should complicate it. Especially as MySQL and PostgreSQL will then from now on (with default settings) behave differently. I solved this in my extended PostgreSQL driver by using traits which is an easy thing to implement. So anyone departing from the default can change the model. But I personally would like to not add more behavioural differences between using MySQL and PostgreSQL. |
I understand your concern, but I believe that the benefits far outweigh the cons, improve the developer experience, and reduce the potential for developer mistakes. Current ProblemAs it currently stands, passing a string to Eloquent / QueryBuilder works exactly as expected, but passing a Carbon instance truncates the microseconds and timezone information causing serious data integrity issues. The Carbon instance contains all the information needed to fully define that timestamp---I should not lose information or wind up with an incorrectly serialized string when I pass a Carbon instance to Eloquent / QueryBuilder. I also should not experience different behaviour between passing a Carbon instance and passing an equivalent timestamp string. Postgres Rounding Issue
You don't elaborate on what these edge cases are, but I suspect that you are referring to Postgres rounding the microseconds when using a non-default precision. I just updated our enterprise application to override the Postgres Grammar Automatic Timezone ConversionThe main driver behind this push was to ensure that all timestamps are consistently handled and converted to UTC by the framework/database (and not by the developer) before being persisted or queried. Keep in mind that the Postgres Before this, we had simply defaulted to Moving all timestamps to Additional Thoughts
That may be so, but they are used and it is worth the effort to ensure that they are handled correctly and consistently. I firmly believe that when using Postgres all timestamps should be
I took a look at your traits, and you only override the Model
Postgres and MySQL are different, and we should leverage these differences to their strengths rather than trying to find a poor middle ground. ConclusionBy unilaterally adopting
The proposed change:
Timestamp Conversion QueryFor anyone who is interested, here is the query I used to convert all timestamps across the board: Note that we only use the <?php
$columns = DB::select(<<<'SQL'
SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND data_type IN ('timestamp without time zone', 'timestamp with time zone');
SQL);
collect($columns)
->groupBy('table_name')
->each(function ($columns, $table): void {
$alterStatement = collect($columns)
->map(fn ($column) => <<<SQL
ALTER COLUMN {$column->column_name} SET DATA TYPE timestamp(6) with time zone
SQL)
->join(', ');
DB::statement(<<<SQL
ALTER TABLE public.{$table}
{$alterStatement};
SQL);
}); |
Hello!
PostgreSQL supports
time[stamp] with time zone
fields with a resolution of 1 microsecond. However, the default grammar date format isY-m-d H:i:s
which truncatesDateTimeInterface
objects that are passed to queries.This results in invalid queries and records being saved to / returned from the database. For example:
This PR updates the PostgresGrammar date format to prevent the lose of information:
Thanks!