Hi there, in the big application that supports user from multiple countries should always have the support for selecting timezone and even their locale somewhere. In Zyllem, as the SaaS company, this feature has been embedded inside the product since day 1.
What we have applied so far is to follow the best practice to store UTC date/times in our database and display to the user in their local timezone. We’ll also store the time zone rather than the offset so we can support daylight savings time. In the post, I’ll only cover how we display the date in the correct timezone as the server deliver the result via an API and we have the client app to consume it.
As described in the timezone tag wiki, there are two different styles of time zones.
Those provided by Microsoft for use with Windows and the .Net TimeZoneInfo class are identified by a value such as Singapore Standard Time
.
Those provided by IANA in the TZDB are identified by a value such as Asia/Singapore
.
I did a quick test with Moment timezone, and basically most client-side library using standard IANA time zones. Refer to the resource below.
Completed IANA timezone list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
Completed Microsoft timezone list: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones
Client library the support IANA: https://stackoverflow.com/a/15171030/3375906
Which is very different from our technology since we are using Microsoft and it come with their timezone (Microsoft’s one).
Server converts the timezone into IANA format and sends it to client using API. It doesn’t sound convenience because, with every single Date object, we need to include another string property as a timezone, and the string is big. E.g Singapore Standard Time
Server converts the time into ISO 8601 format. Then the client will to parse it and display.
ISO 8601 meaning it should always include either a Z (for UTC values)
, or an offset (for local values)
. Therefore, you may take the user’s time zone into account, but the result you deliver should include the local offset so it is unambiguous.
For example, you have the UTC value 2018-04-28T03:00:00.00Z
, then in Asia/Singapore
it should be 2018-04-28T11:00:00.00+08:00
. And that’s what should be delivered over the API.
On the client-side, you can render that value for the user with a library like moment.js. For example:
var string = moment.parseZone('2018-04-28T11:00:00.00+08:00').format('LLL')
See more about localized format at https://momentjs.com/docs/#/displaying/format/.
So that we write a class to also handle both the locale and timezone. Basically, it will extract the locale from browser and display accordingly. For the getSafe function, refer to my previous post here
timezone.ts
import { getSafe } from "./utils";
import * as moment from "moment";
export const DEFAULT_FORMAT = "DD MMM YYYY, HH:mm";
export const NUMERAL_DATE_TIME_ZONE_FORMAT = "L LT";
export const NAME_DATE_TIME_ZONE_FORMAT = "ll LT";
export const NAME_DATE_ONLY_ZONE_FORMAT = "ll";
export const NAME_DATE_TIME_ZONE_FULL_FORMAT = "llll";
export const TIME_ONLY_FORMAT = "LT";
export class MomentTimezone {
private static momentLocale: string;
private static setLocale() {
if(!this.momentLocale) {
this.momentLocale = getSafe(() => navigator.languages[0]) || navigator.language;
moment.locale(this.momentLocale);
}
}
//input format "2018-04-28T11:00:00.00+08:00"
public static formatDateInTimeZone(input: string): string {
this.setLocale();
return moment.parseZone(input).format(this.momentLocale ? NUMERAL_DATE_TIME_ZONE_FORMAT : DEFAULT_FORMAT)
}
public static parseDateInTimeZone(input) {
this.setLocale();
return moment.parseZone(input);
}
}
So If I configure the browser language in Chinese, it will also display in the correct locale as well.