diff options
Diffstat (limited to 'src/interfaces')
-rw-r--r-- | src/interfaces/ecpg/pgtypeslib/dt.h | 1 | ||||
-rw-r--r-- | src/interfaces/ecpg/pgtypeslib/dt_common.c | 55 | ||||
-rw-r--r-- | src/interfaces/ecpg/pgtypeslib/interval.c | 68 |
3 files changed, 123 insertions, 1 deletions
diff --git a/src/interfaces/ecpg/pgtypeslib/dt.h b/src/interfaces/ecpg/pgtypeslib/dt.h index 2cbc58984bd..fa7b905608d 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt.h +++ b/src/interfaces/ecpg/pgtypeslib/dt.h @@ -21,6 +21,7 @@ typedef double fsec_t; #define USE_ISO_DATES 1 #define USE_SQL_DATES 2 #define USE_GERMAN_DATES 3 +#define USE_ISO8601BASIC_DATES 4 #define DAGO "ago" #define EPOCH "epoch" diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c index 04aaa70ccfc..aa4f943fb8c 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt_common.c +++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c @@ -704,6 +704,16 @@ EncodeDateOnly(struct tm * tm, int style, char *str, bool EuroDates) -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC"); break; + case USE_ISO8601BASIC_DATES: + /* compatible with ISO date formats */ + if (tm->tm_year > 0) + sprintf(str, "%04d%02d%02d", + tm->tm_year, tm->tm_mon, tm->tm_mday); + else + sprintf(str, "%04d%02d%02d %s", + -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC"); + break; + case USE_SQL_DATES: /* compatible with Oracle/Ingres date formats */ if (EuroDates) @@ -820,6 +830,51 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha } break; + case USE_ISO8601BASIC_DATES: + /* Compatible with ISO-8601 date formats */ + + 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 be at least equal to MAX_TIMESTAMP_PRECISION. + * + * In float mode, don't print fractional seconds before 1 AD, + * since it's unlikely there's any precision left ... + */ +#ifdef HAVE_INT64_TIMESTAMP + if (fsec != 0) + { + sprintf((str + strlen(str)), "%02d.%06d", tm->tm_sec, fsec); +#else + if ((fsec != 0) && (tm->tm_year > 0)) + { + sprintf((str + strlen(str)), "%09.6f", tm->tm_sec + fsec); +#endif + TrimTrailingZeros(str); + } + else + sprintf((str + strlen(str)), "%02d", tm->tm_sec); + + if (tm->tm_year <= 0) + sprintf((str + strlen(str)), " BC"); + + /* + * tzp == NULL indicates that we don't want *any* time zone + * info in the output string. *tzn != NULL indicates that we + * have alpha time zone info available. tm_isdst != -1 + * indicates that we have a valid time zone translation. + */ + if ((tzp != NULL) && (tm->tm_isdst >= 0)) + { + hour = -(*tzp / 3600); + min = ((abs(*tzp) / 60) % 60); + sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min); + } + break; + case USE_SQL_DATES: /* Compatible with Oracle/Ingres date formats */ diff --git a/src/interfaces/ecpg/pgtypeslib/interval.c b/src/interfaces/ecpg/pgtypeslib/interval.c index c49cd0e9979..8c720c8a988 100644 --- a/src/interfaces/ecpg/pgtypeslib/interval.c +++ b/src/interfaces/ecpg/pgtypeslib/interval.c @@ -442,6 +442,17 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse return (fmask != 0) ? 0 : -1; } /* DecodeInterval() */ + +/* + * Small helper function to avoid cut&paste in EncodeInterval below + */ +static char * AppendISO8601Fragment(char * cp, int value, char character) +{ + sprintf(cp,"%d%c",value,character); + return cp + strlen(cp); +} + + /* EncodeInterval() * Interpret time structure as a delta time and convert to string. * @@ -449,6 +460,14 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse * Actually, afaik ISO does not address time interval formatting, * but this looks similar to the spec for absolute date/time. * - thomas 1998-04-30 + * + * Actually, afaik, ISO 8601 does specify formats for "time + * intervals...[of the]...format with time-unit designators", which + * are pretty ugly. The format looks something like + * P1Y1M1DT1H1M1.12345S + * If you want this (perhaps for interoperability with computers + * rather than humans), datestyle 'iso8601basic' will output these. + * - ron 2003-07-14 */ int EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str) @@ -465,7 +484,12 @@ EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str) */ switch (style) { - /* compatible with ISO date formats */ + /* compatible with ISO date formats + ([ram] Not for ISO 8601, perhaps some other ISO format. + but I'm leaving it that way because it's more human + readable than ISO8601 time intervals and for backwards + compatability.) + */ case USE_ISO_DATES: if (tm->tm_year != 0) { @@ -533,6 +557,48 @@ EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str) } break; + case USE_ISO8601BASIC_DATES: + sprintf(cp,"P"); + cp++; + if (tm->tm_year != 0) cp = AppendISO8601Fragment(cp,tm->tm_year,'Y'); + if (tm->tm_mon != 0) cp = AppendISO8601Fragment(cp,tm->tm_mon ,'M'); + if (tm->tm_mday != 0) cp = AppendISO8601Fragment(cp,tm->tm_mday,'D'); + if ((tm->tm_hour != 0) || (tm->tm_min != 0) || + (tm->tm_sec != 0) || (fsec != 0)) + { + sprintf(cp,"T"), + cp++; + } + if (tm->tm_hour != 0) cp = AppendISO8601Fragment(cp,tm->tm_hour,'H'); + if (tm->tm_min != 0) cp = AppendISO8601Fragment(cp,tm->tm_min ,'M'); + + if ((tm->tm_year == 0) && (tm->tm_mon == 0) && (tm->tm_mday == 0) && + (tm->tm_hour == 0) && (tm->tm_min == 0) && (tm->tm_sec == 0) && + (fsec == 0)) + { + sprintf(cp,"T0S"), + cp+=2; + } + else if (fsec != 0) + { +#ifdef HAVE_INT64_TIMESTAMP + sprintf(cp, "%d", abs(tm->tm_sec)); + cp += strlen(cp); + sprintf(cp, ".%6dS", ((fsec >= 0) ? fsec : -(fsec))); +#else + fsec += tm->tm_sec; + sprintf(cp, "%fS", fabs(fsec)); +#endif + TrimTrailingZeros(cp); + cp += strlen(cp); + } + else if (tm->tm_sec != 0) + { + cp = AppendISO8601Fragment(cp,tm->tm_sec ,'S'); + cp += strlen(cp); + } + break; + case USE_POSTGRES_DATES: default: strcpy(cp, "@ "); |