Fix date/time formats for XML Schema output.
authorPeter Eisentraut <peter_e@gmx.net>
Thu, 1 Mar 2007 14:52:04 +0000 (14:52 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Thu, 1 Mar 2007 14:52:04 +0000 (14:52 +0000)
Pavel Stehule

src/backend/utils/adt/datetime.c
src/backend/utils/adt/xml.c
src/include/miscadmin.h

index 6154c96b9c257f0483c01707fc7555b758239763..1be6e091632967dd4671cfbd5a0ff51321eebec5 100644 (file)
@@ -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);
                }
            }
 
index c12522cfe4537d7ce73b197408e883a69b427c3b..547d98df1e64be443850cb7b0ed4bb36e9337346 100644 (file)
@@ -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,
-                                    "  <xsd:restriction base=\"xsd:time\">\n"
+                                    "  <xsd:restriction base=\"xsd:dateTime\">\n"
                                     "    <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"
                                     "  </xsd:restriction>\n", tz);
                else if (typmod == 0)
                    appendStringInfo(&result,
-                                    "  <xsd:restriction base=\"xsd:time\">\n"
+                                    "  <xsd:restriction base=\"xsd:dateTime\">\n"
                                     "    <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}T\\p{Nd}{2}:\\p{Nd}{2}:\\p{Nd}{2}%s\"/>\n"
                                     "  </xsd:restriction>\n", tz);
                else
                    appendStringInfo(&result,
-                                    "  <xsd:restriction base=\"xsd:time\">\n"
+                                    "  <xsd:restriction base=\"xsd:dateTime\">\n"
                                     "    <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"
                                     "  </xsd:restriction>\n", typmod - VARHDRSZ, tz);
                break;
index 29a450cab60e087c75d5668f6e58563021de2984..ca5cc799c519140ad2341969f4e76ba80ed5b11a 100644 (file)
@@ -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