- Backend sends all data in UTC, and accepts data in LOCAL client timezones.
- The frontend could send dates to backend either:
- in UTC (that's what JS does by default)
- in local client timezone with timezone specified, e.g. '2023-04-28T02:02:41.605+07:00' (that's what we do in our frontend by overriding
Date.prototype.toISOString =
in index.tsx)
- Database - all values are in UTC.
- Backend - all values are in UTC.
- Client - all values are in LOCAL timezone (converted from UTC automatically on deserialization. when serializing - no conversion to UTC is made).
We only use DateTime class on backend (never use DateTimeOffset).
This aligns with recommendations npgsql/npgsql#2209 (comment)
Working with timezone-aware databases is a headache. Whenever possible, we recommend that users go
turtlesUTC all the way down. That is, only convert from/to local time when displaying to a human user.
- Use
DateOnly
if you want to store only the dates (independent of the TimeZone). - Use
DateTime
if you want to store Date with Time. It will be always in UTC on backend. - Never use
DateTimeOffset
.
- Client need to send the datetime using local timezone, i.e.
2021-01-23T17:30:00+07:00
should be sent over http. - Backend upon deserialization will convert the date to UTC. I.e. on backend it will be
2021-01-23T10:30:00
. Since we useDateTime
(notDateTimeOffset
) no timezone is specified. All values on backend are in UTC. - In GET requests the server sends values in UTC, i.e. the following will be sent:
2021-01-23T10:30:00+00:00
. Client will know it's UTC (by the trailing+00:00
) and will convert it to local time,2021-01-23T17:30:00+07:00
.
If certain property contains only Date (without time), e.g. BirthDate
, it must be of DateOnly
type. In this case everything is handled automatically (by DateOnlyConverter
s and autogenerated clients). DateOnly
fields are serialized as yyyy-MM-dd
(both from Frontend and Backend side).
We do NOT use DateTimeOffset at all.
PostgreSQL doesn't store timezone offset, and Npgsql requires that all DateTimeOffset have Zero offset (otherwise it throws an exception upon saving). So, if you always have to use Zero offset, using DateTimeOffset
type doesn't make any sense and only brings confusion (because it seems like you could use different time zones, while in reality you could not).