Stopwatch data should include timezone data, to ensure the originating timezone can be tracked. If a stopwatch has a valid timezone/timezoneOffset value, the stopwatch data will be rendered in that timezone.
Store all stopwatch values as timezone-aware dates:
class TZDate {
private utcTimestamp: number; // Milliseconds since Unix epoch in UTC
private timezone: string;
private timezoneOffset: number;
constructor(utcTimestamp: number, timezoneOffset: number | null, timezone: string | null) {
this.utcTimestamp = utcTimestamp;
this.timezoneOffset = timezoneOffset || (new Date).getTimezoneOffset();
this.timezone = timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
}
toOriginalDate(): Date {
var date = new Date(this.utcTimestamp),
utcMinutes = date.getUTCHours() * 60 + date.getUTCMinutes(),
localMinutes = (utcMinutes + this.timezoneOffset + 1440) % 1440;
date.setUTCHours(Math.floor(localMinutes / 60), localMinutes % 60);
return date;
}
toLocalDate(): Date {
return new Date(this.utcTimestamp);
}
static now(): TZDate {
var now: number = Date.now(),
timezoneOffset = (new Date).getTimezoneOffset(),
timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
return new TZDate(now, timezoneOffset, timezone);
}
}
interface CreationModificationDates {
readonly createdAt: TZDate;
lastModified: TZDate | null;
}
interface StopWatchMetadata {
readonly createdAt: TZDate;
startedAt: TZDate | null;
stoppedAt: TZDate | null;
resumedAt: TZDate | null;
resetAt: TZDate | null;
lastModified: TZDate | null;
}
class Split {
public value: TZDate;
public metadata: CreationModificationDates;
constructor(value: number, metadata: CreationModificationDates) {
this.value = value;
this.metadata = metadata;
}
}
Stopwatch data should include timezone data, to ensure the originating timezone can be tracked. If a stopwatch has a valid
timezone/timezoneOffsetvalue, the stopwatch data will be rendered in that timezone.Store all stopwatch values as timezone-aware dates: