Search code examples
angularmomentjsmoment-timezone

Moment JS use in client only standard time regardless of the timezone


"angular": "12.2.0" "moment": "^2.30.1" "moment-timezone": "^0.5.44"

The project is a calendar scheduler.

Backend: C# sends UTC timestamp;

Frontend: In angular i use momentJS to process timestamp from server. The idea is to always have the times in standard time, because in this case there is winter (standard time) and summer (DST) time in eastern europe (of course in other places in the world too).

Example: when a user sets the start of a working day and the end of a working day -> from 10 to 18 (winter time, UTC+2), and then months pass and change to summer (DST, UTC+3) hours become -> from 11 to 19 hours. I want to prevent this time change.

How to always use only standard time, or what is the best approach of this case?

import { Injectable } from '@angular/core';
import * as moment from 'moment-timezone';

@Injectable({
    providedIn: 'root'
})
export class TimezoneService {
    // Method to parse the date to UTC+2
    public parseToUtcPlusTwo(date: Date | moment.Moment): moment.Moment {
        const utcMoment = moment.utc(date);
        const utcPlusTwo = moment.parseZone(utcMoment.format('YYYY-MM-DDTHH:mm:ss') + '+0200');
        return utcPlusTwo;
    }
}
import { Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment-timezone'; // Import moment-timezone
import { TimezoneService } from '../services/timezone.service';

@Pipe({
  name: 'utcToLocal'
})
export class UtcToLocalPipe implements PipeTransform {
  constructor(private timezoneService: TimezoneService) { }

  transform(utcDate: Date | moment.Moment, format: string = 'HH:mm'): string {
    const localMoment = this.timezoneService.parseToUtcPlusTwo(utcDate);

    return localMoment.isValid() ? localMoment.format(format) : '';
  }
}
@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent implements OnInit {
  ngOnInit(): void {
    const pipe = new UtcToLocalPipe(new TimezoneService());
    const format = 'YYYY-MM-DD HH:mm';

    // Winter Time (Standard Time) Test: January 15, 2023
    const winterTestDate = new Date('2023-01-15T10:00:00Z'); // 12:00 PM UTC
    console.log(pipe.transform(winterTestDate, format)); // Should output the date and time in UTC+2 (Standard Time)

    // Summer Time (Daylight Saving Time) Test: July 15, 2023
    const summerTestDate = new Date('2023-07-15T09:00:00Z'); // 12:00 PM UTC
    console.log(pipe.transform(summerTestDate, format)); // Should output the date and time in UTC+2 (Standard Time, despite being UTC+3 in reality)
}
}

Solution

  • I think utcOffset will work good for this scenario. Working example below!

    @Injectable({
      providedIn: 'root',
    })
    export class TimezoneService {
      // Method to parse the date to UTC+2
      public parseToUtcPlusTwo(date: Date | moment.Moment): moment.Moment {
        const utcMoment = moment.utc(date, true).tz("Europe/Sofia");
        return utcMoment;
      }
    }
    

    FULL CODE:

    import { Component } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import 'zone.js';
    
    import { Injectable } from '@angular/core';
    import * as moment from 'moment-timezone';
    import { Pipe, PipeTransform } from '@angular/core';
    
    @Injectable({
      providedIn: 'root',
    })
    export class TimezoneService {
      // Method to parse the date to UTC+2
      public parseToUtcPlusTwo(date: Date | moment.Moment): moment.Moment {
        const utcMoment = moment.utc(date, true).utcOffset(2);
        return utcMoment;
      }
    }
    
    @Pipe({
      name: 'utcToLocal',
      standalone: true,
    })
    export class UtcToLocalPipe implements PipeTransform {
      constructor(private timezoneService: TimezoneService) {}
    
      transform(utcDate: Date | moment.Moment, format: string = 'HH:mm'): string {
        const localMoment = this.timezoneService.parseToUtcPlusTwo(utcDate);
    
        return localMoment.isValid() ? localMoment.format(format) : '';
      }
    }
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [UtcToLocalPipe],
      template: ``,
    })
    export class App {
      ngOnInit(): void {
        const pipe = new UtcToLocalPipe(new TimezoneService());
        const format = 'YYYY-MM-DD HH:mm';
    
        // Winter Time (Standard Time) Test: January 15, 2023
        const winterTestDate = new Date('2023-01-15T10:00:00Z'); // 12:00 PM UTC
        console.log(pipe.transform(winterTestDate, format)); // Should output the date and time in UTC+2 (Standard Time)
        // Summer Time (Daylight Saving Time) Test: July 15, 2023
        const summerTestDate = new Date('2023-07-15T09:00:00Z'); // 12:00 PM UTC
        console.log(pipe.transform(summerTestDate, format)); // Should output the date and time in UTC+2 (Standard Time, despite being UTC+3 in reality)
      }
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo