From 7b76bfbe186f59fb4d7d7b87fd9196723a10d550 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Thu, 1 Mar 2007 14:52:04 +0000 Subject: [PATCH] Fix date/time formats for XML Schema output. Pavel Stehule --- src/backend/utils/adt/datetime.c | 27 ++++++---- src/backend/utils/adt/xml.c | 89 ++++++++++++++++++++++++++++---- src/include/miscadmin.h | 3 +- 3 files changed, 100 insertions(+), 19 deletions(-) diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 6154c96b9c..1be6e09163 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.177 2007/02/19 17:41:39 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.178 2007/03/01 14:52:03 petere Exp $ * *------------------------------------------------------------------------- */ @@ -3153,7 +3153,7 @@ datebsearch(const char *key, const datetkn *base, int nel) * Append representation of a numeric timezone offset to str. */ static void -EncodeTimezone(char *str, int tz) +EncodeTimezone(char *str, int tz, int style) { int hour, min, @@ -3171,7 +3171,7 @@ EncodeTimezone(char *str, int tz) if (sec != 0) sprintf(str, "%02d:%02d:%02d", hour, min, sec); - else if (min != 0) + else if (min != 0 || style == USE_XSD_DATES) sprintf(str, "%02d:%02d", hour, min); else sprintf(str, "%02d", hour); @@ -3189,6 +3189,7 @@ EncodeDateOnly(struct pg_tm * tm, int style, char *str) switch (style) { case USE_ISO_DATES: + case USE_XSD_DATES: /* compatible with ISO date formats */ if (tm->tm_year > 0) sprintf(str, "%04d-%02d-%02d", @@ -3266,7 +3267,7 @@ EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str) sprintf(str + strlen(str), ":%02d", tm->tm_sec); if (tzp != NULL) - EncodeTimezone(str, *tzp); + EncodeTimezone(str, *tzp, style); return TRUE; } /* EncodeTimeOnly() */ @@ -3279,6 +3280,7 @@ EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str) * SQL - mm/dd/yyyy hh:mm:ss.ss tz * ISO - yyyy-mm-dd hh:mm:ss+/-tz * German - dd.mm.yyyy hh:mm:ss tz + * XSD - yyyy-mm-ddThh:mm:ss.ss+/-tz * Variants (affects order of month and day for Postgres and SQL styles): * US - mm/dd/yyyy * European - dd/mm/yyyy @@ -3297,11 +3299,18 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, switch (style) { case USE_ISO_DATES: + case USE_XSD_DATES: /* Compatible with ISO-8601 date formats */ - sprintf(str, "%04d-%02d-%02d %02d:%02d", + if (style == USE_ISO_DATES) + sprintf(str, "%04d-%02d-%02d %02d:%02d", (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); + else + sprintf(str, "%04d-%02d-%02dT%02d:%02d", + (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); + /* * 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, * a valid time zone translation. */ if (tzp != NULL && tm->tm_isdst >= 0) - EncodeTimezone(str, *tzp); + EncodeTimezone(str, *tzp, style); if (tm->tm_year <= 0) sprintf(str + strlen(str), " BC"); @@ -3379,7 +3388,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, if (*tzn != NULL) sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); else - EncodeTimezone(str, *tzp); + EncodeTimezone(str, *tzp, style); } if (tm->tm_year <= 0) @@ -3423,7 +3432,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, if (*tzn != NULL) sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); else - EncodeTimezone(str, *tzp); + EncodeTimezone(str, *tzp, style); } if (tm->tm_year <= 0) @@ -3486,7 +3495,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, * the date/time parser later. - thomas 2001-10-19 */ sprintf(str + strlen(str), " "); - EncodeTimezone(str, *tzp); + EncodeTimezone(str, *tzp, style); } } diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index c12522cfe4..547d98df1e 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.32 2007/02/27 23:48:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.33 2007/03/01 14:52:04 petere Exp $ * *------------------------------------------------------------------------- */ @@ -63,6 +63,8 @@ #include "parser/parse_expr.h" #include "utils/array.h" #include "utils/builtins.h" +#include "utils/date.h" +#include "utils/datetime.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/xml.h" @@ -1513,12 +1515,81 @@ map_sql_value_to_xml_value(Datum value, Oid type) bool isvarlena; char *p, *str; - if (type == BOOLOID) + /* + * Special XSD formatting for some data types + */ + switch (type) { - if (DatumGetBool(value)) - return "true"; - else - return "false"; + case BOOLOID: + if (DatumGetBool(value)) + return "true"; + else + return "false"; + + case DATEOID: + { + DateADT date; + struct pg_tm tm; + char buf[MAXDATELEN + 1]; + + date = DatumGetDateADT(value); + j2date(date + POSTGRES_EPOCH_JDATE, + &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday)); + EncodeDateOnly(&tm, USE_XSD_DATES, buf); + + return pstrdup(buf); + } + + case TIMESTAMPOID: + { + Timestamp timestamp; + struct pg_tm tm; + fsec_t fsec; + char *tzn = NULL; + char buf[MAXDATELEN + 1]; + + timestamp = DatumGetTimestamp(value); + + /* XSD doesn't support infinite values */ + if (TIMESTAMP_NOT_FINITE(timestamp)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0) + EncodeDateTime(&tm, fsec, NULL, &tzn, USE_XSD_DATES, buf); + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + + return pstrdup(buf); + } + + case TIMESTAMPTZOID: + { + TimestampTz timestamp; + struct pg_tm tm; + int tz; + fsec_t fsec; + char *tzn = NULL; + char buf[MAXDATELEN + 1]; + + timestamp = DatumGetTimestamp(value); + + /* XSD doesn't support infinite values */ + if (TIMESTAMP_NOT_FINITE(timestamp)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0) + EncodeDateTime(&tm, fsec, &tz, &tzn, USE_XSD_DATES, buf); + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + + return pstrdup(buf); + } } getTypeOutputInfo(type, &typeOut, &isvarlena); @@ -2234,17 +2305,17 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod) if (typmod == -1) appendStringInfo(&result, - " \n" + " \n" " \n" " \n", tz); else if (typmod == 0) appendStringInfo(&result, - " \n" + " \n" " \n" " \n", tz); else appendStringInfo(&result, - " \n" + " \n" " \n" " \n", typmod - VARHDRSZ, tz); break; diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 29a450cab6..ca5cc799c5 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.192 2007/02/15 23:23:23 alvherre Exp $ + * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.193 2007/03/01 14:52:04 petere Exp $ * * NOTES * some of the information in this file should be moved to other files. @@ -178,6 +178,7 @@ extern DLLIMPORT Oid MyDatabaseTableSpace; #define USE_ISO_DATES 1 #define USE_SQL_DATES 2 #define USE_GERMAN_DATES 3 +#define USE_XSD_DATES 4 /* valid DateOrder values */ #define DATEORDER_YMD 0 -- 2.40.0