Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e56ec50

Browse files
committed
Use ISO 8601 format for dates converted to JSON, too.
Commit f30015b made this happen for timestamp and timestamptz, but it seems pretty inconsistent to not do it for simple dates as well. (In passing, I re-pgindent'd json.c.)
1 parent 3e9f70f commit e56ec50

File tree

2 files changed

+48
-14
lines changed

2 files changed

+48
-14
lines changed

doc/src/sgml/release-9.4.sgml

+5-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120

121121
<listitem>
122122
<para>
123-
When converting values of type <type>timestamp</>
123+
When converting values of type <type>date</>, <type>timestamp</>
124124
or <type>timestamptz</>
125125
to <link linkend="datatype-json"><type>JSON</type></link>, render the
126126
values in a format compliant with ISO 8601 (Andrew Dunstan)
@@ -129,7 +129,10 @@
129129
<para>
130130
Previously such values were rendered according to the current
131131
<xref linkend="guc-datestyle"> setting; but many JSON processors
132-
require timestamps to be in ISO 8601 format.
132+
require timestamps to be in ISO 8601 format. If necessary, the
133+
previous behavior can be obtained by explicitly casting the datetime
134+
value to <type>text</> before passing it to the JSON conversion
135+
function.
133136
</para>
134137
</listitem>
135138

src/backend/utils/adt/json.c

+43-12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "parser/parse_coerce.h"
2626
#include "utils/array.h"
2727
#include "utils/builtins.h"
28+
#include "utils/date.h"
2829
#include "utils/datetime.h"
2930
#include "utils/lsyscache.h"
3031
#include "utils/json.h"
@@ -55,8 +56,9 @@ typedef enum /* type categories for datum_to_json */
5556
JSONTYPE_NULL, /* null, so we didn't bother to identify */
5657
JSONTYPE_BOOL, /* boolean (built-in types only) */
5758
JSONTYPE_NUMERIC, /* numeric (ditto) */
58-
JSONTYPE_TIMESTAMP, /* we use special formatting for timestamp */
59-
JSONTYPE_TIMESTAMPTZ, /* ... and timestamptz */
59+
JSONTYPE_DATE, /* we use special formatting for datetimes */
60+
JSONTYPE_TIMESTAMP,
61+
JSONTYPE_TIMESTAMPTZ,
6062
JSONTYPE_JSON, /* JSON itself (and JSONB) */
6163
JSONTYPE_ARRAY, /* array */
6264
JSONTYPE_COMPOSITE, /* composite */
@@ -1267,6 +1269,10 @@ json_categorize_type(Oid typoid,
12671269
*tcategory = JSONTYPE_NUMERIC;
12681270
break;
12691271

1272+
case DATEOID:
1273+
*tcategory = JSONTYPE_DATE;
1274+
break;
1275+
12701276
case TIMESTAMPOID:
12711277
*tcategory = JSONTYPE_TIMESTAMP;
12721278
break;
@@ -1348,7 +1354,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
13481354
tcategory == JSONTYPE_CAST))
13491355
ereport(ERROR,
13501356
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1351-
errmsg("key value must be scalar, not array, composite, or json")));
1357+
errmsg("key value must be scalar, not array, composite, or json")));
13521358

13531359
switch (tcategory)
13541360
{
@@ -1388,6 +1394,30 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
13881394
}
13891395
pfree(outputstr);
13901396
break;
1397+
case JSONTYPE_DATE:
1398+
{
1399+
DateADT date;
1400+
struct pg_tm tm;
1401+
char buf[MAXDATELEN + 1];
1402+
1403+
date = DatumGetDateADT(val);
1404+
1405+
/* XSD doesn't support infinite values */
1406+
if (DATE_NOT_FINITE(date))
1407+
ereport(ERROR,
1408+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1409+
errmsg("date out of range"),
1410+
errdetail("JSON does not support infinite date values.")));
1411+
else
1412+
{
1413+
j2date(date + POSTGRES_EPOCH_JDATE,
1414+
&(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
1415+
EncodeDateOnly(&tm, USE_XSD_DATES, buf);
1416+
}
1417+
1418+
appendStringInfo(result, "\"%s\"", buf);
1419+
}
1420+
break;
13911421
case JSONTYPE_TIMESTAMP:
13921422
{
13931423
Timestamp timestamp;
@@ -1410,7 +1440,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
14101440
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
14111441
errmsg("timestamp out of range")));
14121442

1413-
appendStringInfo(result,"\"%s\"",buf);
1443+
appendStringInfo(result, "\"%s\"", buf);
14141444
}
14151445
break;
14161446
case JSONTYPE_TIMESTAMPTZ:
@@ -1437,7 +1467,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
14371467
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
14381468
errmsg("timestamp out of range")));
14391469

1440-
appendStringInfo(result,"\"%s\"",buf);
1470+
appendStringInfo(result, "\"%s\"", buf);
14411471
}
14421472
break;
14431473
case JSONTYPE_JSON:
@@ -2305,20 +2335,21 @@ escape_json(StringInfo buf, const char *str)
23052335
appendStringInfoString(buf, "\\\"");
23062336
break;
23072337
case '\\':
2338+
23082339
/*
23092340
* Unicode escapes are passed through as is. There is no
23102341
* requirement that they denote a valid character in the
23112342
* server encoding - indeed that is a big part of their
23122343
* usefulness.
23132344
*
2314-
* All we require is that they consist of \uXXXX where
2315-
* the Xs are hexadecimal digits. It is the responsibility
2316-
* of the caller of, say, to_json() to make sure that the
2317-
* unicode escape is valid.
2345+
* All we require is that they consist of \uXXXX where the Xs
2346+
* are hexadecimal digits. It is the responsibility of the
2347+
* caller of, say, to_json() to make sure that the unicode
2348+
* escape is valid.
23182349
*
2319-
* In the case of a jsonb string value being escaped, the
2320-
* only unicode escape that should be present is \u0000,
2321-
* all the other unicode escapes will have been resolved.
2350+
* In the case of a jsonb string value being escaped, the only
2351+
* unicode escape that should be present is \u0000, all the
2352+
* other unicode escapes will have been resolved.
23222353
*/
23232354
if (p[1] == 'u' &&
23242355
isxdigit((unsigned char) p[2]) &&

0 commit comments

Comments
 (0)