Invariant datetime
The invariant datetime is a datetime that is always the same, regardless of the time zone or daylight saving time. It is used to represent a specific point in time and make sense only in a known location. This type of datetime is displayed in the same way in all time zones.
Warning
The invariant datetime is not a standard concept in programming. It is a term used in Neos to refer to a datetime that is always the same, regardless of the time zone or daylight saving time. This type of datetime should be used only when you not need to consider the time zone and you need to display the same datetime in different time zones.
Using in entity and entity view
To use the invariant datetime in an entity you need to define a property of type InvariantDateTime.
The .NET type of the property is a System.DateTime and the value is stored in the database like a DateTime but the value is not an UTC datetime.
When you handle an InvariantDateTime entity or entity view in your code, you should always consider that the value is not an UTC datetime, the DateTimeKind of the datetime instance is Unspecified.
For example if the value in database is 2024-01-01 12:00:00, the .NET datetime value is 2024-01-01 12:00:00 and the DateTimeKind is Unspecified.
Using in UI view
The invariant datetime is the same as the datetime in the entity or entity view and is not converted to the user's time zone.
For example if the value in database is 2024-01-01 12:00:00 the value of the UI view property is 2024-01-01 12:00:00 in the local time zone of the user, whatever the time zone of the user.
An invariant datetime is of type .NET DateTime in C# abstraction and of type Date in javascript.
Using in server methods
A server method's argument or return type does not have metadata to indicate that the datetime is an invariant datetime. So the argument or return type must be GroupeIsa.Neos.Shared.InvariantDateTime
Example of a method taking an invariant date/time as an argument:
public async Task ExecuteAsync(int id, GroupeIsa.Neos.Shared.InvariantDateTime invariantDateTime)
{
_transportEventRepository.Get(id).InvariantEventDate = invariantDateTime;
await _unitOfWork.SaveAsync();
}
Note
_transportEventRepository.Get(id).InvariantEventDate is a property of type System.DateTime the conversion from InvariantEventDate to DateTime is implicit
Example of a method returning an invariant datetime :
public GroupeIsa.Neos.Shared.InvariantDateTime Execute(int id)
{
return _transportEventRepository.Get(id).InvariantEventDate;
}
Note
_transportEventRepository.Get(id).InvariantEventDate is a property of type System.DateTime the conversion from DateTime to InvariantEventDate is implicit
Using in Data Object
To indicate that a property is an invariant datetime in a data object you need to use the GroupeIsa.Neos.Shared.InvariantDateTime type.
Consume Web API
JSON format
The invariant datetime is received with the format yyyy-MM-ddTHH:mm:ss and should be send with the same format.
Example :
{
"date": "2024-01-01T12:00:00"
}
OData format
The date in the OData filter must be in the format yyyy-MM-ddTHH:mm:ssZ the date should be send like a UTC datetime but without any conversion.
For example if the invariant date is 2024-01-01 12:00:00 the date in the OData filter should be 2024-01-01T12:00:00Z whatever the time zone of the client.
Under the hood
Entity and entity view
The invariant datetime is stored in the database as a datetime without any conversion.
An EF converter is used to convert the value from the database to a .NET DateTime with DateTimeKind Unspecified.
A InvariantDateTime value is serialized as a string in the format yyyy-MM-ddTHH:mm:ss without any time zone information and without the Z character to indicate that the datetime is UTC.
When the date is deserialized in the browser the value is converted to a javascript Date from the format yyyy-MM-ddTHH:mm:ss.
When the date is serialized in the browser the value is converted to a string in the format yyyy-MM-ddTHH:mm:ss without any time zone information, a json converter is used to deserialize the date on backend to a DateTime with DateTimeKind Unspecified.
sequenceDiagram
participant Database
participant EF Converter
participant Backend JSON Converter
participant Browser
Database->>EF Converter: Read datetime
Note over EF Converter: Convert to DateTime with DateTimeKind Unspecified
EF Converter->>Backend JSON Converter: Serialize DateTime
Note over Backend JSON Converter: Convert to string yyyy-MM-ddTHH:mm:ss
Backend JSON Converter->>Browser: Json Date (yyyy-MM-ddTHH:mm:ss)
Note over Browser: Convert yyyy-MM-ddTHH:mm:ss to Js Date
Browser->>Backend JSON Converter: Json Date (yyyy-MM-ddTHH:mm:ss)
Backend JSON Converter->>Database: DateTime
Server methods
The InvariantDateTime type is a wrapper around a DateTime value with DateTimeKind Unspecified with implicit conversion to/from DateTime.
A Json converter is used to serialize and deserialize the InvariantDateTime value in the server methods.
On browser the InvariantDateTime prototype inherits from Date.
When the InvariantDateTime value is serialized in the browser the value is converted to a string in the format yyyy-MM-ddTHH:mm:ss without any time zone information.
When a DateTime instance is assigned to a InvariantDateTime property or method argument, the DateTime value is converted to a InvariantDateTime value by the C# to typescript transpiler
The InvariantDateTime value is deserialized in the browser from a string in the format yyyy-MM-ddTHH:mm:ss into a Date instance.
sequenceDiagram
participant S as Backend Server
participant B as Web Browser
rect rgb(191, 223, 255)
note right of S: Backend serialization/deserialization.
S->>B: Serialize InvariantDateTime as yyyy-MM-ddTHH:mm:ss
note right of B: Instance of Date.
B->>S: Deserialize yyyy-MM-ddTHH:mm:ss as InvariantDateTime
end
rect rgb(191, 255, 191)
note left of B: Frontend serialization/deserialization.
S-->>B: Deserialize yyyy-MM-ddTHH:mm:ss as Date
note right of B: Instance of Date.
B->>B: Transpiler convert DateTime to InvariantDateTime
B->>S: Serialize InvariantDateTime as yyyy-MM-ddTHH:mm:ss
end
OData filter
In OData V4 the datetime format in filter must be in the format yyyy-MM-ddTHH:mm:ssZ. So the locale datetime is send like a UTC datetime without any conversion.