Preserve named time zones when persisting ZonedDateTime in JSON
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 5/5
- Tempo estimado
- Mais de uma semana
- Facilidade para iniciantes
- 25/100
Direção de pesquisa
Start with TimestampTzZonedDateTimeMapping and the JSON reader/writer used in the repro, then inspect the prior implementation and tests at commit 817b4fff. First decide the persisted representation and compatibility policy, including existing data, query behavior, and precision; then trace JSON projections, predicates, recordset fields, collections, and containment. Done means named zones and offsets round-trip while existing deployments and query semantics are explicitly addressed.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Description
ZonedDateTime JSON currently stores the local date/time and UTC offset, but not the named time zone. A value in Europe/Berlin is therefore indistinguishable from a value in another zone with the same offset. Deserialization cannot recover the original zone identity or its daylight-saving rules.
Split out of #4021. That issue covers the reader throwing on the existing writer's nonzero-offset output; #4022 fixes that failure without changing the persisted format, returning a fixed-offset zone. This issue covers the separate capability of preserving the original named zone and is not fixed by #4022.
Minimal repro
Run this as a .NET 11 console application referencing src/EFCore.PG.NodaTime/EFCore.PG.NodaTime.csproj from this repository. No PostgreSQL server is required.
using System;
using NodaTime;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
var readerWriter = TimestampTzZonedDateTimeMapping.Default.JsonValueReaderWriter!;
foreach (var zoneId in new[] { "Europe/Berlin", "Europe/Paris" })
{
var value = new LocalDateTime(2018, 4, 20, 10, 31, 33)
.InZoneLeniently(DateTimeZoneProviders.Tzdb[zoneId]);
Console.WriteLine(value.Zone.Id);
Console.WriteLine(readerWriter.ToJsonString(value));
}
Both values produce the same JSON string (the plus sign may be JSON-escaped as \u002B):
Europe/Berlin
"2018-04-20T10:31:33+02"
Europe/Paris
"2018-04-20T10:31:33+02"
After the compatible reader fix in #4022, this representation can be read as a fixed-offset zone, but neither original zone ID can be recovered from it.
Desired behavior
Provide a way to persist and recover the original named zone for ZonedDateTime JSON values. Retain the explicit offset so ambiguous local times during a daylight-saving overlap can be disambiguated. This concerns JSON document round-tripping; PostgreSQL timestamptz columns do not preserve named zones.
Proposed approach and compatibility decisions
An earlier implementation in #4022 used a JSON-specific NodaTime pattern, ZonedDateTimePattern.ExtendedFormatOnlyIso.WithZoneProvider(DateTimeZoneProviders.Tzdb), producing text such as:
2018-04-20T10:31:33 Europe/Berlin (+02)
It was removed in commit 8681ae17 because it was not a backward-compatible bug fix. The proposed representation remains a candidate, not an approved design:
- Older providers cannot read the new output, even for UTC. A fallback in the new reader does not make mixed-version deployments or rollbacks safe. Decide whether this should be opt-in or a documented breaking change, and define existing-data/migration behavior.
- The zone-bearing string is not valid PostgreSQL
timestamptzinput. EF scalar JSON projections/predicates, typedjson[b]_to_recordsetfields, primitive collections, and representation-sensitive containment need deliberate query semantics. EF-only conversions would not repair application-written SQL, views, or indexes that cast the JSON text directly. - Keep SQL and embedded PostgreSQL literal formatting separate from JSON representation changes.
- The historical pattern also expanded precision from six fractional digits to nanoseconds. That expansion is not required for named-zone persistence and should be decided separately. PostgreSQL rounds to microseconds while Npgsql parameter encoding truncates toward the PostgreSQL epoch; blindly expanding precision can make equality predicates miss saved values.
- Clearly distinguish full-document named-zone round-tripping from scalar
timestamptzquery results, which retain instant/UTC semantics rather than named-zone identity.
Prior implementation
The complete reverted implementation and its tests can be inspected at 817b4fff. It added mapping-specific JSON extraction conversion, a query postprocessor, a containment optimization exclusion, and precision normalization. Those changes are historical reference, not a requirement to reintroduce that architecture. The follow-up should choose the simplest justified representation and compatibility policy before implementation.
- Linguagem predominante
- C#
- Estrelas
- 1.8k
- Forks
- 268
- Merge médio
- 2h 35min
- PRs com merge (30d)
- 136
Preparar o ambiente
Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de npgsql/efcore.pg
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
Mantenedores costumam responder em até 1 dia
-
NTS: the M ordinate is dropped from geometry SQL literals and from geometries stored in JSONTalvez já em andamento @Ahmed7991 assumiu há 5 dias. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 85/100
npgsql/efcore.pg#4093 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
`TimeSpan`/`Duration` component members: negative values are floored, and intervals computed in SQL are read field by fieldTalvez já em andamento @jeremy-morren assumiu há 11 dias. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
Mantenedores costumam responder em até 1 dia
-
Numeric storage parameters are formatted with the current culture, so migrations emit 0,01 instead of 0.01Talvez já em andamento @Sorbitol assumiu há 12 dias. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 30/100
Mantenedores costumam responder em até 1 dia
-
`Contains` on a JSON primitive collection compares JSON text, so `DateTime` and `TimeOnly` items never matchTalvez já em andamento @Mr444-dev assumiu há 7 dias. Aberta
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 45/100
npgsql/efcore.pg#4099 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
Todas as issues de npgsql/efcore.pg
Issues semelhantes
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
Mantenedores costumam responder em até 1 dia
-
[Feature]: Add Ukrainian (Українська) as a target language for the Translator (Ollama) engineAbertaenhancement
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 73/100
KnifeLemon/Filee#1344 ·
Mantenedores costumam responder em até 1 dia
-
Issue-Bug Needs-Triage
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
Mantenedores costumam responder em até 2 dias
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 66/100
JiaFeiMiao-K-Cat/DiscImageStudio#281 ·
Mantenedores costumam responder em até 1 dia
-
bug triage
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100