<!DOCTYPE html>
<html>
<head>
<script src="./lib/main.ts"></script>
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
//our root app component
import { Component, NgModule, VERSION } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { DateTime } from "luxon";
@Component({
selector: 'my-app',
template: `
<div>
<h1>{{ timezone }}</h1>
<table>
<thead>
<tr>
<th>Day</th>
<th>Start</th>
<th>Start(UTC)</th>
<th>Minutes</th>
<th>End</th>
<th>End(UTC)</th>
<th>DST</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let range of ranges'>
<td>{{ range.day }}</td>
<td>{{ range.start }}</td>
<td>{{ toUTC(range.day, range.start) }}</td>
<td>{{ getDiff(range) }}</td>
<td>{{ range.end }}</td>
<td>{{ toUTC(range.day, range.end) }}</td>
<td>{{ getTimeChangeMessage(range) }}</td>
</tr>
</tbody>
</table>
</div>
`,
})
export class App {
timezone: string;
ranges = [
{ 'day': '2025-03-09', 'start': '00:00', 'end': '04:00' },
{ 'day': '2025-03-09', 'start': '01:59', 'end': '04:00' },
{ 'day': '2025-03-09', 'start': '02:00', 'end': '04:00' },
{ 'day': '2025-03-09', 'start': '02:01', 'end': '04:00' },
{ 'day': '2025-03-09', 'start': '02:59', 'end': '04:00' },
{ 'day': '2025-03-09', 'start': '03:00', 'end': '04:00' },
{ 'day': '2025-03-09', 'start': '03:01', 'end': '04:00' },
{ 'day': '2025-03-09', 'start': '01:59', 'end': '02:00' },
{ 'day': '2025-03-09', 'start': '01:59', 'end': '02:01' },
{ 'day': '2025-03-09', 'start': '01:59', 'end': '02:59' },
{ 'day': '2025-03-09', 'start': '01:59', 'end': '03:00' },
{ 'day': '2025-03-09', 'start': '01:59', 'end': '03:01' },
{ 'day': '2025-03-09', 'start': '02:00', 'end': '02:01' },
{ 'day': '2025-03-09', 'start': '02:00', 'end': '02:59' },
{ 'day': '2025-03-09', 'start': '02:00', 'end': '03:00' },
{ 'day': '2025-03-09', 'start': '02:00', 'end': '03:01' },
{ 'day': '2025-03-09', 'start': '02:01', 'end': '02:59' },
{ 'day': '2025-03-09', 'start': '02:01', 'end': '03:00' },
{ 'day': '2025-03-09', 'start': '02:01', 'end': '03:01' },
{ 'day': '2025-03-09', 'start': '02:59', 'end': '03:00' },
{ 'day': '2025-03-09', 'start': '02:59', 'end': '03:01' },
{ 'day': '2025-03-09', 'start': '03:00', 'end': '03:01' },
{ 'day': '2025-03-09', 'start': '00:00', 'end': '01:59' },
{ 'day': '2025-03-09', 'start': '00:00', 'end': '02:00' },
{ 'day': '2025-03-09', 'start': '00:00', 'end': '02:01' },
{ 'day': '2025-03-09', 'start': '00:00', 'end': '02:59' },
{ 'day': '2025-03-09', 'start': '00:00', 'end': '03:00' },
{ 'day': '2025-03-09', 'start': '00:00', 'end': '03:01' },
{ 'day': '2025-03-09', 'start': '00:00', 'end': '04:00' },
{ 'day': '2025-11-02', 'start': '00:00', 'end': '03:00' },
{ 'day': '2025-11-02', 'start': '00:59', 'end': '03:00' },
{ 'day': '2025-11-02', 'start': '01:00', 'end': '03:00' },
{ 'day': '2025-11-02', 'start': '01:01', 'end': '03:00' },
{ 'day': '2025-11-02', 'start': '01:59', 'end': '03:00' },
{ 'day': '2025-11-02', 'start': '02:00', 'end': '03:00' },
{ 'day': '2025-11-02', 'start': '02:01', 'end': '03:00' },
{ 'day': '2025-11-02', 'start': '00:59', 'end': '01:00' },
{ 'day': '2025-11-02', 'start': '00:59', 'end': '01:01' },
{ 'day': '2025-11-02', 'start': '00:59', 'end': '01:59' },
{ 'day': '2025-11-02', 'start': '00:59', 'end': '02:00' },
{ 'day': '2025-11-02', 'start': '00:59', 'end': '02:01' },
{ 'day': '2025-11-02', 'start': '01:00', 'end': '01:01' },
{ 'day': '2025-11-02', 'start': '01:00', 'end': '01:59' },
{ 'day': '2025-11-02', 'start': '01:00', 'end': '02:00' },
{ 'day': '2025-11-02', 'start': '01:00', 'end': '02:01' },
{ 'day': '2025-11-02', 'start': '01:01', 'end': '01:59' },
{ 'day': '2025-11-02', 'start': '01:01', 'end': '02:00' },
{ 'day': '2025-11-02', 'start': '01:01', 'end': '02:01' },
{ 'day': '2025-11-02', 'start': '01:59', 'end': '02:00' },
{ 'day': '2025-11-02', 'start': '01:59', 'end': '02:01' },
{ 'day': '2025-11-02', 'start': '02:00', 'end': '02:01' },
{ 'day': '2025-11-02', 'start': '00:00', 'end': '00:59' },
{ 'day': '2025-11-02', 'start': '00:00', 'end': '01:00' },
{ 'day': '2025-11-02', 'start': '00:00', 'end': '01:01' },
{ 'day': '2025-11-02', 'start': '00:00', 'end': '01:59' },
{ 'day': '2025-11-02', 'start': '00:00', 'end': '02:00' },
{ 'day': '2025-11-02', 'start': '00:00', 'end': '02:01' }
];
constructor() {
}
ngOnInit() {
this.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
}
formatDate(date:string): string {
return (date.replace('T', ' ').replace(new RegExp(':00$'), '').replace(new RegExp(':00.000Z$'), ''));
}
getDiff(range:any): boolean {
const startDateTime = DateTime.fromISO(`${range.day}T${range.start}:00`, {zone: this.timezone});
const endDateTime = DateTime.fromISO(`${range.day}T${range.end}:00`, {zone: this.timezone});
return endDateTime.diff(startDateTime, 'minutes').minutes;
}
getTimeChangeMessage(range:any): string {
let ret = '';
const startDateTime = DateTime.fromISO(`${range.day}T${range.start}:00`, {zone: this.timezone});
const endDateTime = DateTime.fromISO(`${range.day}T${range.end}:00`, {zone: this.timezone});
if (startDateTime.offset == endDateTime.offset) {
ret = 'No time change';
} else if (startDateTime.offset < endDateTime.offset){
ret = 'Spring forward';
} else {
ret = 'Fall back';
}
return ret;
}
toUTC(day:string, time:string): string {
const dateTime = DateTime.fromISO(`${day}T${time}:00`, {zone: this.timezone});
return dateTime.toUTC().toFormat('HH:mm');
}
}
@NgModule({
imports: [BrowserModule],
declarations: [App],
bootstrap: [App],
})
export class AppModule {}
// Shim the environment
import 'core-js/client/shim';
// Angular requires Zones to be pre-configured in the environment
import 'zone.js/dist/zone';
//main entry point
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app';
import './style.css';
platformBrowserDynamic().bootstrapModule(AppModule);
h1,
p {
font-family: sans-serif;
}
table, th, td {
border: 1px solid;
}
{
"name": "@plnkr/starter-angular",
"version": "1.0.3",
"description": "Angular starter template",
"dependencies": {
"@angular/common": "^8.2.14",
"@angular/compiler": "^8.2.14",
"@angular/core": "^8.2.14",
"@angular/platform-browser": "^8.2.14",
"@angular/platform-browser-dynamic": "^8.2.14",
"core-js": "2.6.11",
"rxjs": "6.5.4",
"zone.js": "0.10.2",
"luxon": "3.6.1"
},
"main": "./lib/main.ts",
"plnkr": {
"runtime": "system",
"useHotReload": true
}
}
{
"compilerOptions": {
"experimentalDecorators": true
}
}