date-fns-tz
                                
                                
                                
                                    date-fns-tz copied to clipboard
                            
                            
                            
                        Unreliable conversions with zonedTimeToUtc
zonedTimeToUtc
Sun Jul 09 2022 21:00:00 GMT+0000 <- input
Sat Jul 09 2022 14:00:00 GMT+0000 <- output
10 'Australia/Melbourne' getTimezoneOffset 
That is a difference of 7 hours.
Where do these wide swings come from?
Agree. Also for me, JEST fails at the second line, a proof for this issue:
expect(getTimezoneOffset('Asia/Jerusalem', new Date('1995-12-17T03:23:00Z'))).toBe(2 * 60 * 60 * 1000);
expect(zonedTimeToUtc(new Date('1995-12-17T03:23:00Z'), 'Asia/Jerusalem')).not.toEqual(new Date('1995-12-17T03:23:00Z'));
                                    
                                    
                                    
                                
As a temporary fix, here is my implementation to these function, using the offset function of this library:
import { getTimezoneOffset } from 'date-fns-tz';
export function utcToZonedTime(date: Date | number, timeZone: string) {
	const offset = getTimezoneOffset(timeZone, date);
	return new Date(date.valueOf() + offset);
}
export function zonedTimeToUtc(date: Date | number, timeZone: string) {
	const offset = getTimezoneOffset(timeZone, date);
	return new Date(date.valueOf() - offset);
}
It passes the following Jest test:
test('check the alternative self implemented `utcToZonedTime` and `zonedTimeToUtc`', () => {
	expect(getTimezoneOffset('Asia/Jerusalem', new Date('1995-12-17T03:23:00Z'))).toBe(2 * 60 * 60 * 1000);
	expect(utcToZonedTime(new Date('2022-07-27T18:11:40Z'), 'Asia/Jerusalem')).toEqual(new Date('2022-07-27T21:11:40Z'));
	expect(zonedTimeToUtc(new Date('2022-07-27T21:11:40Z'), 'Asia/Jerusalem')).toEqual(new Date('2022-07-27T18:11:40Z'));
});
                                    
                                    
                                    
                                
Yeah, I'm having odd behaviour where this behaviours perfectly in Jest, but as soon as I run it in the the browser it just turns things into UTC time.
eg code:
    const date = {
        day: 2, 
        monthIndex: 7, 
        fullYear: 2022
    }; 
    const tz = "Australia/Melbourne"; 
    
    const utcDate = new Date(Date.UTC(date.fullYear, date.monthIndex, date.day, 0,0)); 
    const tzDate = zonedTimeToUtc(utcDate, tz);
    const rString = tzDate.toISOString(); 
    console.log({date, tz, rString}); 
Jest output:
    {
      date: { fullYear: 2022, monthIndex: 7, day: 2 },
      tz: 'Australia/Melbourne',
      rString: '2022-08-01T14:00:00.000Z'
    }
Browser output: (Locale is Melbourne)
{
    "date": {
        "day": 2,
        "monthIndex": 7,
        "fullYear": 2022
    },
    "tz": "Australia/Melbourne",
    "rString": "2022-08-02T00:00:00.000Z"
}
                                    
                                    
                                    
                                
Seeing same, @Tal500 workaround fixed it 🙏🏻
Remember that with this library you should never be looking at the UTC time stored within a date. The idea is to have the "local" values of the date be "wrong" in the sense that it shows the time in the target time zone instead of the system local time zone. To accomplish that, the internal UTC time of the date is changed.
I didn't follow everything happening here with a quick read, but one problem that caught my eye is this:
const utcDate = new Date(Date.UTC(date.fullYear, date.monthIndex, date.day, 0,0)); 
const tzDate = zonedTimeToUtc(utcDate, tz);
This is just wrong. You should be using const zonedDate = utcToZonedTime(utcDate, tz). If you do that and then format the output you should see whatever UTC time you've put in printed in the local time of tz.
The only time you'd really use zonedTimeToUtc would be if a user entered a date which represents a time in a time zone other than their system time zone. Then you need this function to convert that date to the proper UTC time of the user's intended date. But in the example above you have a proper UTC time to start with, so there is no need to ever convert it unless it will be shown in the UI.