Search code examples
timestamptimestamp-with-timezonemoment-timezone

Get Timestamp of date In a different timezone


I need to get a timestamp of a date in a different time zone.

for example - now the timestamp (new Date().valueOf()) is:

1643530435160

in my timezone is (new Date(1643530435160)):

Sun Jan 30 2022 10:13:55 GMT+0200 (Israel Standard Time)

enter image description here

i need this date (10:13:55) but as timestamp but in a timestamp - so that means that i am looking for this timestamp:

1643555635000

enter image description here

so my solution for this is:

 export const getTimeStampOfDateInEnvTimeZone = (timeStamp:number, timezoneForTesting:string = null):number => {
    const envTimeZoneOffset = moment.tz.names()
        .filter((name: string) => name === (timezoneForTesting || EnvSelector.TIME_ZONE))
        .map((zone:string) => moment.tz(zone).format('Z'))[0];

    return new Date(`${new Date(timeStamp)} GMT${envTimeZoneOffset}`).valueOf();
};

and it looks like its working - BUT:

  1. I am not very happy to use moment and moment-timezone because they should be deprecated soon.
  2. looks like this code work perfectly locally - I tried from the browser, from postman, and with unit tests - but in prod - we having some issues with this code and we do not get the expected result every time.

so I am thinking probably we have this issue with this code because of the different time zone on AWS remote servers or something like this?

looking for a better solution to this - thanks!


Solution

  • I am sure that there is a simpler way to do that, but the only way I found, without moment and moment-timezone, is:

    first get the time zone offset is units (based on this answer):

    const getTimeZoneOffset = (date, timeZone) => {
    
       // Abuse the Intl API to get a local ISO 8601 string for a given time zone.
       const options = {
           timeZone, calendar: 'iso8601', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false,
    };
      // @ts-ignore
      const dateTimeFormat = new Intl.DateTimeFormat(undefined, options);
      const parts = dateTimeFormat.formatToParts(date);
      const map = new Map(parts.map((x) => [x.type, x.value]));
      const year = map.get('year');
      const month = map.get('month');
      const day = map.get('day');
      const hour = map.get('hour');
      const minute = map.get('minute');
      const second = map.get('second');
      const ms = date.getMilliseconds().toString().padStart(3, '0');
      const iso = `${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}`;
    
      // Lie to the Date object constructor that it's a UTC time.
      const lie = new Date(`${iso}Z`);
    
      // Return the difference in timestamps, as minutes
      // Positive values are West of GMT, opposite of ISO 8601
      // this matches the output of `Date.getTimeZoneOffset`
      // @ts-ignore
      return -(lie - date) / 60 / 1000;
    };
    

    and than:

    export const getTimeStampOfDateInEnvTimeZone = (timeStamp:number, userTimezone: string, timezoneForTesting:string = null) => {
    
       const envTimeZoneOffsetInMinutes = getTimeZoneOffset(new Date(timeStamp), timezoneForTesting || EnvSelector.TIME_ZONE);
       const userTimeZoneOffsetInMInutes = getTimeZoneOffset(new Date(timeStamp), userTimezone);
       const difference = userTimeZoneOffsetInMInutes - envTimeZoneOffsetInMinutes;
       const diffInMilliseconds = difference * 60000;
       return timeStamp - diffInMilliseconds;
    
    };
    

    those are unit tests to verify this code:

    describe('test getTimeStampOfDateInEnvTimeZone method', () => {
    it('should verify that is we get the correct ts when user is in "Asia/Jerusalem" tz of and env is in "America/New_York" time zone', () => {
        expect.hasAssertions();
        expect(getTimeStampOfDateInEnvTimeZone(1643530435160, 'Asia/Jerusalem', 'America/New_York')).toBe(1643555635160);
    });
    
    it('should verify that is we get the correct ts when user is in "Asia/Jerusalem" tz of and env is in "America/Santa_Isabel" time zone', () => {
        expect.hasAssertions();
        expect(getTimeStampOfDateInEnvTimeZone(1643303881092, 'Asia/Jerusalem', 'America/Santa_Isabel')).toBe(1643339881092);
    });
    
    it('should verify that is we get the correct ts when user is in "America/New_York" tz of and env is in "Asia/Jerusalem" time zone', () => {
        expect.hasAssertions();
        expect(getTimeStampOfDateInEnvTimeZone(1643555635160, 'America/New_York', 'Asia/Jerusalem')).toBe(1643530435160);
    });
    
    it('should verify that is we get the correct ts when user is in "America/Santa_Isabel" tz of and env is in "Asia/Jerusalem" time zone', () => {
        expect.hasAssertions();
        expect(getTimeStampOfDateInEnvTimeZone(1643339881092, 'America/Santa_Isabel', 'Asia/Jerusalem')).toBe(1643303881092);
    });
    
    it('should verify that is we get the correct ts when user is in "America/Santa_Isabel" tz of and env is in "America/Santa_Isabel" time zone', () => {
        expect.hasAssertions();
        expect(getTimeStampOfDateInEnvTimeZone(1643339881092, 'America/Santa_Isabel', 'America/Santa_Isabel')).toBe(1643339881092);
    });
    
    it('should verify that is we get the correct ts when user is in "Africa/Douala" tz of and env is in "Pacific/Tahiti" time zone', () => {
        expect.hasAssertions();
        expect(getTimeStampOfDateInEnvTimeZone(1643808653000, 'Africa/Douala', 'Pacific/Tahiti')).toBe(1643848253000);
    });
    
    it('should verify that is we get the correct ts when user is in "Pacific/Tahiti" tz of and env is in "Africa/Douala" time zone', () => {
        expect.hasAssertions();
        expect(getTimeStampOfDateInEnvTimeZone(1643555635000, 'Pacific/Tahiti', 'Africa/Douala')).toBe(1643516035000);
    });
    });