Read a post's date as the Berlin calendar day, not the raw UTC day

This commit is contained in:
tleininger committed 2026-09-24 09:11:37 +02:00
1 parent aef05fb090
commit 6d3260db49
6 files changed
+76 -8

No files matched your search

@@ -0,0 +1,44 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Elternbeirat.PocketBase;
/// <summary>
/// JSON converter that reads and writes a PocketBase date as a calendar date
/// (<see cref="DateOnly"/>), ignoring the time-of-day and the time zone.
/// </summary>
/// <remarks>
/// PocketBase has no date-only field type: it stores every date as a UTC
/// instant with a time-of-day (e.g. an editor's <c>2 Jan 00:00</c> Berlin is
/// stored as <c>"2026-01-01 22:00:00.000Z"</c>). The day the editor meant is
/// therefore the day <em>in Berlin</em>, not the day of the raw UTC string. This
/// converter reuses the same UTC-&gt;Berlin conversion as
/// <see cref="LocalDateTimeConverter"/> and then keeps only the date, so the day
/// shown is the day that was entered -- with no time-of-day and no off-by-one.
/// </remarks>
/// <remarks>
/// Registered on the client's <see cref="System.Text.Json.JsonSerializerOptions"/>
/// and matched by the <see cref="DateOnly"/> field type, so a contract needs no
/// per-field attribute (which would couple the contract to this project).
/// </remarks>
public sealed class DateOnlyConverter : JsonConverter<DateOnly>
{
/// <inheritdoc/>
/// <exception cref="FormatException">
/// The stored value is not a valid date string.
/// </exception>
public override DateOnly Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
=> WallClock.Parse(reader.GetString()) is { } berlin
? DateOnly.FromDateTime(berlin)
: default;
/// <inheritdoc/>
public override void Write(
Utf8JsonWriter writer,
DateOnly value,
JsonSerializerOptions options)
=> writer.WriteStringValue(WallClock.Format(value.ToDateTime(TimeOnly.MinValue)));
}
+3 -1
View File
@@ -83,7 +83,8 @@ public sealed class PocketBaseClient(HttpClient http)
=> GetRecordsAsync<Faq>("faqs", "topic", ct);
/// <summary>
/// Creates the serializer options with both wall-clock date converters registered.
/// Creates the serializer options with the date converters registered: the
/// wall-clock ones for points in time and the calendar-day one for plain dates.
/// </summary>
/// <returns>
/// The configured options.
@@ -96,6 +97,7 @@ public sealed class PocketBaseClient(HttpClient http)
};
options.Converters.Add(new LocalDateTimeConverter());
options.Converters.Add(new NullableLocalDateTimeConverter());
options.Converters.Add(new DateOnlyConverter());
return options;
}