Improve EncodeDateTime and EncodeTimeOnly APIs

Use an explicit argument to tell whether to include the time zone in
the output, rather than using some undocumented pointer magic.
pull/3/head
Peter Eisentraut 14 years ago
parent 942b63193c
commit ad4fb0d0d2
  1. 4
      src/backend/utils/adt/date.c
  2. 65
      src/backend/utils/adt/datetime.c
  3. 2
      src/backend/utils/adt/nabstime.c
  4. 7
      src/backend/utils/adt/timestamp.c
  5. 5
      src/backend/utils/adt/xml.c
  6. 4
      src/include/utils/datetime.h
  7. 6
      src/interfaces/ecpg/pgtypeslib/dt.h
  8. 59
      src/interfaces/ecpg/pgtypeslib/dt_common.c
  9. 3
      src/interfaces/ecpg/pgtypeslib/timestamp.c

@ -1131,7 +1131,7 @@ time_out(PG_FUNCTION_ARGS)
char buf[MAXDATELEN + 1]; char buf[MAXDATELEN + 1];
time2tm(time, tm, &fsec); time2tm(time, tm, &fsec);
EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf); EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
result = pstrdup(buf); result = pstrdup(buf);
PG_RETURN_CSTRING(result); PG_RETURN_CSTRING(result);
@ -1918,7 +1918,7 @@ timetz_out(PG_FUNCTION_ARGS)
char buf[MAXDATELEN + 1]; char buf[MAXDATELEN + 1];
timetz2tm(time, tm, &fsec, &tz); timetz2tm(time, tm, &fsec, &tz);
EncodeTimeOnly(tm, fsec, &tz, DateStyle, buf); EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
result = pstrdup(buf); result = pstrdup(buf);
PG_RETURN_CSTRING(result); PG_RETURN_CSTRING(result);

@ -3679,39 +3679,54 @@ EncodeDateOnly(struct pg_tm * tm, int style, char *str)
/* EncodeTimeOnly() /* EncodeTimeOnly()
* Encode time fields only. * Encode time fields only.
*
* tm and fsec are the value to encode, print_tz determines whether to include
* a time zone (the difference between time and timetz types), tz is the
* numeric time zone offset, style is the date style, str is where to write the
* output.
*/ */
void void
EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str) EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, int style, char *str)
{ {
sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min); sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min);
str += strlen(str); str += strlen(str);
AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true); AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
if (tzp != NULL) if (print_tz)
EncodeTimezone(str, *tzp, style); EncodeTimezone(str, tz, style);
} }
/* EncodeDateTime() /* EncodeDateTime()
* Encode date and time interpreted as local time. * Encode date and time interpreted as local time.
* Support several date styles: *
* tm and fsec are the value to encode, print_tz determines whether to include
* a time zone (the difference between timestamp and timestamptz types), tz is
* the numeric time zone offset, tzn is the textual time zone, which if
* specified will be used instead of tz by some styles, style is the date
* style, str is where to write the output.
*
* Supported date styles:
* Postgres - day mon hh:mm:ss yyyy tz * Postgres - day mon hh:mm:ss yyyy tz
* SQL - mm/dd/yyyy hh:mm:ss.ss tz * SQL - mm/dd/yyyy hh:mm:ss.ss tz
* ISO - yyyy-mm-dd hh:mm:ss+/-tz * ISO - yyyy-mm-dd hh:mm:ss+/-tz
* German - dd.mm.yyyy hh:mm:ss tz * German - dd.mm.yyyy hh:mm:ss tz
* XSD - yyyy-mm-ddThh:mm:ss.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
*/ */
void void
EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str) EncodeDateTime(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
{ {
int day; int day;
Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR); Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
/*
* Negative tm_isdst means we have no valid time zone translation.
*/
if (tm->tm_isdst < 0)
print_tz = false;
switch (style) switch (style)
{ {
case USE_ISO_DATES: case USE_ISO_DATES:
@ -3729,14 +3744,8 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
AppendTimestampSeconds(str + strlen(str), tm, fsec); AppendTimestampSeconds(str + strlen(str), tm, fsec);
/* if (print_tz)
* tzp == NULL indicates that we don't want *any* time zone info EncodeTimezone(str, tz, style);
* 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)
EncodeTimezone(str, *tzp, style);
if (tm->tm_year <= 0) if (tm->tm_year <= 0)
sprintf(str + strlen(str), " BC"); sprintf(str + strlen(str), " BC");
@ -3762,12 +3771,12 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
* TZ abbreviations in the Olson database are plain ASCII. * TZ abbreviations in the Olson database are plain ASCII.
*/ */
if (tzp != NULL && tm->tm_isdst >= 0) if (print_tz)
{ {
if (*tzn != NULL) if (tzn)
sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
else else
EncodeTimezone(str, *tzp, style); EncodeTimezone(str, tz, style);
} }
if (tm->tm_year <= 0) if (tm->tm_year <= 0)
@ -3785,12 +3794,12 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
AppendTimestampSeconds(str + strlen(str), tm, fsec); AppendTimestampSeconds(str + strlen(str), tm, fsec);
if (tzp != NULL && tm->tm_isdst >= 0) if (print_tz)
{ {
if (*tzn != NULL) if (tzn)
sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
else else
EncodeTimezone(str, *tzp, style); EncodeTimezone(str, tz, style);
} }
if (tm->tm_year <= 0) if (tm->tm_year <= 0)
@ -3819,10 +3828,10 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
sprintf(str + strlen(str), " %04d", sprintf(str + strlen(str), " %04d",
(tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1)); (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1));
if (tzp != NULL && tm->tm_isdst >= 0) if (print_tz)
{ {
if (*tzn != NULL) if (tzn)
sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
else else
{ {
/* /*
@ -3832,7 +3841,7 @@ EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style,
* the date/time parser later. - thomas 2001-10-19 * the date/time parser later. - thomas 2001-10-19
*/ */
sprintf(str + strlen(str), " "); sprintf(str + strlen(str), " ");
EncodeTimezone(str, *tzp, style); EncodeTimezone(str, tz, style);
} }
} }

@ -311,7 +311,7 @@ abstimeout(PG_FUNCTION_ARGS)
break; break;
default: default:
abstime2tm(time, &tz, tm, &tzn); abstime2tm(time, &tz, tm, &tzn);
EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
break; break;
} }

@ -215,13 +215,12 @@ timestamp_out(PG_FUNCTION_ARGS)
struct pg_tm tt, struct pg_tm tt,
*tm = &tt; *tm = &tt;
fsec_t fsec; fsec_t fsec;
char *tzn = NULL;
char buf[MAXDATELEN + 1]; char buf[MAXDATELEN + 1];
if (TIMESTAMP_NOT_FINITE(timestamp)) if (TIMESTAMP_NOT_FINITE(timestamp))
EncodeSpecialTimestamp(timestamp, buf); EncodeSpecialTimestamp(timestamp, buf);
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf); EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf);
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
@ -501,7 +500,7 @@ timestamptz_out(PG_FUNCTION_ARGS)
if (TIMESTAMP_NOT_FINITE(dt)) if (TIMESTAMP_NOT_FINITE(dt))
EncodeSpecialTimestamp(dt, buf); EncodeSpecialTimestamp(dt, buf);
else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0) else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf); EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
@ -1422,7 +1421,7 @@ timestamptz_to_str(TimestampTz t)
if (TIMESTAMP_NOT_FINITE(t)) if (TIMESTAMP_NOT_FINITE(t))
EncodeSpecialTimestamp(t, buf); EncodeSpecialTimestamp(t, buf);
else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0) else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf); EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
else else
strlcpy(buf, "(timestamp out of range)", sizeof(buf)); strlcpy(buf, "(timestamp out of range)", sizeof(buf));

@ -1987,7 +1987,6 @@ map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
Timestamp timestamp; Timestamp timestamp;
struct pg_tm tm; struct pg_tm tm;
fsec_t fsec; fsec_t fsec;
char *tzn = NULL;
char buf[MAXDATELEN + 1]; char buf[MAXDATELEN + 1];
timestamp = DatumGetTimestamp(value); timestamp = DatumGetTimestamp(value);
@ -1999,7 +1998,7 @@ map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
errmsg("timestamp out of range"), errmsg("timestamp out of range"),
errdetail("XML does not support infinite timestamp values."))); errdetail("XML does not support infinite timestamp values.")));
else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0) else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
EncodeDateTime(&tm, fsec, NULL, &tzn, USE_XSD_DATES, buf); EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
@ -2026,7 +2025,7 @@ map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
errmsg("timestamp out of range"), errmsg("timestamp out of range"),
errdetail("XML does not support infinite timestamp values."))); errdetail("XML does not support infinite timestamp values.")));
else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0) else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
EncodeDateTime(&tm, fsec, &tz, &tzn, USE_XSD_DATES, buf); EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),

@ -290,8 +290,8 @@ extern void DateTimeParseError(int dterr, const char *str,
extern int DetermineTimeZoneOffset(struct pg_tm * tm, pg_tz *tzp); extern int DetermineTimeZoneOffset(struct pg_tm * tm, pg_tz *tzp);
extern void EncodeDateOnly(struct pg_tm * tm, int style, char *str); extern void EncodeDateOnly(struct pg_tm * tm, int style, char *str);
extern void EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str); extern void EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, int style, char *str);
extern void EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str); extern void EncodeDateTime(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str);
extern void EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str); extern void EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str);
extern int DecodeSpecial(int field, char *lowtoken, int *val); extern int DecodeSpecial(int field, char *lowtoken, int *val);

@ -334,12 +334,12 @@ do { \
int DecodeInterval(char **, int *, int, int *, struct tm *, fsec_t *); int DecodeInterval(char **, int *, int, int *, struct tm *, fsec_t *);
int DecodeTime(char *, int *, struct tm *, fsec_t *); int DecodeTime(char *, int *, struct tm *, fsec_t *);
int EncodeDateTime(struct tm *, fsec_t, int *, char **, int, char *, bool); int EncodeDateTime(struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates);
int EncodeInterval(struct tm *, fsec_t, int, char *); int EncodeInterval(struct tm *tm, fsec_t fsec, int style, char *str);
int tm2timestamp(struct tm *, fsec_t, int *, timestamp *); int tm2timestamp(struct tm *, fsec_t, int *, timestamp *);
int DecodeUnits(int field, char *lowtoken, int *val); int DecodeUnits(int field, char *lowtoken, int *val);
bool CheckDateTokenTables(void); bool CheckDateTokenTables(void);
int EncodeDateOnly(struct tm *, int, char *, bool); int EncodeDateOnly(struct tm *tm, int style, char *str, bool EuroDates);
int GetEpochTime(struct tm *); int GetEpochTime(struct tm *);
int ParseDateTime(char *, char *, char **, int *, int *, char **); int ParseDateTime(char *, char *, char **, int *, int *, char **);
int DecodeDateTime(char **, int *, int, int *, struct tm *, fsec_t *, bool); int DecodeDateTime(char **, int *, int, int *, struct tm *, fsec_t *, bool);

@ -759,7 +759,14 @@ TrimTrailingZeros(char *str)
/* EncodeDateTime() /* EncodeDateTime()
* Encode date and time interpreted as local time. * Encode date and time interpreted as local time.
* Support several date styles: *
* tm and fsec are the value to encode, print_tz determines whether to include
* a time zone (the difference between timestamp and timestamptz types), tz is
* the numeric time zone offset, tzn is the textual time zone, which if
* specified will be used instead of tz by some styles, style is the date
* style, str is where to write the output.
*
* Supported date styles:
* Postgres - day mon hh:mm:ss yyyy tz * Postgres - day mon hh:mm:ss yyyy tz
* SQL - mm/dd/yyyy hh:mm:ss.ss tz * SQL - mm/dd/yyyy hh:mm:ss.ss tz
* ISO - yyyy-mm-dd hh:mm:ss+/-tz * ISO - yyyy-mm-dd hh:mm:ss+/-tz
@ -769,12 +776,18 @@ TrimTrailingZeros(char *str)
* European - dd/mm/yyyy * European - dd/mm/yyyy
*/ */
int int
EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str, bool EuroDates) EncodeDateTime(struct tm * tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates)
{ {
int day, int day,
hour, hour,
min; min;
/*
* Negative tm_isdst means we have no valid time zone translation.
*/
if (tm->tm_isdst < 0)
print_tz = false;
switch (style) switch (style)
{ {
case USE_ISO_DATES: case USE_ISO_DATES:
@ -808,16 +821,10 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
if (tm->tm_year <= 0) if (tm->tm_year <= 0)
sprintf(str + strlen(str), " BC"); sprintf(str + strlen(str), " BC");
/* if (print_tz)
* 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 / SECS_PER_HOUR); hour = -(tz / SECS_PER_HOUR);
min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR; min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
if (min != 0) if (min != 0)
sprintf(str + strlen(str), "%+03d:%02d", hour, min); sprintf(str + strlen(str), "%+03d:%02d", hour, min);
else else
@ -867,14 +874,14 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
* TZ abbreviations in the Olson database are plain ASCII. * TZ abbreviations in the Olson database are plain ASCII.
*/ */
if (tzp != NULL && tm->tm_isdst >= 0) if (print_tz)
{ {
if (*tzn != NULL) if (tzn)
sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
else else
{ {
hour = -(*tzp / SECS_PER_HOUR); hour = -(tz / SECS_PER_HOUR);
min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR; min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
if (min != 0) if (min != 0)
sprintf(str + strlen(str), "%+03d:%02d", hour, min); sprintf(str + strlen(str), "%+03d:%02d", hour, min);
else else
@ -916,14 +923,14 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
if (tm->tm_year <= 0) if (tm->tm_year <= 0)
sprintf(str + strlen(str), " BC"); sprintf(str + strlen(str), " BC");
if (tzp != NULL && tm->tm_isdst >= 0) if (print_tz)
{ {
if (*tzn != NULL) if (tzn)
sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
else else
{ {
hour = -(*tzp / SECS_PER_HOUR); hour = -(tz / SECS_PER_HOUR);
min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR; min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
if (min != 0) if (min != 0)
sprintf(str + strlen(str), "%+03d:%02d", hour, min); sprintf(str + strlen(str), "%+03d:%02d", hour, min);
else else
@ -975,10 +982,10 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
if (tm->tm_year <= 0) if (tm->tm_year <= 0)
sprintf(str + strlen(str), " BC"); sprintf(str + strlen(str), " BC");
if (tzp != NULL && tm->tm_isdst >= 0) if (print_tz)
{ {
if (*tzn != NULL) if (tzn)
sprintf(str + strlen(str), " %.*s", MAXTZLEN, *tzn); sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
else else
{ {
/* /*
@ -987,8 +994,8 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
* avoid formatting something which would be rejected by * avoid formatting something which would be rejected by
* the date/time parser later. - thomas 2001-10-19 * the date/time parser later. - thomas 2001-10-19
*/ */
hour = -(*tzp / SECS_PER_HOUR); hour = -(tz / SECS_PER_HOUR);
min = (abs(*tzp) / MINS_PER_HOUR) % MINS_PER_HOUR; min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
if (min != 0) if (min != 0)
sprintf(str + strlen(str), " %+03d:%02d", hour, min); sprintf(str + strlen(str), " %+03d:%02d", hour, min);
else else

@ -354,7 +354,6 @@ PGTYPEStimestamp_to_asc(timestamp tstamp)
struct tm tt, struct tm tt,
*tm = &tt; *tm = &tt;
char buf[MAXDATELEN + 1]; char buf[MAXDATELEN + 1];
char *tzn = NULL;
fsec_t fsec; fsec_t fsec;
int DateStyle = 1; /* this defaults to ISO_DATES, shall we make int DateStyle = 1; /* this defaults to ISO_DATES, shall we make
* it an option? */ * it an option? */
@ -362,7 +361,7 @@ PGTYPEStimestamp_to_asc(timestamp tstamp)
if (TIMESTAMP_NOT_FINITE(tstamp)) if (TIMESTAMP_NOT_FINITE(tstamp))
EncodeSpecialTimestamp(tstamp, buf); EncodeSpecialTimestamp(tstamp, buf);
else if (timestamp2tm(tstamp, NULL, tm, &fsec, NULL) == 0) else if (timestamp2tm(tstamp, NULL, tm, &fsec, NULL) == 0)
EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf, 0); EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf, 0);
else else
{ {
errno = PGTYPES_TS_BAD_TIMESTAMP; errno = PGTYPES_TS_BAD_TIMESTAMP;

Loading…
Cancel
Save