When an application includes a timestamp, it's usually reading it from the current machine. If you're in New York, the timestamp is EST; if you're in California, it's Pacific time. In some cases, though, you'll need the app to be consistent with the server time, so that it's consistent everywhere around the world. For example, if you're scheduling a one-day sale, you may want to ensure that the time is static for one time zone; otherwise users will be able to access the sale in their own time zone across the globe.
This post looks at how to maintain a consistent, server-based timestamp in ASP.NET MVC web apps using JSON text. As we know, text is used for transferring data between the server and the client. We always use the text in JSON format.
Json.NET is a popular high-performance JSON framework for .NET to serialize the data into text in JSON format and read the data from a JSON format text. It's used by default for JSON serialization in ASP.NET MVC 6 and ASP.NET Web API.
Before an object is transferred to the client, it has to be serialized into JSON text, which will then be parsed into a client object on the client side.
For a DateTime object with different Kinds, it has to be serialized into different texts with Json.NET:
Server (+07:00) | Serialization Text | Client (+08.00) |
---|---|---|
2017/1/25 07:00:00 (DateTimeKind.Unspecified) | "2017-01-25T07:00:00" | 2017/1/25 07:00:00 |
2017/1/25 07:00:00 (DateTimeKind.Utc) | "2017-01-25T07:00:00Z" | 2017/1/25 15:00:00 |
2017/1/25 07:00:00 (DateTimeKind.Local) | "2017-01-25T07:00:00+07:00:00" | 2017/1/25 08:00:00 |
In this example, the serialization text keeps the original date and time text, and ends with the time zone, including all the information about the server DateTime object. Using new Date([serialization text]), we can then parse the serialization text into the client object.
However, the Client column shows that only the Unspecified DateTime object keeps the same date and time text as the server. Both the UTC DateTime and the Local objects have different string representations, and they even show different texts in machines with different time zones.
Before a client object is transferred to the server, it has to be serialized into a text; then, on the server, the text is deserialized into an object. A text with the following formats could be deserialized into the corresponding DateTime object by Json.NET:
Serialization Text | The DateTime object |
---|---|
"2017-01-25T07:00:00Z" | 2017/1/25 O7:00:00(DateKind.Utc) |
"2017-01-25T07:00:00+07:00" | 2017/1/25 07:00:00(DateTimeKind.Local) |
"2017-01-25T07:00:00" | 2017/1/25 07:00:00(DateTimeKind.Unspecified) |
Looking at the table above, we can follow three guidelines:
For some applications, the user only focuses on the date and the time without the time zone for the Date field. In other words, the user wants the application to reflect the server’s date and time, instead of whatever time zone they’re in. So how do we make this happen?
If we want to keep the date and the time the same for both the server and client, we need to apply transformations in two parts:
For the UTC format DateTime object, the client Date object will be generated with this code:
new Date("2017-01-25T07:00:00Z");
The object shows different texts from the server. If we remove the time zone text from the serialization text, and use that text to generate a client local Date object, the date and time match the server, which solves the problem about the client Date text.
new Date("2017-01-25T07:00:00");
Now we'll let the server get the same Kind and correct DateTime object after the previous transformation is complete. (Without the previous transformation, the server gets the wrong DateTime object.)
After the transformation from the client to the server, get a client local Date object:
2017/01/25 7:00(+08:00).
Serialize the local Date object into the following text by the JSON.stringify() method:
2017-01-24T23:00:00Z
After deserialization, we'll get the server DateTime object:
2017/01/24 23:00(Utc).
However, we see that the object has changed and different from its original value (2017/01/25 7:00(Utc)), which means it's incorrect.
If we add a customization on the serialization of the client object to get the following text, we get the correct DateTime object in the server:
2017-01-25T07:00:00Z,
We can make these transformations on the server or client side, which offers two possible solutions:
The Unspecified DateTime can keep the date and the time, so we can convert all the DateTime objects on the server to Unspecified and convert them back when necessary.
The DateTimeFields sample shows you how to make these transformations. Get the sample.
Although it seems like a simple solution, we need to pay close attention to the conversions and not miss any transformations. Otherwise, there could be an unexpected problem.
On the client side, we need to customize the parsing for the Date text and the serialization for the client Date object. Our MVC components provide two client events that support these transformations: OnClientReponseTextParsing and OnClientRequestDataStringifying.
1) OnClientReponseTextParsing
This event, which is fired when parsing the JSON text, allows us to customize the parsing to generate the desired client Date object.
We can get following information from the event argument:
2) OnClientRequestDataStringifying
This event is fired when we serialize the client object into the text; it's then sent to the server and deserialized into the server object. In this event, we can customize the serialization and generate the text with the appropriate format.
We can get following information from the event argument:
This solution is easier for the user. They only need to focus on these two events and make the transformations in the events.
The DateTimeFields sample also shows how to make transformations this way. Get the sample.