Commit 06edce4c authored by Tom Lane's avatar Tom Lane

Tighten up to_date/to_timestamp so that they are more likely to reject

erroneous input, rather than silently producing bizarre results as formerly
happened.

Brendan Jurd
parent 70530c80
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.446 2008/09/08 00:47:40 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.447 2008/09/11 17:32:33 tgl Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
......@@ -5187,7 +5187,12 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
</itemizedlist>
</para>
<para>
Attempting to construct a date using a mixture of ISO week and Gregorian date fields is nonsensical, and could yield unexpected results. In the context of an ISO year, the concept of a 'month' or 'day of month' has no meaning. In the context of a Gregorian year, the ISO week has no meaning. Users should take care to keep Gregorian and ISO date specifications separate.
Attempting to construct a date using a mixture of ISO week and
Gregorian date fields is nonsensical, and will cause an error. In the
context of an ISO year, the concept of a <quote>month</> or <quote>day
of month</> has no meaning. In the context of a Gregorian year, the
ISO week has no meaning. Users should take care to keep Gregorian and
ISO date specifications separate.
</para>
</listitem>
......
/* -----------------------------------------------------------------------
* formatting.c
*
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.146 2008/08/22 17:57:34 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.147 2008/09/11 17:32:34 tgl Exp $
*
*
* Portions Copyright (c) 1999-2008, PostgreSQL Global Development Group
......@@ -144,6 +144,20 @@ typedef struct
type; /* prefix / postfix */
} KeySuffix;
/* ----------
* FromCharDateMode
* ----------
*
* This value is used to nominate one of several distinct (and mutually
* exclusive) date conventions that a keyword can belong to.
*/
typedef enum
{
FROM_CHAR_DATE_NONE = 0, /* Value does not affect date mode. */
FROM_CHAR_DATE_GREGORIAN, /* Gregorian (day, month, year) style date */
FROM_CHAR_DATE_ISOWEEK /* ISO 8601 week date */
} FromCharDateMode;
typedef struct FormatNode FormatNode;
typedef struct
......@@ -152,6 +166,7 @@ typedef struct
int len;
int id;
bool is_digit;
FromCharDateMode date_mode;
} KeyWord;
struct FormatNode
......@@ -366,6 +381,7 @@ static int NUMCounter = 0;
*/
typedef struct
{
FromCharDateMode mode;
int hh,
am,
pm,
......@@ -377,14 +393,11 @@ typedef struct
ddd,
mm,
ms,
iyear,
year,
bc,
iw,
ww,
w,
cc,
q,
j,
us,
yysz; /* is it YY or YYYY ? */
......@@ -398,11 +411,11 @@ typedef struct
*/
#ifdef DEBUG_TO_FROM_CHAR
#define DEBUG_TMFC(_X) \
elog(DEBUG_elog_output, "TMFC:\nhh %d\nam %d\npm %d\nmi %d\nss %d\nssss %d\nd %d\ndd %d\nddd %d\nmm %d\nms: %d\nyear %d\nbc %d\niw %d\nww %d\nw %d\ncc %d\nq %d\nj %d\nus: %d\nyysz: %d", \
(_X)->hh, (_X)->am, (_X)->pm, (_X)->mi, (_X)->ss, \
elog(DEBUG_elog_output, "TMFC:\nmode %d\nhh %d\nam %d\npm %d\nmi %d\nss %d\nssss %d\nd %d\ndd %d\nddd %d\nmm %d\nms: %d\nyear %d\nbc %d\nww %d\nw %d\ncc %d\nj %d\nus: %d\nyysz: %d", \
(_X)->mode, (_X)->hh, (_X)->am, (_X)->pm, (_X)->mi, (_X)->ss, \
(_X)->ssss, (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, \
(_X)->year, (_X)->bc, (_X)->iw, (_X)->ww, (_X)->w, \
(_X)->cc, (_X)->q, (_X)->j, (_X)->us, (_X)->yysz);
(_X)->year, (_X)->bc, (_X)->ww, (_X)->w, (_X)->cc, (_X)->j, \
(_X)->us, (_X)->yysz);
#define DEBUG_TM(_X) \
elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\
(_X)->tm_sec, (_X)->tm_year,\
......@@ -673,106 +686,108 @@ typedef enum
* ----------
*/
static const KeyWord DCH_keywords[] = {
/* name, len, id, is_digit is in Index */
{"A.D.", 4, DCH_A_D, FALSE}, /* A */
{"A.M.", 4, DCH_A_M, FALSE},
{"AD", 2, DCH_AD, FALSE},
{"AM", 2, DCH_AM, FALSE},
{"B.C.", 4, DCH_B_C, FALSE}, /* B */
{"BC", 2, DCH_BC, FALSE},
{"CC", 2, DCH_CC, TRUE}, /* C */
{"DAY", 3, DCH_DAY, FALSE}, /* D */
{"DDD", 3, DCH_DDD, TRUE},
{"DD", 2, DCH_DD, TRUE},
{"DY", 2, DCH_DY, FALSE},
{"Day", 3, DCH_Day, FALSE},
{"Dy", 2, DCH_Dy, FALSE},
{"D", 1, DCH_D, TRUE},
{"FX", 2, DCH_FX, FALSE}, /* F */
{"HH24", 4, DCH_HH24, TRUE}, /* H */
{"HH12", 4, DCH_HH12, TRUE},
{"HH", 2, DCH_HH, TRUE},
{"IDDD", 4, DCH_IDDD, TRUE}, /* I */
{"ID", 2, DCH_ID, TRUE},
{"IW", 2, DCH_IW, TRUE},
{"IYYY", 4, DCH_IYYY, TRUE},
{"IYY", 3, DCH_IYY, TRUE},
{"IY", 2, DCH_IY, TRUE},
{"I", 1, DCH_I, TRUE},
{"J", 1, DCH_J, TRUE}, /* J */
{"MI", 2, DCH_MI, TRUE}, /* M */
{"MM", 2, DCH_MM, TRUE},
{"MONTH", 5, DCH_MONTH, FALSE},
{"MON", 3, DCH_MON, FALSE},
{"MS", 2, DCH_MS, TRUE},
{"Month", 5, DCH_Month, FALSE},
{"Mon", 3, DCH_Mon, FALSE},
{"P.M.", 4, DCH_P_M, FALSE}, /* P */
{"PM", 2, DCH_PM, FALSE},
{"Q", 1, DCH_Q, TRUE}, /* Q */
{"RM", 2, DCH_RM, FALSE}, /* R */
{"SSSS", 4, DCH_SSSS, TRUE}, /* S */
{"SS", 2, DCH_SS, TRUE},
{"TZ", 2, DCH_TZ, FALSE}, /* T */
{"US", 2, DCH_US, TRUE}, /* U */
{"WW", 2, DCH_WW, TRUE}, /* W */
{"W", 1, DCH_W, TRUE},
{"Y,YYY", 5, DCH_Y_YYY, TRUE}, /* Y */
{"YYYY", 4, DCH_YYYY, TRUE},
{"YYY", 3, DCH_YYY, TRUE},
{"YY", 2, DCH_YY, TRUE},
{"Y", 1, DCH_Y, TRUE},
{"a.d.", 4, DCH_a_d, FALSE}, /* a */
{"a.m.", 4, DCH_a_m, FALSE},
{"ad", 2, DCH_ad, FALSE},
{"am", 2, DCH_am, FALSE},
{"b.c.", 4, DCH_b_c, FALSE}, /* b */
{"bc", 2, DCH_bc, FALSE},
{"cc", 2, DCH_CC, TRUE}, /* c */
{"day", 3, DCH_day, FALSE}, /* d */
{"ddd", 3, DCH_DDD, TRUE},
{"dd", 2, DCH_DD, TRUE},
{"dy", 2, DCH_dy, FALSE},
{"d", 1, DCH_D, TRUE},
{"fx", 2, DCH_FX, FALSE}, /* f */
{"hh24", 4, DCH_HH24, TRUE}, /* h */
{"hh12", 4, DCH_HH12, TRUE},
{"hh", 2, DCH_HH, TRUE},
{"iddd", 4, DCH_IDDD, TRUE}, /* i */
{"id", 2, DCH_ID, TRUE},
{"iw", 2, DCH_IW, TRUE},
{"iyyy", 4, DCH_IYYY, TRUE},
{"iyy", 3, DCH_IYY, TRUE},
{"iy", 2, DCH_IY, TRUE},
{"i", 1, DCH_I, TRUE},
{"j", 1, DCH_J, TRUE}, /* j */
{"mi", 2, DCH_MI, TRUE}, /* m */
{"mm", 2, DCH_MM, TRUE},
{"month", 5, DCH_month, FALSE},
{"mon", 3, DCH_mon, FALSE},
{"ms", 2, DCH_MS, TRUE},
{"p.m.", 4, DCH_p_m, FALSE}, /* p */
{"pm", 2, DCH_pm, FALSE},
{"q", 1, DCH_Q, TRUE}, /* q */
{"rm", 2, DCH_rm, FALSE}, /* r */
{"ssss", 4, DCH_SSSS, TRUE}, /* s */
{"ss", 2, DCH_SS, TRUE},
{"tz", 2, DCH_tz, FALSE}, /* t */
{"us", 2, DCH_US, TRUE}, /* u */
{"ww", 2, DCH_WW, TRUE}, /* w */
{"w", 1, DCH_W, TRUE},
{"y,yyy", 5, DCH_Y_YYY, TRUE}, /* y */
{"yyyy", 4, DCH_YYYY, TRUE},
{"yyy", 3, DCH_YYY, TRUE},
{"yy", 2, DCH_YY, TRUE},
{"y", 1, DCH_Y, TRUE},
/* name, len, id, is_digit, date_mode */
{"A.D.", 4, DCH_A_D, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* A */
{"A.M.", 4, DCH_A_M, FALSE, FROM_CHAR_DATE_NONE},
{"AD", 2, DCH_AD, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"AM", 2, DCH_AM, FALSE, FROM_CHAR_DATE_NONE},
{"B.C.", 4, DCH_B_C, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* B */
{"BC", 2, DCH_BC, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"CC", 2, DCH_CC, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* C */
{"DAY", 3, DCH_DAY, FALSE, FROM_CHAR_DATE_NONE}, /* D */
{"DDD", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"DD", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"DY", 2, DCH_DY, FALSE, FROM_CHAR_DATE_NONE},
{"Day", 3, DCH_Day, FALSE, FROM_CHAR_DATE_NONE},
{"Dy", 2, DCH_Dy, FALSE, FROM_CHAR_DATE_NONE},
{"D", 1, DCH_D, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"FX", 2, DCH_FX, FALSE, FROM_CHAR_DATE_NONE}, /* F */
{"HH24", 4, DCH_HH24, TRUE, FROM_CHAR_DATE_NONE}, /* H */
{"HH12", 4, DCH_HH12, TRUE, FROM_CHAR_DATE_NONE},
{"HH", 2, DCH_HH, TRUE, FROM_CHAR_DATE_NONE},
{"IDDD", 4, DCH_IDDD, TRUE, FROM_CHAR_DATE_ISOWEEK}, /* I */
{"ID", 2, DCH_ID, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"IW", 2, DCH_IW, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"IYYY", 4, DCH_IYYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"IYY", 3, DCH_IYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"IY", 2, DCH_IY, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"I", 1, DCH_I, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"J", 1, DCH_J, TRUE, FROM_CHAR_DATE_NONE}, /* J */
{"MI", 2, DCH_MI, TRUE, FROM_CHAR_DATE_NONE}, /* M */
{"MM", 2, DCH_MM, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"MONTH", 5, DCH_MONTH, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"MON", 3, DCH_MON, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"MS", 2, DCH_MS, TRUE, FROM_CHAR_DATE_NONE},
{"Month", 5, DCH_Month, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"Mon", 3, DCH_Mon, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"P.M.", 4, DCH_P_M, FALSE, FROM_CHAR_DATE_NONE}, /* P */
{"PM", 2, DCH_PM, FALSE, FROM_CHAR_DATE_NONE},
{"Q", 1, DCH_Q, TRUE, FROM_CHAR_DATE_NONE}, /* Q */
{"RM", 2, DCH_RM, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* R */
{"SSSS", 4, DCH_SSSS, TRUE, FROM_CHAR_DATE_NONE}, /* S */
{"SS", 2, DCH_SS, TRUE, FROM_CHAR_DATE_NONE},
{"TZ", 2, DCH_TZ, FALSE, FROM_CHAR_DATE_NONE}, /* T */
{"US", 2, DCH_US, TRUE, FROM_CHAR_DATE_NONE}, /* U */
{"WW", 2, DCH_WW, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* W */
{"W", 1, DCH_W, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"Y,YYY", 5, DCH_Y_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},/* Y */
{"YYYY", 4, DCH_YYYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"YYY", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"YY", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"Y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"a.d.", 4, DCH_a_d, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* a */
{"a.m.", 4, DCH_a_m, FALSE, FROM_CHAR_DATE_NONE},
{"ad", 2, DCH_ad, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"am", 2, DCH_am, FALSE, FROM_CHAR_DATE_NONE},
{"b.c.", 4, DCH_b_c, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* b */
{"bc", 2, DCH_bc, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"cc", 2, DCH_CC, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* c */
{"day", 3, DCH_day, FALSE, FROM_CHAR_DATE_NONE}, /* d */
{"ddd", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"dd", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"dy", 2, DCH_dy, FALSE, FROM_CHAR_DATE_NONE},
{"d", 1, DCH_D, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"fx", 2, DCH_FX, FALSE, FROM_CHAR_DATE_NONE}, /* f */
{"hh24", 4, DCH_HH24, TRUE, FROM_CHAR_DATE_NONE}, /* h */
{"hh12", 4, DCH_HH12, TRUE, FROM_CHAR_DATE_NONE},
{"hh", 2, DCH_HH, TRUE, FROM_CHAR_DATE_NONE},
{"iddd", 4, DCH_IDDD, TRUE, FROM_CHAR_DATE_ISOWEEK}, /* i */
{"id", 2, DCH_ID, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"iw", 2, DCH_IW, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"iyyy", 4, DCH_IYYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"iyy", 3, DCH_IYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"iy", 2, DCH_IY, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"i", 1, DCH_I, TRUE, FROM_CHAR_DATE_ISOWEEK},
{"j", 1, DCH_J, TRUE, FROM_CHAR_DATE_NONE}, /* j */
{"mi", 2, DCH_MI, TRUE, FROM_CHAR_DATE_NONE}, /* m */
{"mm", 2, DCH_MM, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"month", 5, DCH_month, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"mon", 3, DCH_mon, FALSE, FROM_CHAR_DATE_GREGORIAN},
{"ms", 2, DCH_MS, TRUE, FROM_CHAR_DATE_NONE},
{"p.m.", 4, DCH_p_m, FALSE, FROM_CHAR_DATE_NONE}, /* p */
{"pm", 2, DCH_pm, FALSE, FROM_CHAR_DATE_NONE},
{"q", 1, DCH_Q, TRUE, FROM_CHAR_DATE_NONE}, /* q */
{"rm", 2, DCH_rm, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* r */
{"ssss", 4, DCH_SSSS, TRUE, FROM_CHAR_DATE_NONE}, /* s */
{"ss", 2, DCH_SS, TRUE, FROM_CHAR_DATE_NONE},
{"tz", 2, DCH_tz, FALSE, FROM_CHAR_DATE_NONE}, /* t */
{"us", 2, DCH_US, TRUE, FROM_CHAR_DATE_NONE}, /* u */
{"ww", 2, DCH_WW, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* w */
{"w", 1, DCH_W, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"y,yyy", 5, DCH_Y_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},/* y */
{"yyyy", 4, DCH_YYYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"yyy", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"yy", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
{"y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
/* last */
{NULL, 0, 0, 0}
{NULL, 0, 0, 0, 0}
};
/* ----------
* KeyWords for NUMBER version (is_digit field is not needful here...)
* KeyWords for NUMBER version
*
* The is_digit and date_mode fields are not relevant here.
* ----------
*/
static const KeyWord NUM_keywords[] = {
......@@ -925,8 +940,12 @@ static char *get_th(char *num, int type);
static char *str_numth(char *dest, char *num, int type);
static int strspace_len(char *str);
static int strdigits_len(char *str);
static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode);
static void from_char_set_int(int *dest, const int value, const FormatNode *node);
static int from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node);
static int from_char_parse_int(int *dest, char **src, FormatNode *node);
static int seq_search(char *name, char **array, int type, int max, int *len);
static int from_char_seq_search(int *dest, char **src, char **array, int type, int max, FormatNode *node);
static void do_to_timestamp(text *date_txt, text *fmt,
struct pg_tm * tm, fsec_t *fsec);
static char *fill_str(char *str, int c, int max);
......@@ -1081,7 +1100,7 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
NUM_cache_remove(last_NUMCacheEntry);
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("not unique \"S\"")));
errmsg("cannot use \"S\" twice")));
}
if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
{
......@@ -1603,80 +1622,10 @@ str_initcap_z(const char *buff)
/* ----------
* Sequential search with to upper/lower conversion
* Skip TM / th in FROM_CHAR
* ----------
*/
static int
seq_search(char *name, char **array, int type, int max, int *len)
{
char *p,
*n,
**a;
int last,
i;
*len = 0;
if (!*name)
return -1;
/* set first char */
if (type == ONE_UPPER || type == ALL_UPPER)
*name = pg_toupper((unsigned char) *name);
else if (type == ALL_LOWER)
*name = pg_tolower((unsigned char) *name);
for (last = 0, a = array; *a != NULL; a++)
{
/* comperate first chars */
if (*name != **a)
continue;
for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++)
{
/* search fragment (max) only */
if (max && i == max)
{
*len = i;
return a - array;
}
/* full size */
if (*p == '\0')
{
*len = i;
return a - array;
}
/* Not found in array 'a' */
if (*n == '\0')
break;
/*
* Convert (but convert new chars only)
*/
if (i > last)
{
if (type == ONE_UPPER || type == ALL_LOWER)
*n = pg_tolower((unsigned char) *n);
else if (type == ALL_UPPER)
*n = pg_toupper((unsigned char) *n);
last = i;
}
#ifdef DEBUG_TO_FROM_CHAR
/*
* elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)", *n, *p, *a,
* name);
*/
#endif
if (*n != *p)
break;
}
}
return -1;
}
#define SKIP_THth(_suf) (S_THth(_suf) ? 2 : 0)
#ifdef DEBUG_TO_FROM_CHAR
/* -----------
......@@ -1711,12 +1660,6 @@ dump_index(const KeyWord *k, const int *index)
}
#endif /* DEBUG */
/* ----------
* Skip TM / th in FROM_CHAR
* ----------
*/
#define SKIP_THth(_suf) (S_THth(_suf) ? 2 : 0)
/* ----------
* Return TRUE if next format picture is not digit value
* ----------
......@@ -1785,14 +1728,263 @@ strdigits_len(char *str)
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
errmsg("invalid AM/PM string")));
#define CHECK_SEQ_SEARCH(_l, _s) \
do { \
if ((_l) <= 0) { \
ereport(ERROR, \
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
errmsg("invalid value for %s", (_s)))); \
} \
} while (0)
/*
* Set the date mode of a from-char conversion.
*
* Puke if the date mode has already been set, and the caller attempts to set
* it to a conflicting mode.
*/
static void
from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode)
{
if (mode != FROM_CHAR_DATE_NONE)
{
if (tmfc->mode == FROM_CHAR_DATE_NONE)
tmfc->mode = mode;
else if (tmfc->mode != mode)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid combination of date conventions"),
errhint("Do not mix Gregorian and ISO week date "
"conventions in a formatting template.")));
}
}
/*
* Set the integer pointed to by 'dest' to the given value.
*
* Puke if the destination integer has previously been set to some other
* non-zero value.
*/
static void
from_char_set_int(int *dest, const int value, const FormatNode *node)
{
if (*dest != 0 && *dest != value)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("conflicting values for \"%s\" field in formatting string",
node->key->name),
errdetail("This value contradicts a previous setting for "
"the same field type.")));
*dest = value;
}
/*
* Read a single integer from the source string, into the int pointed to by
* 'dest'.
*
* In fixed-width mode (the node does not have the FM suffix), consume at most
* 'len' characters.
*
* We use strtol() to recover the integer value from the source string, in
* accordance with the given FormatNode.
*
* If the conversion completes successfully, src will have been advanced to
* point at the character immediately following the last character used in the
* conversion.
*
* Return the number of characters consumed.
*
* Note that from_char_parse_int() provides a more convenient wrapper where
* the length of the field is the same as the length of the format keyword (as
* with DD and MI).
*/
static int
from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node)
{
long result;
char *init = *src;
if (S_FM(node->suffix) || is_next_separator(node))
{
/*
* This node is in Fill Mode, or the next node is known to be a
* non-digit value, so we just slurp as many characters as we
* can get.
*/
errno = 0;
result = strtol(init, src, 10);
}
else
{
/*
* We need to pull exactly the number of characters given in 'len' out
* of the string, and convert those.
*/
char first[DCH_MAX_ITEM_SIZ + 1];
char *last;
int used;
Assert(len <= DCH_MAX_ITEM_SIZ);
strncpy(first, init, len);
first[len] = '\0';
if (strlen(first) < len)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("source string too short for \"%s\" formatting field",
node->key->name),
errdetail("Field requires %d characters, but only %d "
"remain.",
len, (int) strlen(first)),
errhint("If your source string is not fixed-width, try "
"using the \"FM\" modifier.")));
errno = 0;
result = strtol(first, &last, 10);
used = last - first;
if (used > 0 && used < len)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid value for \"%s\" in source string",
node->key->name),
errdetail("Field requires %d characters, but only %d "
"could be parsed.", len, used),
errhint("If your source string is not fixed-width, try "
"using the \"FM\" modifier.")));
*src += used;
}
if (*src == init)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid value for \"%s\" in source string",
node->key->name),
errdetail("Value must be an integer.")));
if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("value for \"%s\" in source string is out of range",
node->key->name),
errdetail("Value must be in the range %d to %d.",
INT_MIN, INT_MAX)));
from_char_set_int(dest, (int) result, node);
return *src - init;
}
/*
* Call from_char_parse_int_len(), using the length of the format keyword as
* the expected length of the field.
*
* Don't call this function if the field differs in length from the format
* keyword (as with HH24; the keyword length is 4, but the field length is 2).
* In such cases, call from_char_parse_int_len() instead to specify the
* required length explictly.
*/
static int
from_char_parse_int(int *dest, char **src, FormatNode *node)
{
return from_char_parse_int_len(dest, src, node->key->len, node);
}
/* ----------
* Sequential search with to upper/lower conversion
* ----------
*/
static int
seq_search(char *name, char **array, int type, int max, int *len)
{
char *p,
*n,
**a;
int last,
i;
*len = 0;
if (!*name)
return -1;
/* set first char */
if (type == ONE_UPPER || type == ALL_UPPER)
*name = pg_toupper((unsigned char) *name);
else if (type == ALL_LOWER)
*name = pg_tolower((unsigned char) *name);
for (last = 0, a = array; *a != NULL; a++)
{
/* comperate first chars */
if (*name != **a)
continue;
for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++)
{
/* search fragment (max) only */
if (max && i == max)
{
*len = i;
return a - array;
}
/* full size */
if (*p == '\0')
{
*len = i;
return a - array;
}
/* Not found in array 'a' */
if (*n == '\0')
break;
/*
* Convert (but convert new chars only)
*/
if (i > last)
{
if (type == ONE_UPPER || type == ALL_LOWER)
*n = pg_tolower((unsigned char) *n);
else if (type == ALL_UPPER)
*n = pg_toupper((unsigned char) *n);
last = i;
}
#ifdef DEBUG_TO_FROM_CHAR
/*
* elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)", *n, *p, *a,
* name);
*/
#endif
if (*n != *p)
break;
}
}
return -1;
}
/*
* Perform a sequential search in 'array' for text matching the first 'max'
* characters of the source string.
*
* If a match is found, copy the array index of the match into the integer
* pointed to by 'dest', advance 'src' to the end of the part of the string
* which matched, and return the number of characters consumed.
*
* If the string doesn't match, throw an error.
*/
static int
from_char_seq_search(int *dest, char **src, char **array, int type, int max,
FormatNode *node)
{
int result;
int len;
result = seq_search(*src, array, type, max, &len);
if (len <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid value for \"%s\" in source string",
node->key->name),
errdetail("The given value did not match any of the allowed "
"values for this field.")));
from_char_set_int(dest, result, node);
*src += len;
return len;
}
/* ----------
* Process a TmToChar struct as denoted by a list of FormatNodes.
......@@ -2258,9 +2450,7 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
{
FormatNode *n;
char *s;
int len,
x;
int *target;
int len;
bool fx_mode = false;
for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
......@@ -2277,6 +2467,8 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
continue;
}
from_char_set_mode(out, n->key->date_mode);
switch (n->key->id)
{
case DCH_FX:
......@@ -2324,106 +2516,43 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
break;
case DCH_HH:
case DCH_HH12:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->hh);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->hh);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
break;
case DCH_HH24:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->hh);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->hh);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
from_char_parse_int_len(&out->hh, &s, 2, n);
s += SKIP_THth(n->suffix);
break;
case DCH_MI:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->mi);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->mi);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
from_char_parse_int(&out->mi, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_SS:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->ss);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->ss);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
from_char_parse_int(&out->ss, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_MS: /* millisecond */
if (is_next_separator(n))
{
sscanf(s, "%d", &out->ms);
len = x = strdigits_len(s);
}
else
{
sscanf(s, "%03d", &out->ms);
x = strdigits_len(s);
len = x = x > 3 ? 3 : x;
}
len = from_char_parse_int_len(&out->ms, &s, 3, n);
/*
* 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
*/
out->ms *= x == 1 ? 100 :
x == 2 ? 10 : 1;
out->ms *= len == 1 ? 100 :
len == 2 ? 10 : 1;
s += len + SKIP_THth(n->suffix);
break;
case DCH_US: /* microsecond */
if (is_next_separator(n))
{
sscanf(s, "%d", &out->us);
len = x = strdigits_len(s);
}
else
{
sscanf(s, "%06d", &out->us);
x = strdigits_len(s);
len = x = x > 6 ? 6 : x;
}
len = from_char_parse_int_len(&out->us, &s, 6, n);
out->us *= x == 1 ? 100000 :
x == 2 ? 10000 :
x == 3 ? 1000 :
x == 4 ? 100 :
x == 5 ? 10 : 1;
out->us *= len == 1 ? 100000 :
len == 2 ? 10000 :
len == 3 ? 1000 :
len == 4 ? 100 :
len == 5 ? 10 : 1;
s += len + SKIP_THth(n->suffix);
break;
case DCH_SSSS:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->ssss);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%05d", &out->ssss);
s += strspace_len(s) + 5 + SKIP_THth(n->suffix);
}
from_char_parse_int(&out->ssss, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_tz:
case DCH_TZ:
......@@ -2457,205 +2586,153 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
case DCH_MONTH:
case DCH_Month:
case DCH_month:
out->mm = seq_search(s, months_full, ONE_UPPER, FULL_SIZ, &len) + 1;
CHECK_SEQ_SEARCH(len, "MONTH/Month/month");
s += len;
from_char_seq_search(&out->mm, &s, months_full, ONE_UPPER,
FULL_SIZ, n);
out->mm++;
break;
case DCH_MON:
case DCH_Mon:
case DCH_mon:
out->mm = seq_search(s, months, ONE_UPPER, MAX_MON_LEN, &len) + 1;
CHECK_SEQ_SEARCH(len, "MON/Mon/mon");
s += len;
from_char_seq_search(&out->mm, &s, months, ONE_UPPER,
MAX_MON_LEN, n);
out->mm++;
break;
case DCH_MM:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->mm);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->mm);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
from_char_parse_int(&out->mm, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_DAY:
case DCH_Day:
case DCH_day:
out->d = seq_search(s, days, ONE_UPPER, FULL_SIZ, &len);
CHECK_SEQ_SEARCH(len, "DAY/Day/day");
s += len;
from_char_seq_search(&out->d, &s, days, ONE_UPPER,
FULL_SIZ, n);
break;
case DCH_DY:
case DCH_Dy:
case DCH_dy:
out->d = seq_search(s, days, ONE_UPPER, MAX_DY_LEN, &len);
CHECK_SEQ_SEARCH(len, "DY/Dy/dy");
s += len;
from_char_seq_search(&out->d, &s, days, ONE_UPPER,
MAX_DY_LEN, n);
break;
case DCH_DDD:
from_char_parse_int(&out->ddd, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_IDDD:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->ddd);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%03d", &out->ddd);
s += strspace_len(s) + 3 + SKIP_THth(n->suffix);
}
from_char_parse_int_len(&out->ddd, &s, 3, n);
s += SKIP_THth(n->suffix);
break;
case DCH_DD:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->dd);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->dd);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
from_char_parse_int(&out->dd, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_D:
case DCH_ID:
sscanf(s, "%1d", &out->d);
if (n->key->id == DCH_D)
from_char_parse_int(&out->d, &s, n);
out->d--;
s += strspace_len(s) + 1 + SKIP_THth(n->suffix);
s += SKIP_THth(n->suffix);
break;
case DCH_WW:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->ww);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->ww);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
case DCH_ID:
from_char_parse_int_len(&out->d, &s, 1, n);
s += SKIP_THth(n->suffix);
break;
case DCH_WW:
case DCH_IW:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->iw);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->iw);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
from_char_parse_int(&out->ww, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_Q:
/*
* We ignore Q when converting to date because it is not
* normative.
*
* We still parse the source string for an integer, but it
* isn't stored anywhere in 'out'.
*/
s += strspace_len(s) + 1 + SKIP_THth(n->suffix);
from_char_parse_int((int *) NULL, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_CC:
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", &out->cc);
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%02d", &out->cc);
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
}
from_char_parse_int(&out->cc, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_Y_YYY:
sscanf(s, "%d,%03d", &x, &out->year);
out->year += (x * 1000);
{
int matched, years, millenia;
matched = sscanf(s, "%d,%03d", &millenia, &years);
if (matched != 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input string for \"Y,YYY\"")));
years += (millenia * 1000);
from_char_set_int(&out->year, years, n);
out->yysz = 4;
s += strdigits_len(s) + 4 + SKIP_THth(n->suffix);
}
break;
case DCH_YYYY:
case DCH_IYYY:
target = (n->key->id == DCH_YYYY) ? &out->year : &out->iyear;
if (S_FM(n->suffix) || is_next_separator(n))
{
sscanf(s, "%d", target);
out->yysz = 4;
s += strdigits_len(s) + SKIP_THth(n->suffix);
}
else
{
sscanf(s, "%04d", target);
from_char_parse_int(&out->year, &s, n);
out->yysz = 4;
s += strspace_len(s) + 4 + SKIP_THth(n->suffix);
}
s += SKIP_THth(n->suffix);
break;
case DCH_YYY:
case DCH_IYY:
target = (n->key->id == DCH_YYY) ? &out->year : &out->iyear;
sscanf(s, "%03d", target);
from_char_parse_int(&out->year, &s, n);
out->yysz = 3;
/*
* 3-digit year: '100' ... '999' = 1100 ... 1999 '000' ...
* '099' = 2000 ... 2099
*/
if (*target >= 100)
*target += 1000;
if (out->year >= 100)
out->year += 1000;
else
*target += 2000;
out->yysz = 3;
s += strspace_len(s) + 3 + SKIP_THth(n->suffix);
out->year += 2000;
s += SKIP_THth(n->suffix);
break;
case DCH_YY:
case DCH_IY:
target = (n->key->id == DCH_YY) ? &out->year : &out->iyear;
sscanf(s, "%02d", target);
from_char_parse_int(&out->year, &s, n);
out->yysz = 2;
/*
* 2-digit year: '00' ... '69' = 2000 ... 2069 '70' ... '99'
* = 1970 ... 1999
*/
if (*target < 70)
*target += 2000;
if (out->year < 70)
out->year += 2000;
else
*target += 1900;
out->yysz = 2;
s += strspace_len(s) + 2 + SKIP_THth(n->suffix);
out->year += 1900;
s += SKIP_THth(n->suffix);
break;
case DCH_Y:
case DCH_I:
target = (n->key->id == DCH_Y) ? &out->year : &out->iyear;
sscanf(s, "%1d", target);
from_char_parse_int(&out->year, &s, n);
out->yysz = 1;
/*
* 1-digit year: always +2000
*/
*target += 2000;
out->yysz = 1;
s += strspace_len(s) + 1 + SKIP_THth(n->suffix);
out->year += 2000;
s += SKIP_THth(n->suffix);
break;
case DCH_RM:
out->mm = 12 - seq_search(s, rm_months_upper, ALL_UPPER, FULL_SIZ, &len);
CHECK_SEQ_SEARCH(len, "RM");
s += len;
from_char_seq_search(&out->mm, &s, rm_months_upper,
ALL_UPPER, FULL_SIZ, n);
out->mm = 12 - out->mm;
break;
case DCH_rm:
out->mm = 12 - seq_search(s, rm_months_lower, ALL_LOWER, FULL_SIZ, &len);
CHECK_SEQ_SEARCH(len, "rm");
s += len;
from_char_seq_search(&out->mm, &s, rm_months_lower,
ALL_LOWER, FULL_SIZ, n);
out->mm = 12 - out->mm;
break;
case DCH_W:
sscanf(s, "%1d", &out->w);
s += strspace_len(s) + 1 + SKIP_THth(n->suffix);
from_char_parse_int(&out->w, &s, n);
s += SKIP_THth(n->suffix);
break;
case DCH_J:
sscanf(s, "%d", &out->j);
s += strdigits_len(s) + SKIP_THth(n->suffix);
from_char_parse_int(&out->j, &s, n);
s += SKIP_THth(n->suffix);
break;
}
}
......@@ -3002,8 +3079,7 @@ do_to_timestamp(text *date_txt, text *fmt,
{
FormatNode *format;
TmFromChar tmfc;
int fmt_len,
year;
int fmt_len;
ZERO_tmfc(&tmfc);
ZERO_tm(tm);
......@@ -3093,12 +3169,6 @@ do_to_timestamp(text *date_txt, text *fmt,
tm->tm_sec = x;
}
if (tmfc.ww)
tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
if (tmfc.w)
tmfc.dd = (tmfc.w - 1) * 7 + 1;
if (tmfc.ss)
tm->tm_sec = tmfc.ss;
if (tmfc.mi)
......@@ -3120,33 +3190,7 @@ do_to_timestamp(text *date_txt, text *fmt,
tm->tm_hour = 0;
}
switch (tmfc.q)
{
case 1:
tm->tm_mday = 1;
tm->tm_mon = 1;
break;
case 2:
tm->tm_mday = 1;
tm->tm_mon = 4;
break;
case 3:
tm->tm_mday = 1;
tm->tm_mon = 7;
break;
case 4:
tm->tm_mday = 1;
tm->tm_mon = 10;
break;
}
/*
* Only one year value is used. If iyear (the ISO year) is defined, it
* takes precedence. Otherwise year (the Gregorian year) is used.
*/
year = (tmfc.iyear) ? tmfc.iyear : tmfc.year;
if (year)
if (tmfc.year)
{
/*
* If CC and YY (or Y) are provided, use YY as 2 low-order digits for
......@@ -3157,14 +3201,14 @@ do_to_timestamp(text *date_txt, text *fmt,
*/
if (tmfc.cc && tmfc.yysz <= 2)
{
tm->tm_year = year % 100;
tm->tm_year = tmfc.year % 100;
if (tm->tm_year)
tm->tm_year += (tmfc.cc - 1) * 100;
else
tm->tm_year = tmfc.cc * 100;
}
else
tm->tm_year = year;
tm->tm_year = tmfc.year;
}
else if (tmfc.cc) /* use first year of century */
tm->tm_year = (tmfc.cc - 1) * 100 + 1;
......@@ -3183,31 +3227,30 @@ do_to_timestamp(text *date_txt, text *fmt,
if (tmfc.j)
j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
if (tmfc.iw)
if (tmfc.ww)
{
if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
{
/*
* Since the user has employed the IW field, it is assumed that the
* value in tmfc.d is in ISO day-of-week form (1 = Monday), as set by
* the ID field. Mixing IW and D will yield weird results.
*
* tmfc.iyear must have been set (e.g., with IYYY) for this to work
* properly (an ISO week without an ISO year is meaningless).
*
* If tmfc.d is not set, then the date is left at the beginning of the
* ISO week (Monday).
* If tmfc.d is not set, then the date is left at the beginning of
* the ISO week (Monday).
*/
if (tmfc.d)
isoweekdate2date(tmfc.iw, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
else
isoweek2date(tmfc.iw, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
}
else
tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
}
if (tmfc.w)
tmfc.dd = (tmfc.w - 1) * 7 + 1;
if (tmfc.d)
tm->tm_wday = tmfc.d;
if (tmfc.dd)
tm->tm_mday = tmfc.dd;
if (tmfc.ddd && !tmfc.iyear)
if (tmfc.ddd)
tm->tm_yday = tmfc.ddd;
if (tmfc.mm)
tm->tm_mon = tmfc.mm;
......@@ -3215,16 +3258,16 @@ do_to_timestamp(text *date_txt, text *fmt,
if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
{
/*
* If the iyear field is set, the value of ddd is taken to be an ISO
* day-of-year. Otherwise, it is a Gregorian day-of-year. Either way,
* since the month and day fields have not been set by some other
* means, the value of ddd will be used to compute them.
* The month and day field have not been set, so we use the day-of-year
* field to populate them. Depending on the date mode, this field may
* be interpreted as a Gregorian day-of-year, or an ISO week date
* day-of-year.
*/
if (tmfc.iyear)
if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
{
int j0; /* zeroth day of the ISO year, in Julian */
j0 = isoweek2j(tmfc.iyear, 1) - 1;
j0 = isoweek2j(tmfc.year, 1) - 1;
j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
}
......
......@@ -2705,3 +2705,160 @@ SELECT '' AS seven, f1 AS european_sql FROM ABSTIME_TBL;
(7 rows)
RESET DateStyle;
--
-- to_timestamp()
--
SELECT '' AS to_timestamp_1, to_timestamp('0097/Feb/16 --> 08:14:30', 'YYYY/Mon/DD --> HH:MI:SS');
to_timestamp_1 | to_timestamp
----------------+------------------------------
| Sat Feb 16 08:14:30 0097 PST
(1 row)
SELECT '' AS to_timestamp_2, to_timestamp('97/2/16 8:14:30', 'FMYYYY/FMMM/FMDD FMHH:FMMI:FMSS');
to_timestamp_2 | to_timestamp
----------------+------------------------------
| Sat Feb 16 08:14:30 0097 PST
(1 row)
SELECT '' AS to_timestamp_3, to_timestamp('1985 January 12', 'YYYY FMMonth DD');
to_timestamp_3 | to_timestamp
----------------+------------------------------
| Sat Jan 12 00:00:00 1985 PST
(1 row)
SELECT '' AS to_timestamp_4, to_timestamp('My birthday-> Year: 1976, Month: May, Day: 16',
'"My birthday-> Year" YYYY, "Month:" FMMonth, "Day:" DD');
to_timestamp_4 | to_timestamp
----------------+------------------------------
| Sun May 16 00:00:00 1976 PDT
(1 row)
SELECT '' AS to_timestamp_5, to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD');
to_timestamp_5 | to_timestamp
----------------+------------------------------
| Sat Aug 21 00:00:00 1582 PST
(1 row)
SELECT '' AS to_timestamp_6, to_timestamp('15 "text between quote marks" 98 54 45',
E'HH "\\text between quote marks\\"" YY MI SS');
to_timestamp_6 | to_timestamp
----------------+------------------------------
| Thu Jan 01 15:54:45 1998 PST
(1 row)
SELECT '' AS to_timestamp_7, to_timestamp('05121445482000', 'MMDDHHMISSYYYY');
to_timestamp_7 | to_timestamp
----------------+------------------------------
| Fri May 12 14:45:48 2000 PDT
(1 row)
SELECT '' AS to_timestamp_8, to_timestamp('2000January09Sunday', 'YYYYFMMonthDDFMDay');
to_timestamp_8 | to_timestamp
----------------+------------------------------
| Sun Jan 09 00:00:00 2000 PST
(1 row)
SELECT '' AS to_timestamp_9, to_timestamp('97/Feb/16', 'YYMonDD');
ERROR: invalid value for "Mon" in source string
DETAIL: The given value did not match any of the allowed values for this field.
SELECT '' AS to_timestamp_10, to_timestamp('19971116', 'YYYYMMDD');
to_timestamp_10 | to_timestamp
-----------------+------------------------------
| Sun Nov 16 00:00:00 1997 PST
(1 row)
SELECT '' AS to_timestamp_11, to_timestamp('20000-1116', 'YYYY-MMDD');
to_timestamp_11 | to_timestamp
-----------------+-------------------------------
| Thu Nov 16 00:00:00 20000 PST
(1 row)
SELECT '' AS to_timestamp_12, to_timestamp('9-1116', 'Y-MMDD');
to_timestamp_12 | to_timestamp
-----------------+------------------------------
| Mon Nov 16 00:00:00 2009 PST
(1 row)
SELECT '' AS to_timestamp_13, to_timestamp('95-1116', 'YY-MMDD');
to_timestamp_13 | to_timestamp
-----------------+------------------------------
| Thu Nov 16 00:00:00 1995 PST
(1 row)
SELECT '' AS to_timestamp_14, to_timestamp('995-1116', 'YYY-MMDD');
to_timestamp_14 | to_timestamp
-----------------+------------------------------
| Thu Nov 16 00:00:00 1995 PST
(1 row)
SELECT '' AS to_timestamp_15, to_timestamp('2005426', 'YYYYWWD');
to_timestamp_15 | to_timestamp
-----------------+------------------------------
| Sat Oct 15 00:00:00 2005 PDT
(1 row)
SELECT '' AS to_timestamp_16, to_timestamp('2005300', 'YYYYDDD');
to_timestamp_16 | to_timestamp
-----------------+------------------------------
| Thu Oct 27 00:00:00 2005 PDT
(1 row)
SELECT '' AS to_timestamp_17, to_timestamp('2005527', 'IYYYIWID');
to_timestamp_17 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_18, to_timestamp('005527', 'IYYIWID');
to_timestamp_18 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_19, to_timestamp('05527', 'IYIWID');
to_timestamp_19 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_20, to_timestamp('5527', 'IIWID');
to_timestamp_20 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_21, to_timestamp('2005364', 'IYYYIDDD');
to_timestamp_21 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
--
-- Check errors for some incorrect usages of to_timestamp()
--
-- Mixture of date conventions (ISO week and Gregorian):
SELECT '' AS to_timestamp_22, to_timestamp('2005527', 'YYYYIWID');
ERROR: invalid combination of date conventions
HINT: Do not mix Gregorian and ISO week date conventions in a formatting template.
-- Insufficient characters in the source string:
SELECT '' AS to_timestamp_23, to_timestamp('19971', 'YYYYMMDD');
ERROR: source string too short for "MM" formatting field
DETAIL: Field requires 2 characters, but only 1 remain.
HINT: If your source string is not fixed-width, try using the "FM" modifier.
-- Insufficient digit characters for a single node:
SELECT '' AS to_timestamp_24, to_timestamp('19971)24', 'YYYYMMDD');
ERROR: invalid value for "MM" in source string
DETAIL: Field requires 2 characters, but only 1 could be parsed.
HINT: If your source string is not fixed-width, try using the "FM" modifier.
-- Value clobbering:
SELECT '' AS to_timestamp_25, to_timestamp('1997-11-Jan-16', 'YYYY-MM-Mon-DD');
ERROR: conflicting values for "Mon" field in formatting string
DETAIL: This value contradicts a previous setting for the same field type.
-- Non-numeric input:
SELECT '' AS to_timestamp_26, to_timestamp('199711xy', 'YYYYMMDD');
ERROR: invalid value for "DD" in source string
DETAIL: Value must be an integer.
-- Input that doesn't fit in an int:
SELECT '' AS to_timestamp_27, to_timestamp('10000000000', 'FMYYYY');
ERROR: value for "YYYY" in source string is out of range
DETAIL: Value must be in the range -2147483648 to 2147483647.
......@@ -1590,130 +1590,3 @@ SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
| 2001 001 01 1 1 1 1
(65 rows)
-- TO_TIMESTAMP()
SELECT '' AS to_timestamp_1, to_timestamp('0097/Feb/16 --> 08:14:30', 'YYYY/Mon/DD --> HH:MI:SS');
to_timestamp_1 | to_timestamp
----------------+------------------------------
| Sat Feb 16 08:14:30 0097 PST
(1 row)
SELECT '' AS to_timestamp_2, to_timestamp('97/2/16 8:14:30', 'FMYYYY/FMMM/FMDD FMHH:FMMI:FMSS');
to_timestamp_2 | to_timestamp
----------------+------------------------------
| Sat Feb 16 08:14:30 0097 PST
(1 row)
SELECT '' AS to_timestamp_3, to_timestamp('1985 January 12', 'YYYY FMMonth DD');
to_timestamp_3 | to_timestamp
----------------+------------------------------
| Sat Jan 12 00:00:00 1985 PST
(1 row)
SELECT '' AS to_timestamp_4, to_timestamp('My birthday-> Year: 1976, Month: May, Day: 16',
'"My birthday-> Year" YYYY, "Month:" FMMonth, "Day:" DD');
to_timestamp_4 | to_timestamp
----------------+------------------------------
| Sun May 16 00:00:00 1976 PDT
(1 row)
SELECT '' AS to_timestamp_5, to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD');
to_timestamp_5 | to_timestamp
----------------+------------------------------
| Sat Aug 21 00:00:00 1582 PST
(1 row)
SELECT '' AS to_timestamp_6, to_timestamp('15 "text between quote marks" 98 54 45',
E'HH "\\text between quote marks\\"" YY MI SS');
to_timestamp_6 | to_timestamp
----------------+------------------------------
| Thu Jan 01 15:54:45 1998 PST
(1 row)
SELECT '' AS to_timestamp_7, to_timestamp('05121445482000', 'MMDDHHMISSYYYY');
to_timestamp_7 | to_timestamp
----------------+------------------------------
| Fri May 12 14:45:48 2000 PDT
(1 row)
SELECT '' AS to_timestamp_8, to_timestamp('2000January09Sunday', 'YYYYFMMonthDDFMDay');
to_timestamp_8 | to_timestamp
----------------+------------------------------
| Sun Jan 09 00:00:00 2000 PST
(1 row)
SELECT '' AS to_timestamp_9, to_timestamp('97/Feb/16', 'YYMonDD');
ERROR: invalid value for MON/Mon/mon
SELECT '' AS to_timestamp_10, to_timestamp('19971116', 'YYYYMMDD');
to_timestamp_10 | to_timestamp
-----------------+------------------------------
| Sun Nov 16 00:00:00 1997 PST
(1 row)
SELECT '' AS to_timestamp_11, to_timestamp('20000-1116', 'YYYY-MMDD');
to_timestamp_11 | to_timestamp
-----------------+-------------------------------
| Thu Nov 16 00:00:00 20000 PST
(1 row)
SELECT '' AS to_timestamp_12, to_timestamp('9-1116', 'Y-MMDD');
to_timestamp_12 | to_timestamp
-----------------+------------------------------
| Mon Nov 16 00:00:00 2009 PST
(1 row)
SELECT '' AS to_timestamp_13, to_timestamp('95-1116', 'YY-MMDD');
to_timestamp_13 | to_timestamp
-----------------+------------------------------
| Thu Nov 16 00:00:00 1995 PST
(1 row)
SELECT '' AS to_timestamp_14, to_timestamp('995-1116', 'YYY-MMDD');
to_timestamp_14 | to_timestamp
-----------------+------------------------------
| Thu Nov 16 00:00:00 1995 PST
(1 row)
SELECT '' AS to_timestamp_15, to_timestamp('2005426', 'YYYYWWD');
to_timestamp_15 | to_timestamp
-----------------+------------------------------
| Sat Oct 15 00:00:00 2005 PDT
(1 row)
SELECT '' AS to_timestamp_16, to_timestamp('2005300', 'YYYYDDD');
to_timestamp_16 | to_timestamp
-----------------+------------------------------
| Thu Oct 27 00:00:00 2005 PDT
(1 row)
SELECT '' AS to_timestamp_17, to_timestamp('2005527', 'IYYYIWID');
to_timestamp_17 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_18, to_timestamp('005527', 'IYYIWID');
to_timestamp_18 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_19, to_timestamp('05527', 'IYIWID');
to_timestamp_19 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_20, to_timestamp('5527', 'IIWID');
to_timestamp_20 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_21, to_timestamp('2005364', 'IYYYIDDD');
to_timestamp_21 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SET DateStyle TO DEFAULT;
......@@ -1684,131 +1684,3 @@ SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
| 2001 001 01 1 1 1 1
(66 rows)
-- TO_TIMESTAMP()
SELECT '' AS to_timestamp_1, to_timestamp('0097/Feb/16 --> 08:14:30', 'YYYY/Mon/DD --> HH:MI:SS');
to_timestamp_1 | to_timestamp
----------------+------------------------------
| Sat Feb 16 08:14:30 0097 PST
(1 row)
SELECT '' AS to_timestamp_2, to_timestamp('97/2/16 8:14:30', 'FMYYYY/FMMM/FMDD FMHH:FMMI:FMSS');
to_timestamp_2 | to_timestamp
----------------+------------------------------
| Sat Feb 16 08:14:30 0097 PST
(1 row)
SELECT '' AS to_timestamp_3, to_timestamp('1985 January 12', 'YYYY FMMonth DD');
to_timestamp_3 | to_timestamp
----------------+------------------------------
| Sat Jan 12 00:00:00 1985 PST
(1 row)
SELECT '' AS to_timestamp_4, to_timestamp('My birthday-> Year: 1976, Month: May, Day: 16',
'"My birthday-> Year" YYYY, "Month:" FMMonth, "Day:" DD');
to_timestamp_4 | to_timestamp
----------------+------------------------------
| Sun May 16 00:00:00 1976 PDT
(1 row)
SELECT '' AS to_timestamp_5, to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD');
to_timestamp_5 | to_timestamp
----------------+------------------------------
| Sat Aug 21 00:00:00 1582 PST
(1 row)
SELECT '' AS to_timestamp_6, to_timestamp('15 "text between quote marks" 98 54 45',
E'HH "\\text between quote marks\\"" YY MI SS');
to_timestamp_6 | to_timestamp
----------------+------------------------------
| Thu Jan 01 15:54:45 1998 PST
(1 row)
SELECT '' AS to_timestamp_7, to_timestamp('05121445482000', 'MMDDHHMISSYYYY');
to_timestamp_7 | to_timestamp
----------------+------------------------------
| Fri May 12 14:45:48 2000 PDT
(1 row)
SELECT '' AS to_timestamp_8, to_timestamp('2000January09Sunday', 'YYYYFMMonthDDFMDay');
to_timestamp_8 | to_timestamp
----------------+------------------------------
| Sun Jan 09 00:00:00 2000 PST
(1 row)
SELECT '' AS to_timestamp_9, to_timestamp('97/Feb/16', 'YYMonDD');
ERROR: invalid value for MON/Mon/mon
SELECT '' AS to_timestamp_10, to_timestamp('19971116', 'YYYYMMDD');
to_timestamp_10 | to_timestamp
-----------------+------------------------------
| Sun Nov 16 00:00:00 1997 PST
(1 row)
SELECT '' AS to_timestamp_11, to_timestamp('20000-1116', 'YYYY-MMDD');
to_timestamp_11 | to_timestamp
-----------------+-------------------------------
| Thu Nov 16 00:00:00 20000 PST
(1 row)
SELECT '' AS to_timestamp_12, to_timestamp('9-1116', 'Y-MMDD');
to_timestamp_12 | to_timestamp
-----------------+------------------------------
| Mon Nov 16 00:00:00 2009 PST
(1 row)
SELECT '' AS to_timestamp_13, to_timestamp('95-1116', 'YY-MMDD');
to_timestamp_13 | to_timestamp
-----------------+------------------------------
| Thu Nov 16 00:00:00 1995 PST
(1 row)
SELECT '' AS to_timestamp_14, to_timestamp('995-1116', 'YYY-MMDD');
to_timestamp_14 | to_timestamp
-----------------+------------------------------
| Thu Nov 16 00:00:00 1995 PST
(1 row)
SELECT '' AS to_timestamp_15, to_timestamp('2005426', 'YYYYWWD');
to_timestamp_15 | to_timestamp
-----------------+------------------------------
| Sat Oct 15 00:00:00 2005 PDT
(1 row)
SELECT '' AS to_timestamp_16, to_timestamp('2005300', 'YYYYDDD');
to_timestamp_16 | to_timestamp
-----------------+------------------------------
| Thu Oct 27 00:00:00 2005 PDT
(1 row)
SELECT '' AS to_timestamp_17, to_timestamp('2005527', 'IYYYIWID');
to_timestamp_17 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_18, to_timestamp('005527', 'IYYIWID');
to_timestamp_18 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_19, to_timestamp('05527', 'IYIWID');
to_timestamp_19 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_20, to_timestamp('5527', 'IIWID');
to_timestamp_20 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SELECT '' AS to_timestamp_21, to_timestamp('2005364', 'IYYYIDDD');
to_timestamp_21 | to_timestamp
-----------------+------------------------------
| Sun Jan 01 00:00:00 2006 PST
(1 row)
SET DateStyle TO DEFAULT;
......@@ -374,3 +374,73 @@ SELECT '' AS "65", d1 AS european_sql FROM TIMESTAMP_TBL;
SELECT '' AS seven, f1 AS european_sql FROM ABSTIME_TBL;
RESET DateStyle;
--
-- to_timestamp()
--
SELECT '' AS to_timestamp_1, to_timestamp('0097/Feb/16 --> 08:14:30', 'YYYY/Mon/DD --> HH:MI:SS');
SELECT '' AS to_timestamp_2, to_timestamp('97/2/16 8:14:30', 'FMYYYY/FMMM/FMDD FMHH:FMMI:FMSS');
SELECT '' AS to_timestamp_3, to_timestamp('1985 January 12', 'YYYY FMMonth DD');
SELECT '' AS to_timestamp_4, to_timestamp('My birthday-> Year: 1976, Month: May, Day: 16',
'"My birthday-> Year" YYYY, "Month:" FMMonth, "Day:" DD');
SELECT '' AS to_timestamp_5, to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD');
SELECT '' AS to_timestamp_6, to_timestamp('15 "text between quote marks" 98 54 45',
E'HH "\\text between quote marks\\"" YY MI SS');
SELECT '' AS to_timestamp_7, to_timestamp('05121445482000', 'MMDDHHMISSYYYY');
SELECT '' AS to_timestamp_8, to_timestamp('2000January09Sunday', 'YYYYFMMonthDDFMDay');
SELECT '' AS to_timestamp_9, to_timestamp('97/Feb/16', 'YYMonDD');
SELECT '' AS to_timestamp_10, to_timestamp('19971116', 'YYYYMMDD');
SELECT '' AS to_timestamp_11, to_timestamp('20000-1116', 'YYYY-MMDD');
SELECT '' AS to_timestamp_12, to_timestamp('9-1116', 'Y-MMDD');
SELECT '' AS to_timestamp_13, to_timestamp('95-1116', 'YY-MMDD');
SELECT '' AS to_timestamp_14, to_timestamp('995-1116', 'YYY-MMDD');
SELECT '' AS to_timestamp_15, to_timestamp('2005426', 'YYYYWWD');
SELECT '' AS to_timestamp_16, to_timestamp('2005300', 'YYYYDDD');
SELECT '' AS to_timestamp_17, to_timestamp('2005527', 'IYYYIWID');
SELECT '' AS to_timestamp_18, to_timestamp('005527', 'IYYIWID');
SELECT '' AS to_timestamp_19, to_timestamp('05527', 'IYIWID');
SELECT '' AS to_timestamp_20, to_timestamp('5527', 'IIWID');
SELECT '' AS to_timestamp_21, to_timestamp('2005364', 'IYYYIDDD');
--
-- Check errors for some incorrect usages of to_timestamp()
--
-- Mixture of date conventions (ISO week and Gregorian):
SELECT '' AS to_timestamp_22, to_timestamp('2005527', 'YYYYIWID');
-- Insufficient characters in the source string:
SELECT '' AS to_timestamp_23, to_timestamp('19971', 'YYYYMMDD');
-- Insufficient digit characters for a single node:
SELECT '' AS to_timestamp_24, to_timestamp('19971)24', 'YYYYMMDD');
-- Value clobbering:
SELECT '' AS to_timestamp_25, to_timestamp('1997-11-Jan-16', 'YYYY-MM-Mon-DD');
-- Non-numeric input:
SELECT '' AS to_timestamp_26, to_timestamp('199711xy', 'YYYYMMDD');
-- Input that doesn't fit in an int:
SELECT '' AS to_timestamp_27, to_timestamp('10000000000', 'FMYYYY');
......@@ -223,50 +223,3 @@ SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID')
SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
FROM TIMESTAMP_TBL;
-- TO_TIMESTAMP()
SELECT '' AS to_timestamp_1, to_timestamp('0097/Feb/16 --> 08:14:30', 'YYYY/Mon/DD --> HH:MI:SS');
SELECT '' AS to_timestamp_2, to_timestamp('97/2/16 8:14:30', 'FMYYYY/FMMM/FMDD FMHH:FMMI:FMSS');
SELECT '' AS to_timestamp_3, to_timestamp('1985 January 12', 'YYYY FMMonth DD');
SELECT '' AS to_timestamp_4, to_timestamp('My birthday-> Year: 1976, Month: May, Day: 16',
'"My birthday-> Year" YYYY, "Month:" FMMonth, "Day:" DD');
SELECT '' AS to_timestamp_5, to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD');
SELECT '' AS to_timestamp_6, to_timestamp('15 "text between quote marks" 98 54 45',
E'HH "\\text between quote marks\\"" YY MI SS');
SELECT '' AS to_timestamp_7, to_timestamp('05121445482000', 'MMDDHHMISSYYYY');
SELECT '' AS to_timestamp_8, to_timestamp('2000January09Sunday', 'YYYYFMMonthDDFMDay');
SELECT '' AS to_timestamp_9, to_timestamp('97/Feb/16', 'YYMonDD');
SELECT '' AS to_timestamp_10, to_timestamp('19971116', 'YYYYMMDD');
SELECT '' AS to_timestamp_11, to_timestamp('20000-1116', 'YYYY-MMDD');
SELECT '' AS to_timestamp_12, to_timestamp('9-1116', 'Y-MMDD');
SELECT '' AS to_timestamp_13, to_timestamp('95-1116', 'YY-MMDD');
SELECT '' AS to_timestamp_14, to_timestamp('995-1116', 'YYY-MMDD');
SELECT '' AS to_timestamp_15, to_timestamp('2005426', 'YYYYWWD');
SELECT '' AS to_timestamp_16, to_timestamp('2005300', 'YYYYDDD');
SELECT '' AS to_timestamp_17, to_timestamp('2005527', 'IYYYIWID');
SELECT '' AS to_timestamp_18, to_timestamp('005527', 'IYYIWID');
SELECT '' AS to_timestamp_19, to_timestamp('05527', 'IYIWID');
SELECT '' AS to_timestamp_20, to_timestamp('5527', 'IIWID');
SELECT '' AS to_timestamp_21, to_timestamp('2005364', 'IYYYIDDD');
SET DateStyle TO DEFAULT;
......@@ -241,50 +241,3 @@ SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID')
SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID')
FROM TIMESTAMPTZ_TBL;
-- TO_TIMESTAMP()
SELECT '' AS to_timestamp_1, to_timestamp('0097/Feb/16 --> 08:14:30', 'YYYY/Mon/DD --> HH:MI:SS');
SELECT '' AS to_timestamp_2, to_timestamp('97/2/16 8:14:30', 'FMYYYY/FMMM/FMDD FMHH:FMMI:FMSS');
SELECT '' AS to_timestamp_3, to_timestamp('1985 January 12', 'YYYY FMMonth DD');
SELECT '' AS to_timestamp_4, to_timestamp('My birthday-> Year: 1976, Month: May, Day: 16',
'"My birthday-> Year" YYYY, "Month:" FMMonth, "Day:" DD');
SELECT '' AS to_timestamp_5, to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD');
SELECT '' AS to_timestamp_6, to_timestamp('15 "text between quote marks" 98 54 45',
E'HH "\\text between quote marks\\"" YY MI SS');
SELECT '' AS to_timestamp_7, to_timestamp('05121445482000', 'MMDDHHMISSYYYY');
SELECT '' AS to_timestamp_8, to_timestamp('2000January09Sunday', 'YYYYFMMonthDDFMDay');
SELECT '' AS to_timestamp_9, to_timestamp('97/Feb/16', 'YYMonDD');
SELECT '' AS to_timestamp_10, to_timestamp('19971116', 'YYYYMMDD');
SELECT '' AS to_timestamp_11, to_timestamp('20000-1116', 'YYYY-MMDD');
SELECT '' AS to_timestamp_12, to_timestamp('9-1116', 'Y-MMDD');
SELECT '' AS to_timestamp_13, to_timestamp('95-1116', 'YY-MMDD');
SELECT '' AS to_timestamp_14, to_timestamp('995-1116', 'YYY-MMDD');
SELECT '' AS to_timestamp_15, to_timestamp('2005426', 'YYYYWWD');
SELECT '' AS to_timestamp_16, to_timestamp('2005300', 'YYYYDDD');
SELECT '' AS to_timestamp_17, to_timestamp('2005527', 'IYYYIWID');
SELECT '' AS to_timestamp_18, to_timestamp('005527', 'IYYIWID');
SELECT '' AS to_timestamp_19, to_timestamp('05527', 'IYIWID');
SELECT '' AS to_timestamp_20, to_timestamp('5527', 'IIWID');
SELECT '' AS to_timestamp_21, to_timestamp('2005364', 'IYYYIDDD');
SET DateStyle TO DEFAULT;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment