<!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
  }
}