From da8c27863cf8c6e633eb55686d4556f045fc35be Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Fri, 15 Nov 2024 15:35:55 +0100 Subject: [PATCH] fix zones --- hogvm/__tests__/__snapshots__/date.js | 31 ++++++++++++------------ posthog/hogql/compiler/javascript_stl.py | 31 ++++++++++++------------ 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/hogvm/__tests__/__snapshots__/date.js b/hogvm/__tests__/__snapshots__/date.js index 66b2b87239e78..71af223af0e56 100644 --- a/hogvm/__tests__/__snapshots__/date.js +++ b/hogvm/__tests__/__snapshots__/date.js @@ -81,8 +81,8 @@ function __escapeIdentifier(identifier) { } function __isHogDateTime(obj) { return obj && obj.__hogDateTime__ === true } function __isHogDate(obj) { return obj && obj.__hogDate__ === true } -function __DateTimeToString (dt) { - if (__isHogDateTime(dt)) { +function __DateTimeToString(dt) { + if (__isHogDateTime(dt)) { const date = new Date(dt.dt * 1000); const timeZone = dt.zone || 'UTC'; const milliseconds = Math.floor(dt.dt * 1000 % 1000); @@ -101,25 +101,26 @@ function __DateTimeToString (dt) { default: break; } } + const getOffset = (date, timeZone) => { + const tzDate = new Date(date.toLocaleString('en-US', { timeZone })); + const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' })); + const offset = (tzDate - utcDate) / 60000; // in minutes + const sign = offset >= 0 ? '+' : '-'; + const absOffset = Math.abs(offset); + const hours = Math.floor(absOffset / 60); + const minutes = absOffset % 60; + return `${sign}${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; + }; let offset = 'Z'; if (timeZone !== 'UTC') { - const tzOptions = { timeZone, timeZoneName: 'shortOffset' }; - const tzFormatter = new Intl.DateTimeFormat('en-US', tzOptions); - const tzParts = tzFormatter.formatToParts(date); - const timeZoneNamePart = tzParts.find(part => part.type === 'timeZoneName'); - if (timeZoneNamePart && timeZoneNamePart.value) { - const offsetString = timeZoneNamePart.value; - const match = offsetString.match(/GMT([+-]\d{2})(?::?(\d{2}))?/); - offset = match ? `${match[1][0]}${match[1].slice(1).padStart(2, '0')}:${(match[2] || '00').padStart(2, '0')}` : offsetString === 'GMT' ? '+00:00' : ''; - } + offset = getOffset(date, timeZone); } let isoString = `${year}-${month}-${day}T${hour}:${minute}:${second}`; - if (milliseconds !== null) { - isoString += `.${milliseconds.toString().padStart(3, '0')}`; - } + isoString += `.${milliseconds.toString().padStart(3, '0')}`; isoString += offset; return isoString; - }} + } +} let dt = fromUnixTimestamp(1234334543); print(dt); diff --git a/posthog/hogql/compiler/javascript_stl.py b/posthog/hogql/compiler/javascript_stl.py index dd5e9f6b02cb1..6fcbcb6f9de52 100644 --- a/posthog/hogql/compiler/javascript_stl.py +++ b/posthog/hogql/compiler/javascript_stl.py @@ -439,8 +439,8 @@ ["__isHogDateTime", "__isHogDate", "__isHogError"], ], "__DateTimeToString": [ - r"""function __DateTimeToString (dt) { - if (__isHogDateTime(dt)) { + r"""function __DateTimeToString(dt) { + if (__isHogDateTime(dt)) { const date = new Date(dt.dt * 1000); const timeZone = dt.zone || 'UTC'; const milliseconds = Math.floor(dt.dt * 1000 % 1000); @@ -459,25 +459,26 @@ default: break; } } + const getOffset = (date, timeZone) => { + const tzDate = new Date(date.toLocaleString('en-US', { timeZone })); + const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' })); + const offset = (tzDate - utcDate) / 60000; // in minutes + const sign = offset >= 0 ? '+' : '-'; + const absOffset = Math.abs(offset); + const hours = Math.floor(absOffset / 60); + const minutes = absOffset % 60; + return `${sign}${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; + }; let offset = 'Z'; if (timeZone !== 'UTC') { - const tzOptions = { timeZone, timeZoneName: 'shortOffset' }; - const tzFormatter = new Intl.DateTimeFormat('en-US', tzOptions); - const tzParts = tzFormatter.formatToParts(date); - const timeZoneNamePart = tzParts.find(part => part.type === 'timeZoneName'); - if (timeZoneNamePart && timeZoneNamePart.value) { - const offsetString = timeZoneNamePart.value; - const match = offsetString.match(/GMT([+-]\d{2})(?::?(\d{2}))?/); - offset = match ? `${match[1][0]}${match[1].slice(1).padStart(2, '0')}:${(match[2] || '00').padStart(2, '0')}` : offsetString === 'GMT' ? '+00:00' : ''; - } + offset = getOffset(date, timeZone); } let isoString = `${year}-${month}-${day}T${hour}:${minute}:${second}`; - if (milliseconds !== null) { - isoString += `.${milliseconds.toString().padStart(3, '0')}`; - } + isoString += `.${milliseconds.toString().padStart(3, '0')}`; isoString += offset; return isoString; - }} + } +} """, [], ],