Skip to content

Commit 7b76bfb

Browse files
committed
Fix date/time formats for XML Schema output.
Pavel Stehule
1 parent 9f652d4 commit 7b76bfb

File tree

3 files changed

+100
-19
lines changed

3 files changed

+100
-19
lines changed

src/backend/utils/adt/datetime.c

+18-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.177 2007/02/19 17:41:39 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.178 2007/03/01 14:52:03 petere Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -3153,7 +3153,7 @@ datebsearch(const char *key, const datetkn *base, int nel)
31533153
* Append representation of a numeric timezone offset to str.
31543154
*/
31553155
static void
3156-
EncodeTimezone(char *str, int tz)
3156+
EncodeTimezone(char *str, int tz, int style)
31573157
{
31583158
int hour,
31593159
min,
@@ -3171,7 +3171,7 @@ EncodeTimezone(char *str, int tz)
31713171

31723172
if (sec != 0)
31733173
sprintf(str, "%02d:%02d:%02d", hour, min, sec);
3174-
else if (min != 0)
3174+
else if (min != 0 || style == USE_XSD_DATES)
31753175
sprintf(str, "%02d:%02d", hour, min);
31763176
else
31773177
sprintf(str, "%02d", hour);
@@ -3189,6 +3189,7 @@ EncodeDateOnly(struct pg_tm * tm, int style, char *str)
31893189
switch (style)
31903190
{
31913191
case USE_ISO_DATES:
3192+
case USE_XSD_DATES:
31923193
/* compatible with ISO date formats */
31933194
if (tm->tm_year > 0)
31943195
sprintf(str, "%04d-%02d-%02d",
@@ -3266,7 +3267,7 @@ EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str)
32663267
sprintf(str + strlen(str), ":%02d", tm->tm_sec);
32673268

32683269
if (tzp != NULL)
3269-
EncodeTimezone(str, *tzp);
3270+
EncodeTimezone(str, *tzp, style);
32703271

32713272
return TRUE;
32723273
} /* EncodeTimeOnly() */
@@ -3279,6 +3280,7 @@ EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str)
32793280
* SQL - mm/dd/yyyy hh:mm:ss.ss tz
32803281
* ISO - yyyy-mm-dd hh:mm:ss+/-tz
32813282
* German - dd.mm.yyyy hh:mm:ss tz
3283+
* XSD - yyyy-mm-ddThh:mm:ss.ss+/-tz
32823284
* Variants (affects order of month and day for Postgres and SQL styles):
32833285
* US - mm/dd/yyyy
32843286
* European - dd/mm/yyyy
@@ -3297,11 +3299,18 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
32973299
switch (style)
32983300
{
32993301
case USE_ISO_DATES:
3302+
case USE_XSD_DATES:
33003303
/* Compatible with ISO-8601 date formats */
33013304

3302-
sprintf(str, "%04d-%02d-%02d %02d:%02d",
3305+
if (style == USE_ISO_DATES)
3306+
sprintf(str, "%04d-%02d-%02d %02d:%02d",
33033307
(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
33043308
tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
3309+
else
3310+
sprintf(str, "%04d-%02d-%02dT%02d:%02d",
3311+
(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
3312+
tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
3313+
33053314

33063315
/*
33073316
* Print fractional seconds if any. The field widths here should
@@ -3333,7 +3342,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
33333342
* a valid time zone translation.
33343343
*/
33353344
if (tzp != NULL && tm->tm_isdst >= 0)
3336-
EncodeTimezone(str, *tzp);
3345+
EncodeTimezone(str, *tzp, style);
33373346

33383347
if (tm->tm_year <= 0)
33393348
sprintf(str + strlen(str), " BC");
@@ -3379,7 +3388,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
33793388
if (*tzn != NULL)
33803389
sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn);
33813390
else
3382-
EncodeTimezone(str, *tzp);
3391+
EncodeTimezone(str, *tzp, style);
33833392
}
33843393

33853394
if (tm->tm_year <= 0)
@@ -3423,7 +3432,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
34233432
if (*tzn != NULL)
34243433
sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn);
34253434
else
3426-
EncodeTimezone(str, *tzp);
3435+
EncodeTimezone(str, *tzp, style);
34273436
}
34283437

34293438
if (tm->tm_year <= 0)
@@ -3486,7 +3495,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
34863495
* the date/time parser later. - thomas 2001-10-19
34873496
*/
34883497
sprintf(str + strlen(str), " ");
3489-
EncodeTimezone(str, *tzp);
3498+
EncodeTimezone(str, *tzp, style);
34903499
}
34913500
}
34923501

src/backend/utils/adt/xml.c

+80-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.32 2007/02/27 23:48:09 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.33 2007/03/01 14:52:04 petere Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -63,6 +63,8 @@
6363
#include "parser/parse_expr.h"
6464
#include "utils/array.h"
6565
#include "utils/builtins.h"
66+
#include "utils/date.h"
67+
#include "utils/datetime.h"
6668
#include "utils/lsyscache.h"
6769
#include "utils/memutils.h"
6870
#include "utils/xml.h"
@@ -1513,12 +1515,81 @@ map_sql_value_to_xml_value(Datum value, Oid type)
15131515
bool isvarlena;
15141516
char *p, *str;
15151517

1516-
if (type == BOOLOID)
1518+
/*
1519+
* Special XSD formatting for some data types
1520+
*/
1521+
switch (type)
15171522
{
1518-
if (DatumGetBool(value))
1519-
return "true";
1520-
else
1521-
return "false";
1523+
case BOOLOID:
1524+
if (DatumGetBool(value))
1525+
return "true";
1526+
else
1527+
return "false";
1528+
1529+
case DATEOID:
1530+
{
1531+
DateADT date;
1532+
struct pg_tm tm;
1533+
char buf[MAXDATELEN + 1];
1534+
1535+
date = DatumGetDateADT(value);
1536+
j2date(date + POSTGRES_EPOCH_JDATE,
1537+
&(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
1538+
EncodeDateOnly(&tm, USE_XSD_DATES, buf);
1539+
1540+
return pstrdup(buf);
1541+
}
1542+
1543+
case TIMESTAMPOID:
1544+
{
1545+
Timestamp timestamp;
1546+
struct pg_tm tm;
1547+
fsec_t fsec;
1548+
char *tzn = NULL;
1549+
char buf[MAXDATELEN + 1];
1550+
1551+
timestamp = DatumGetTimestamp(value);
1552+
1553+
/* XSD doesn't support infinite values */
1554+
if (TIMESTAMP_NOT_FINITE(timestamp))
1555+
ereport(ERROR,
1556+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1557+
errmsg("timestamp out of range")));
1558+
else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
1559+
EncodeDateTime(&tm, fsec, NULL, &tzn, USE_XSD_DATES, buf);
1560+
else
1561+
ereport(ERROR,
1562+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1563+
errmsg("timestamp out of range")));
1564+
1565+
return pstrdup(buf);
1566+
}
1567+
1568+
case TIMESTAMPTZOID:
1569+
{
1570+
TimestampTz timestamp;
1571+
struct pg_tm tm;
1572+
int tz;
1573+
fsec_t fsec;
1574+
char *tzn = NULL;
1575+
char buf[MAXDATELEN + 1];
1576+
1577+
timestamp = DatumGetTimestamp(value);
1578+
1579+
/* XSD doesn't support infinite values */
1580+
if (TIMESTAMP_NOT_FINITE(timestamp))
1581+
ereport(ERROR,
1582+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1583+
errmsg("timestamp out of range")));
1584+
else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
1585+
EncodeDateTime(&tm, fsec, &tz, &tzn, USE_XSD_DATES, buf);
1586+
else
1587+
ereport(ERROR,
1588+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1589+
errmsg("timestamp out of range")));
1590+
1591+
return pstrdup(buf);
1592+
}
15221593
}
15231594

15241595
getTypeOutputInfo(type, &typeOut, &isvarlena);
@@ -2234,17 +2305,17 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
22342305

22352306
if (typmod == -1)
22362307
appendStringInfo(&result,
2237-
" <xsd:restriction base=\"xsd:time\">\n"
2308+
" <xsd:restriction base=\"xsd:dateTime\">\n"
22382309
" <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}(.\\p{Nd}+)?%s\"/>\n"
22392310
" </xsd:restriction>\n", tz);
22402311
else if (typmod == 0)
22412312
appendStringInfo(&result,
2242-
" <xsd:restriction base=\"xsd:time\">\n"
2313+
" <xsd:restriction base=\"xsd:dateTime\">\n"
22432314
" <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
22442315
" </xsd:restriction>\n", tz);
22452316
else
22462317
appendStringInfo(&result,
2247-
" <xsd:restriction base=\"xsd:time\">\n"
2318+
" <xsd:restriction base=\"xsd:dateTime\">\n"
22482319
" <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}.\\p{Nd}{%d}%s\"/>\n"
22492320
" </xsd:restriction>\n", typmod - VARHDRSZ, tz);
22502321
break;

src/include/miscadmin.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
1414
* Portions Copyright (c) 1994, Regents of the University of California
1515
*
16-
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.192 2007/02/15 23:23:23 alvherre Exp $
16+
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.193 2007/03/01 14:52:04 petere Exp $
1717
*
1818
* NOTES
1919
* some of the information in this file should be moved to other files.
@@ -178,6 +178,7 @@ extern DLLIMPORT Oid MyDatabaseTableSpace;
178178
#define USE_ISO_DATES 1
179179
#define USE_SQL_DATES 2
180180
#define USE_GERMAN_DATES 3
181+
#define USE_XSD_DATES 4
181182

182183
/* valid DateOrder values */
183184
#define DATEORDER_YMD 0

0 commit comments

Comments
 (0)