Skip to content

Commit 7f03761

Browse files
committed
Preserve tz when converting to jsonb timestamptz
The JSONB jbvDatetime type has a field for offset, and displays the time in that offset. For example, when the time zone GUC is set to America/New_York, the jsonpath `timestamp_tz()` method returns a value that displays a parsed value with its offset, not the local offset: david=# set time zone 'America/New_York'; SET david=# select jsonb_path_query_tz('"2024-08-15 12:34:56+10"', '$.timestamp_tz()'); jsonb_path_query_tz ----------------------------- "2024-08-15T12:34:56+10:00" This was not true for values parsed by `timestamp_tz()` that lacked an offset. It correctly assumes the local time zone, but displays it in UTC: david=# select jsonb_path_query_tz('"2024-08-15 12:34:56"', '$.timestamp_tz()'); jsonb_path_query_tz ----------------------------- "2024-08-15T16:34:56+00:00" To fix this inconsistent behavior, determine the offset for values being cast from `DATEOID` and `DATEOID` types to `jpiTimestampTz` and store it in the resulting jbvDatetime value. With this change, the result now preserves the offset just as it does when converting from offset-aware values: david=# select jsonb_path_query_tz('"2024-08-15 12:34:56"', '$.timestamp_tz()'); jsonb_path_query_tz ----------------------------- "2023-08-15T12:34:56-04:00" Author: David Wheeler Reviewed-by: Junwang Zhao Discussion: https://postgr.es/m/7DE080CE-6D8C-4794-9BD1-7D9699172FAB%40justatheory.com
1 parent 5784a49 commit 7f03761

File tree

2 files changed

+14
-2
lines changed

2 files changed

+14
-2
lines changed

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2707,12 +2707,21 @@ executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
27072707
break;
27082708
case jpiTimestampTz:
27092709
{
2710+
struct pg_tm tm;
2711+
fsec_t fsec;
27102712
/* Convert result type to timestamp with time zone */
27112713
switch (typid)
27122714
{
27132715
case DATEOID:
27142716
checkTimezoneIsUsedForCast(cxt->useTz,
27152717
"date", "timestamptz");
2718+
DateADT dateVal = DatumGetDateADT(value);
2719+
j2date(dateVal + POSTGRES_EPOCH_JDATE,
2720+
&(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
2721+
tm.tm_hour = 0;
2722+
tm.tm_min = 0;
2723+
tm.tm_sec = 0;
2724+
tz = DetermineTimeZoneOffset(&tm, session_timezone);
27162725
value = DirectFunctionCall1(date_timestamptz,
27172726
value);
27182727
break;
@@ -2726,6 +2735,9 @@ executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
27262735
case TIMESTAMPOID:
27272736
checkTimezoneIsUsedForCast(cxt->useTz,
27282737
"timestamp", "timestamptz");
2738+
if (timestamp2tm(DatumGetTimestamp(value), NULL, &tm, &fsec, NULL, NULL) == 0) {
2739+
tz = DetermineTimeZoneOffset(&tm, session_timezone);
2740+
}
27292741
value = DirectFunctionCall1(timestamp_timestamptz,
27302742
value);
27312743
break;

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,7 +2964,7 @@ HINT: Use *_tz() function for time zone support.
29642964
select jsonb_path_query_tz('"2023-08-15"', '$.timestamp_tz()'); -- should work
29652965
jsonb_path_query_tz
29662966
-----------------------------
2967-
"2023-08-15T07:00:00+00:00"
2967+
"2023-08-15T00:00:00-07:00"
29682968
(1 row)
29692969

29702970
select jsonb_path_query('"12:34:56"', '$.timestamp_tz()');
@@ -3151,7 +3151,7 @@ HINT: Use *_tz() function for time zone support.
31513151
select jsonb_path_query_tz('"2023-08-15 12:34:56"', '$.timestamp_tz()'); -- should work
31523152
jsonb_path_query_tz
31533153
-----------------------------
3154-
"2023-08-15T02:34:56+00:00"
3154+
"2023-08-15T12:34:56+10:00"
31553155
(1 row)
31563156

31573157
select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp_tz()');

0 commit comments

Comments
 (0)