diff options
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r-- | src/backend/utils/adt/json.c | 32 | ||||
-rw-r--r-- | src/backend/utils/adt/jsonb.c | 27 | ||||
-rw-r--r-- | src/backend/utils/adt/jsonb_util.c | 21 |
3 files changed, 71 insertions, 9 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 26d293709a..d4ba3bd87d 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -1506,7 +1506,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result, { char buf[MAXDATELEN + 1]; - JsonEncodeDateTime(buf, val, DATEOID); + JsonEncodeDateTime(buf, val, DATEOID, NULL); appendStringInfo(result, "\"%s\"", buf); } break; @@ -1514,7 +1514,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result, { char buf[MAXDATELEN + 1]; - JsonEncodeDateTime(buf, val, TIMESTAMPOID); + JsonEncodeDateTime(buf, val, TIMESTAMPOID, NULL); appendStringInfo(result, "\"%s\"", buf); } break; @@ -1522,7 +1522,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result, { char buf[MAXDATELEN + 1]; - JsonEncodeDateTime(buf, val, TIMESTAMPTZOID); + JsonEncodeDateTime(buf, val, TIMESTAMPTZOID, NULL); appendStringInfo(result, "\"%s\"", buf); } break; @@ -1550,10 +1550,11 @@ datum_to_json(Datum val, bool is_null, StringInfo result, /* * Encode 'value' of datetime type 'typid' into JSON string in ISO format using - * optionally preallocated buffer 'buf'. + * optionally preallocated buffer 'buf'. Optional 'tzp' determines time-zone + * offset (in seconds) in which we want to show timestamptz. */ char * -JsonEncodeDateTime(char *buf, Datum value, Oid typid) +JsonEncodeDateTime(char *buf, Datum value, Oid typid, const int *tzp) { if (!buf) buf = palloc(MAXDATELEN + 1); @@ -1630,11 +1631,30 @@ JsonEncodeDateTime(char *buf, Datum value, Oid typid) const char *tzn = NULL; timestamp = DatumGetTimestampTz(value); + + /* + * If a time zone is specified, we apply the time-zone shift, + * convert timestamptz to pg_tm as if it were without a time + * zone, and then use the specified time zone for converting + * the timestamp into a string. + */ + if (tzp) + { + tz = *tzp; + timestamp -= (TimestampTz) tz * USECS_PER_SEC; + } + /* Same as timestamptz_out(), but forcing DateStyle */ if (TIMESTAMP_NOT_FINITE(timestamp)) EncodeSpecialTimestamp(timestamp, buf); - else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0) + else if (timestamp2tm(timestamp, tzp ? NULL : &tz, &tm, &fsec, + tzp ? NULL : &tzn, NULL) == 0) + { + if (tzp) + tm.tm_isdst = 1; /* set time-zone presence flag */ + EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf); + } else ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index 69f41ab455..74b4bbe44c 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -206,6 +206,24 @@ JsonbTypeName(JsonbValue *jbv) return "boolean"; case jbvNull: return "null"; + case jbvDatetime: + switch (jbv->val.datetime.typid) + { + case DATEOID: + return "date"; + case TIMEOID: + return "time without time zone"; + case TIMETZOID: + return "time with time zone"; + case TIMESTAMPOID: + return "timestamp without time zone"; + case TIMESTAMPTZOID: + return "timestamp with time zone"; + default: + elog(ERROR, "unrecognized jsonb value datetime type: %d", + jbv->val.datetime.typid); + } + return "unknown"; default: elog(ERROR, "unrecognized jsonb value type: %d", jbv->type); return "unknown"; @@ -805,17 +823,20 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, break; case JSONBTYPE_DATE: jb.type = jbvString; - jb.val.string.val = JsonEncodeDateTime(NULL, val, DATEOID); + jb.val.string.val = JsonEncodeDateTime(NULL, val, + DATEOID, NULL); jb.val.string.len = strlen(jb.val.string.val); break; case JSONBTYPE_TIMESTAMP: jb.type = jbvString; - jb.val.string.val = JsonEncodeDateTime(NULL, val, TIMESTAMPOID); + jb.val.string.val = JsonEncodeDateTime(NULL, val, + TIMESTAMPOID, NULL); jb.val.string.len = strlen(jb.val.string.val); break; case JSONBTYPE_TIMESTAMPTZ: jb.type = jbvString; - jb.val.string.val = JsonEncodeDateTime(NULL, val, TIMESTAMPTZOID); + jb.val.string.val = JsonEncodeDateTime(NULL, val, + TIMESTAMPTZOID, NULL); jb.val.string.len = strlen(jb.val.string.val); break; case JSONBTYPE_JSONCAST: diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index 7e0d9de7f0..f7f79eb965 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -14,9 +14,12 @@ #include "postgres.h" #include "catalog/pg_collation.h" +#include "catalog/pg_type.h" #include "miscadmin.h" #include "utils/builtins.h" +#include "utils/datetime.h" #include "utils/hashutils.h" +#include "utils/jsonapi.h" #include "utils/jsonb.h" #include "utils/memutils.h" #include "utils/varlena.h" @@ -244,6 +247,8 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b) break; case jbvBinary: elog(ERROR, "unexpected jbvBinary value"); + case jbvDatetime: + elog(ERROR, "unexpected jbvDatetime value"); } } else @@ -1786,6 +1791,22 @@ convertJsonbScalar(StringInfo buffer, JEntry *jentry, JsonbValue *scalarVal) JENTRY_ISBOOL_TRUE : JENTRY_ISBOOL_FALSE; break; + case jbvDatetime: + { + char buf[MAXDATELEN + 1]; + size_t len; + + JsonEncodeDateTime(buf, + scalarVal->val.datetime.value, + scalarVal->val.datetime.typid, + &scalarVal->val.datetime.tz); + len = strlen(buf); + appendToBuffer(buffer, buf, len); + + *jentry = len; + } + break; + default: elog(ERROR, "invalid jsonb scalar type"); } |