From 4ebb0cf9c30c1e477d5e2dfcc1f2c016c3f8bbcf Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Fri, 16 Feb 2007 03:39:46 +0000 Subject: [PATCH] Add two new format fields for use with to_char(), to_date() and to_timestamp(): - ID for day-of-week - IDDD for day-of-year This makes it possible to convert ISO week dates to and from text fully represented in either week ('IYYY-IW-ID') or day-of-year ('IYYY-IDDD') format. I have also added an 'isoyear' field for use with extract / date_part. Brendan Jurd --- doc/src/sgml/func.sgml | 58 +++- src/backend/utils/adt/date.c | 3 +- src/backend/utils/adt/datetime.c | 3 +- src/backend/utils/adt/formatting.c | 177 +++++++++---- src/backend/utils/adt/timestamp.c | 76 ++++-- src/include/utils/datetime.h | 3 +- src/include/utils/timestamp.h | 7 +- src/interfaces/ecpg/pgtypeslib/dt.h | 3 +- src/test/regress/expected/timestamp.out | 247 +++++++++++++++++ src/test/regress/expected/timestamptz.out | 309 +++++++++++++++++----- src/test/regress/sql/timestamp.sql | 25 ++ src/test/regress/sql/timestamptz.sql | 25 +- 12 files changed, 779 insertions(+), 157 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index ae9e9ec105..76b150a9d2 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,4 +1,4 @@ - + Functions and Operators @@ -4539,7 +4539,7 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); I - last digits of ISO year + last digit of ISO year BC or B.C. or @@ -4607,6 +4607,10 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); DDD day of year (001-366) + + IDDD + ISO day of year (001-371; day 1 of the year is Monday of the first ISO week.) + DD day of month (01-31) @@ -4615,6 +4619,10 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); D day of week (1-7; Sunday is 1) + + ID + ISO day of week (1-7; Monday is 1) + W week of month (1-5) (The first week starts on the first day of the month.) @@ -4625,7 +4633,7 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); IW - ISO week number of year (The first Thursday of the new year is in week 1.) + ISO week number of year (1 - 53; the first Thursday of the new year is in week 1.) CC @@ -4791,6 +4799,27 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); + + + An ISO week date (as distinct from a Gregorian date) can be specified to to_timestamp and to_date in one of two ways: + + + + Year, week and weekday, for example to_date('2006-42-4', 'IYYY-IW-ID') returns the date 2006-10-19. If you omit the weekday it is assumed to be 1 (Monday). + + + + + Year and day of year, for example to_date('2006-291', 'IYYY-IDDD') also returns 2006-10-19. + + + + + + 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. + + + Millisecond (MS) and microsecond (US) @@ -5776,6 +5805,29 @@ SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40'); + + isoyear + + + The ISO 8601 year that the date falls in (not applicable to intervals). + + + +SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-01'); +Result: 2005 +SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-02'); +Result: 2006 + + + + Each ISO year begins with the Monday of the week containing the 4th of January, so in early January or late December the ISO year may be different from the Gregorian year. See the week field for more information. + + + This field is not available in PostgreSQL releases prior to 8.3. + + + + microseconds diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 2360419bb7..c3a6415634 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.127 2007/01/05 22:19:40 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.128 2007/02/16 03:39:44 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1748,6 +1748,7 @@ time_part(PG_FUNCTION_ARGS) case DTK_DECADE: case DTK_CENTURY: case DTK_MILLENNIUM: + case DTK_ISOYEAR: default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 10fdf66ac8..18226b5508 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.175 2007/01/05 22:19:40 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.176 2007/02/16 03:39:45 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -125,6 +125,7 @@ static const datetkn datetktbl[] = { {"h", UNITS, DTK_HOUR}, /* "hour" */ {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */ {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for bad time */ + {"isoyear", UNITS, DTK_ISOYEAR}, /* year in terms of the ISO week date */ {"j", UNITS, DTK_JULIAN}, {"jan", MONTH, 1}, {"january", MONTH, 1}, diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 80de2f20e4..eff890c59b 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- * formatting.c * - * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.124 2007/02/14 05:10:55 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.125 2007/02/16 03:39:45 momjian Exp $ * * * Portions Copyright (c) 1999-2007, PostgreSQL Global Development Group @@ -379,6 +379,7 @@ typedef struct ddd, mm, ms, + iyear, year, bc, iw, @@ -528,7 +529,7 @@ static KeySuffix DCH_suff[] = { * position or -1 if char is not used in the KeyWord. Search example for * string "MM": * 1) see in index to index['M' - 32], - * 2) take keywords position (enum DCH_MM) from index + * 2) take keywords position (enum DCH_MI) from index * 3) run sequential search in keywords[] from this position * * ---------- @@ -554,6 +555,8 @@ typedef enum DCH_HH24, DCH_HH12, DCH_HH, + DCH_IDDD, + DCH_ID, DCH_IW, DCH_IYYY, DCH_IYY, @@ -598,6 +601,8 @@ typedef enum DCH_hh24, DCH_hh12, DCH_hh, + DCH_iddd, + DCH_id, DCH_iw, DCH_iyyy, DCH_iyy, @@ -696,13 +701,15 @@ static const KeyWord DCH_keywords[] = { {"HH24", 4, dch_time, DCH_HH24, TRUE}, /* H */ {"HH12", 4, dch_time, DCH_HH12, TRUE}, {"HH", 2, dch_time, DCH_HH, TRUE}, - {"IW", 2, dch_date, DCH_IW, TRUE}, /* I */ + {"IDDD", 4, dch_date, DCH_IDDD, TRUE}, /* I */ + {"ID", 2, dch_date, DCH_ID, TRUE}, + {"IW", 2, dch_date, DCH_IW, TRUE}, {"IYYY", 4, dch_date, DCH_IYYY, TRUE}, {"IYY", 3, dch_date, DCH_IYY, TRUE}, {"IY", 2, dch_date, DCH_IY, TRUE}, {"I", 1, dch_date, DCH_I, TRUE}, {"J", 1, dch_date, DCH_J, TRUE}, /* J */ - {"MI", 2, dch_time, DCH_MI, TRUE}, + {"MI", 2, dch_time, DCH_MI, TRUE}, /* M */ {"MM", 2, dch_date, DCH_MM, TRUE}, {"MONTH", 5, dch_date, DCH_MONTH, FALSE}, {"MON", 3, dch_date, DCH_MON, FALSE}, @@ -740,7 +747,9 @@ static const KeyWord DCH_keywords[] = { {"hh24", 4, dch_time, DCH_HH24, TRUE}, /* h */ {"hh12", 4, dch_time, DCH_HH12, TRUE}, {"hh", 2, dch_time, DCH_HH, TRUE}, - {"iw", 2, dch_date, DCH_IW, TRUE}, /* i */ + {"iddd", 4, dch_date, DCH_IDDD, TRUE}, /* i */ + {"id", 2, dch_date, DCH_ID, TRUE}, + {"iw", 2, dch_date, DCH_IW, TRUE}, {"iyyy", 4, dch_date, DCH_IYYY, TRUE}, {"iyy", 3, dch_date, DCH_IYY, TRUE}, {"iy", 2, dch_date, DCH_IY, TRUE}, @@ -830,10 +839,10 @@ static const int DCH_index[KeyWord_INDEX_SIZE] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1, - DCH_FX, -1, DCH_HH24, DCH_IW, DCH_J, -1, -1, DCH_MI, -1, -1, + DCH_FX, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, -1, DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY, -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc, - DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iw, DCH_j, -1, -1, DCH_mi, + DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi, -1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, DCH_us, -1, DCH_ww, -1, DCH_y_yyy, -1, -1, -1, -1 @@ -2429,9 +2438,13 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval, return strlen(p_inout); case DCH_DDD: + case DCH_IDDD: if (is_to_char) { - sprintf(inout, "%0*d", S_FM(suf) ? 0 : 3, tm->tm_yday); + sprintf(inout, "%0*d", S_FM(suf) ? 0 : 3, + (arg == DCH_DDD) ? + tm->tm_yday : + date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday)); if (S_THth(suf)) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout); @@ -2473,10 +2486,14 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval, } break; case DCH_D: + case DCH_ID: INVALID_FOR_INTERVAL; if (is_to_char) { - sprintf(inout, "%d", tm->tm_wday + 1); + if (arg == DCH_D) + sprintf(inout, "%d", tm->tm_wday + 1); + else + sprintf(inout, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); if (S_THth(suf)) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout); @@ -2484,7 +2501,8 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval, else { sscanf(inout, "%1d", &tmfc->d); - tmfc->d--; + if (arg == DCH_D) + tmfc->d--; return strspace_len(inout) + 1 + SKIP_THth(suf); } break; @@ -2625,15 +2643,18 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval, } else { + int *field; + field = (arg == DCH_YYYY) ? &tmfc->year : &tmfc->iyear; + if (S_FM(suf) || is_next_separator(node)) { - sscanf(inout, "%d", &tmfc->year); + sscanf(inout, "%d", field); tmfc->yysz = 4; return strdigits_len(inout) + SKIP_THth(suf); } else { - sscanf(inout, "%04d", &tmfc->year); + sscanf(inout, "%04d", field); tmfc->yysz = 4; return strspace_len(inout) + 4 + SKIP_THth(suf); } @@ -2657,16 +2678,19 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval, } else { - sscanf(inout, "%03d", &tmfc->year); + int *field; + field = (arg == DCH_YYY) ? &tmfc->year : &tmfc->iyear; + + sscanf(inout, "%03d", field); /* * 3-digit year: '100' ... '999' = 1100 ... 1999 '000' ... * '099' = 2000 ... 2099 */ - if (tmfc->year >= 100) - tmfc->year += 1000; + if (*field >= 100) + *field += 1000; else - tmfc->year += 2000; + *field += 2000; tmfc->yysz = 3; return strspace_len(inout) + 3 + SKIP_THth(suf); } @@ -2689,16 +2713,19 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval, } else { - sscanf(inout, "%02d", &tmfc->year); + int *field; + field = (arg == DCH_YY) ? &tmfc->year : &tmfc->iyear; + + sscanf(inout, "%02d", field); /* * 2-digit year: '00' ... '69' = 2000 ... 2069 '70' ... '99' * = 1970 ... 1999 */ - if (tmfc->year < 70) - tmfc->year += 2000; + if (*field < 70) + *field += 2000; else - tmfc->year += 1900; + *field += 1900; tmfc->yysz = 2; return strspace_len(inout) + 2 + SKIP_THth(suf); } @@ -2721,12 +2748,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval, } else { - sscanf(inout, "%1d", &tmfc->year); + int *field; + field = (arg == DCH_Y) ? &tmfc->year : &tmfc->iyear; + + sscanf(inout, "%1d", field); /* * 1-digit year: always +2000 */ - tmfc->year += 2000; + *field += 2000; tmfc->yysz = 1; return strspace_len(inout) + 1 + SKIP_THth(suf); } @@ -3297,7 +3327,8 @@ do_to_timestamp(text *date_txt, text *fmt, { FormatNode *format; TmFromChar tmfc; - int fmt_len; + int fmt_len, + year; ZERO_tm(tm); *fsec = 0; @@ -3447,7 +3478,13 @@ do_to_timestamp(text *date_txt, text *fmt, break; } - if (tmfc.year) + /* + * 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 CC and YY (or Y) are provided, use YY as 2 low-order digits @@ -3458,14 +3495,14 @@ do_to_timestamp(text *date_txt, text *fmt, */ if (tmfc.cc && tmfc.yysz <= 2) { - tm->tm_year = tmfc.year % 100; + tm->tm_year = year % 100; if (tm->tm_year) tm->tm_year += (tmfc.cc - 1) * 100; else tm->tm_year = tmfc.cc * 100; } else - tm->tm_year = tmfc.year; + tm->tm_year = year; } else if (tmfc.cc) /* use first year of century */ tm->tm_year = (tmfc.cc - 1) * 100 + 1; @@ -3485,48 +3522,78 @@ do_to_timestamp(text *date_txt, text *fmt, j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); if (tmfc.iw) - isoweek2date(tmfc.iw, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + { + /* + * 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) + { + isoweekdate2date(tmfc.iw, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + } + else + isoweek2date(tmfc.iw, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + } + if (tmfc.d) tm->tm_wday = tmfc.d; if (tmfc.dd) tm->tm_mday = tmfc.dd; - if (tmfc.ddd) + if (tmfc.ddd && !tmfc.iyear) tm->tm_yday = tmfc.ddd; if (tmfc.mm) tm->tm_mon = tmfc.mm; - /* - * we don't ignore DDD - */ if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1)) { - /* count mday and mon from yday */ - int *y, - i; - - int ysum[2][13] = { - {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0}, - {31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0}}; - - if (!tm->tm_year) - ereport(ERROR, - (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("cannot calculate day of year without year information"))); - - y = ysum[isleap(tm->tm_year)]; - - for (i = 0; i <= 11; i++) + /* + * 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. + */ + if (tmfc.iyear) { - if (tm->tm_yday < y[i]) - break; - } - if (tm->tm_mon <= 1) - tm->tm_mon = i + 1; + int j0; // zeroth day of the ISO year, in Julian + j0 = isoweek2j(tmfc.iyear, 1) - 1; - if (tm->tm_mday <= 1) - tm->tm_mday = i == 0 ? tm->tm_yday : - tm->tm_yday - y[i - 1]; + j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + } + else + { + int *y, + i; + + int ysum[2][13] = { + {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0}, + {31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0}}; + + if (!tm->tm_year) + ereport(ERROR, + (errcode(ERRCODE_INVALID_DATETIME_FORMAT), + errmsg("cannot calculate day of year without year information"))); + + y = ysum[isleap(tm->tm_year)]; + + for (i = 0; i <= 11; i++) + { + if (tm->tm_yday < y[i]) + break; + } + if (tm->tm_mon <= 1) + tm->tm_mon = i + 1; + + if (tm->tm_mday <= 1) + tm->tm_mday = i == 0 ? tm->tm_yday : + tm->tm_yday - y[i - 1]; + } } #ifdef HAVE_INT64_TIMESTAMP diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 13dba7cb5c..7632e1b896 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.171 2007/01/05 22:19:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.172 2007/02/16 03:39:45 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -3749,6 +3749,31 @@ interval_trunc(PG_FUNCTION_ARGS) PG_RETURN_INTERVAL_P(result); } +/* isoweek2j() + * + * Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week. + * Julian days are used to convert between ISO week dates and Gregorian dates. + */ +int +isoweek2j(int year, int week) +{ + int day0, + day4; + + if (!year) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot calculate week number without year information"))); + + /* fourth day of current year */ + day4 = date2j(year, 1, 4); + + /* day0 == offset to first day of week (Monday) */ + day0 = j2day(day4 - 1); + + return ((week - 1) * 7) + (day4 - day0); +} + /* isoweek2date() * Convert ISO week of year number to date. * The year field must be specified with the ISO year! @@ -3757,24 +3782,24 @@ interval_trunc(PG_FUNCTION_ARGS) void isoweek2date(int woy, int *year, int *mon, int *mday) { - int day0, - day4, - dayn; + j2date(isoweek2j(*year, woy), year, mon, mday); +} - if (!*year) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot calculate week number without year information"))); +/* isoweekdate2date() + * + * Convert an ISO 8601 week date (ISO year, ISO week and day of week) into a Gregorian date. + * Populates year, mon, and mday with the correct Gregorian values. + * year must be passed in as the ISO year. + */ +void +isoweekdate2date(int isoweek, int isowday, int *year, int *mon, int *mday) +{ + int jday; - /* fourth day of current year */ - day4 = date2j(*year, 1, 4); + jday = isoweek2j(*year, isoweek); + jday += isowday - 1; - /* day0 == offset to first day of week (Monday) */ - day0 = j2day(day4 - 1); - - dayn = ((woy - 1) * 7) + (day4 - day0); - - j2date(dayn, year, mon, mday); + j2date(jday, year, mon, mday); } /* date2isoweek() @@ -3887,6 +3912,17 @@ date2isoyear(int year, int mon, int mday) } +/* date2isoyearday() + * + * Returns the ISO 8601 day-of-year, given a Gregorian year, month and day. + * Possible return values are 1 through 371 (364 in non-leap years). + */ +int +date2isoyearday(int year, int mon, int mday) +{ + return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1; +} + /* timestamp_part() * Extract specified field from timestamp. */ @@ -4029,6 +4065,10 @@ timestamp_part(PG_FUNCTION_ARGS) #endif break; + case DTK_ISOYEAR: + result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday); + break; + case DTK_TZ: case DTK_TZ_MINUTE: case DTK_TZ_HOUR: @@ -4256,6 +4296,10 @@ timestamptz_part(PG_FUNCTION_ARGS) #endif break; + case DTK_ISOYEAR: + result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday); + break; + default: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index 0b19143c28..fc7b16fdb4 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.63 2007/01/05 22:19:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.64 2007/02/16 03:39:45 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -165,6 +165,7 @@ #define DTK_DOY 33 #define DTK_TZ_HOUR 34 #define DTK_TZ_MINUTE 35 +#define DTK_ISOYEAR 36 /* diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 4ff1ffe869..0d31cc0294 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.66 2007/01/05 22:19:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.67 2007/02/16 03:39:45 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -331,8 +331,11 @@ extern int timestamp_cmp_internal(Timestamp dt1, Timestamp dt2); /* timestamp comparison works for timestamptz also */ #define timestamptz_cmp_internal(dt1,dt2) timestamp_cmp_internal(dt1, dt2) -extern void isoweek2date(int woy, int *year, int *mon, int *mday); +extern int isoweek2j(int year, int week); +extern void isoweek2date(int woy, int *year, int *mon, int *mday); +extern void isoweekdate2date(int isoweek, int isowday, int *year, int *mon, int *mday); extern int date2isoweek(int year, int mon, int mday); extern int date2isoyear(int year, int mon, int mday); +extern int date2isoyearday(int year, int mon, int mday); #endif /* TIMESTAMP_H */ diff --git a/src/interfaces/ecpg/pgtypeslib/dt.h b/src/interfaces/ecpg/pgtypeslib/dt.h index 95793aabc3..d0bfc00bbd 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt.h +++ b/src/interfaces/ecpg/pgtypeslib/dt.h @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/dt.h,v 1.34 2006/03/11 04:38:39 momjian Exp $ */ +/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/dt.h,v 1.35 2007/02/16 03:39:45 momjian Exp $ */ #ifndef DT_H #define DT_H @@ -157,6 +157,7 @@ typedef double fsec_t; #define DTK_DOY 33 #define DTK_TZ_HOUR 34 #define DTK_TZ_MINUTE 35 +#define DTK_ISOYEAR 36 /* diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out index c26cb9ec99..9f585b68f6 100644 --- a/src/test/regress/expected/timestamp.out +++ b/src/test/regress/expected/timestamp.out @@ -703,6 +703,69 @@ SELECT '' AS "54", d1 as "timestamp", | Mon Jan 01 17:32:01 2001 | 1 | 1000 | 1000000 (55 rows) +SELECT '' AS "54", d1 as "timestamp", + date_part( 'isoyear', d1) AS isoyear, date_part( 'week', d1) AS week, + date_part( 'dow', d1) AS dow + FROM TIMESTAMP_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01'; + 54 | timestamp | isoyear | week | dow +----+-----------------------------+---------+------+----- + | Thu Jan 01 00:00:00 1970 | 1970 | 1 | 4 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:02 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01.40 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01.50 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01.60 1997 | 1997 | 7 | 1 + | Thu Jan 02 00:00:00 1997 | 1997 | 1 | 4 + | Thu Jan 02 03:04:05 1997 | 1997 | 1 | 4 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Tue Jun 10 17:32:01 1997 | 1997 | 24 | 2 + | Sat Sep 22 18:19:20 2001 | 2001 | 38 | 6 + | Wed Mar 15 08:14:01 2000 | 2000 | 11 | 3 + | Wed Mar 15 13:14:02 2000 | 2000 | 11 | 3 + | Wed Mar 15 12:14:03 2000 | 2000 | 11 | 3 + | Wed Mar 15 03:14:04 2000 | 2000 | 11 | 3 + | Wed Mar 15 02:14:05 2000 | 2000 | 11 | 3 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:00 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Tue Jun 10 18:32:01 1997 | 1997 | 24 | 2 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Tue Feb 11 17:32:01 1997 | 1997 | 7 | 2 + | Wed Feb 12 17:32:01 1997 | 1997 | 7 | 3 + | Thu Feb 13 17:32:01 1997 | 1997 | 7 | 4 + | Fri Feb 14 17:32:01 1997 | 1997 | 7 | 5 + | Sat Feb 15 17:32:01 1997 | 1997 | 7 | 6 + | Sun Feb 16 17:32:01 1997 | 1997 | 7 | 0 + | Sun Feb 16 17:32:01 1997 | 1997 | 7 | 0 + | Wed Feb 28 17:32:01 1996 | 1996 | 9 | 3 + | Thu Feb 29 17:32:01 1996 | 1996 | 9 | 4 + | Fri Mar 01 17:32:01 1996 | 1996 | 9 | 5 + | Mon Dec 30 17:32:01 1996 | 1997 | 1 | 1 + | Tue Dec 31 17:32:01 1996 | 1997 | 1 | 2 + | Wed Jan 01 17:32:01 1997 | 1997 | 1 | 3 + | Fri Feb 28 17:32:01 1997 | 1997 | 9 | 5 + | Sat Mar 01 17:32:01 1997 | 1997 | 9 | 6 + | Tue Dec 30 17:32:01 1997 | 1998 | 1 | 2 + | Wed Dec 31 17:32:01 1997 | 1998 | 1 | 3 + | Fri Dec 31 17:32:01 1999 | 1999 | 52 | 5 + | Sat Jan 01 17:32:01 2000 | 1999 | 52 | 6 + | Sun Dec 31 17:32:01 2000 | 2000 | 52 | 0 + | Mon Jan 01 17:32:01 2001 | 2001 | 1 | 1 +(55 rows) + -- TO_CHAR() SELECT '' AS to_char_1, to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon') FROM TIMESTAMP_TBL; @@ -1344,6 +1407,148 @@ SELECT '' AS to_char_9, to_char(d1, 'YYYY A.D. YYYY a.d. YYYY bc HH:MI:SS P.M. H | 2001 A.D. 2001 a.d. 2001 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm (65 rows) +SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID') + FROM TIMESTAMP_TBL; + to_char_10 | to_char +------------+------------------------ + | + | + | 1970 970 70 0 01 004 4 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 01 004 4 + | 1997 997 97 7 01 004 4 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 24 163 2 + | 2001 001 01 1 38 265 6 + | 2000 000 00 0 11 073 3 + | 2000 000 00 0 11 073 3 + | 2000 000 00 0 11 073 3 + | 2000 000 00 0 11 073 3 + | 2000 000 00 0 11 073 3 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 24 163 2 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 044 2 + | 1997 997 97 7 07 045 3 + | 1997 997 97 7 07 046 4 + | 1997 997 97 7 07 047 5 + | 1997 997 97 7 07 048 6 + | 1997 997 97 7 07 049 7 + | 0097 097 97 7 07 044 2 + | 0097 097 97 7 07 048 6 + | 0597 597 97 7 07 046 4 + | 1097 097 97 7 07 044 2 + | 1697 697 97 7 07 048 6 + | 1797 797 97 7 07 046 4 + | 1897 897 97 7 07 044 2 + | 1997 997 97 7 07 049 7 + | 2097 097 97 7 07 048 6 + | 1996 996 96 6 09 059 3 + | 1996 996 96 6 09 060 4 + | 1996 996 96 6 09 061 5 + | 1997 997 97 7 01 001 1 + | 1997 997 97 7 01 002 2 + | 1997 997 97 7 01 003 3 + | 1997 997 97 7 09 061 5 + | 1997 997 97 7 09 062 6 + | 1998 998 98 8 01 002 2 + | 1998 998 98 8 01 003 3 + | 1999 999 99 9 52 362 5 + | 1999 999 99 9 52 363 6 + | 2000 000 00 0 52 364 7 + | 2001 001 01 1 01 001 1 +(65 rows) + +SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID') + FROM TIMESTAMP_TBL; + to_char_11 | to_char +------------+------------------------ + | + | + | 1970 970 70 0 1 4 4 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 1 4 4 + | 1997 997 97 7 1 4 4 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 24 163 2 + | 2001 001 01 1 38 265 6 + | 2000 000 00 0 11 73 3 + | 2000 000 00 0 11 73 3 + | 2000 000 00 0 11 73 3 + | 2000 000 00 0 11 73 3 + | 2000 000 00 0 11 73 3 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 24 163 2 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 44 2 + | 1997 997 97 7 7 45 3 + | 1997 997 97 7 7 46 4 + | 1997 997 97 7 7 47 5 + | 1997 997 97 7 7 48 6 + | 1997 997 97 7 7 49 7 + | 97 097 97 7 7 44 2 + | 97 097 97 7 7 48 6 + | 597 597 97 7 7 46 4 + | 1097 097 97 7 7 44 2 + | 1697 697 97 7 7 48 6 + | 1797 797 97 7 7 46 4 + | 1897 897 97 7 7 44 2 + | 1997 997 97 7 7 49 7 + | 2097 097 97 7 7 48 6 + | 1996 996 96 6 9 59 3 + | 1996 996 96 6 9 60 4 + | 1996 996 96 6 9 61 5 + | 1997 997 97 7 1 1 1 + | 1997 997 97 7 1 2 2 + | 1997 997 97 7 1 3 3 + | 1997 997 97 7 9 61 5 + | 1997 997 97 7 9 62 6 + | 1998 998 98 8 1 2 2 + | 1998 998 98 8 1 3 3 + | 1999 999 99 9 52 362 5 + | 1999 999 99 9 52 363 6 + | 2000 000 00 0 52 364 7 + | 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 @@ -1428,4 +1633,46 @@ SELECT '' AS to_timestamp_14, to_timestamp('995-1116', 'YYY-MMDD'); | 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; diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out index be3d7bed5d..e875c90d5d 100644 --- a/src/test/regress/expected/timestamptz.out +++ b/src/test/regress/expected/timestamptz.out @@ -720,6 +720,69 @@ SELECT '' AS "54", d1 as timestamptz, | Mon Jan 01 17:32:01 2001 PST | 1 | 1000 | 1000000 (56 rows) +SELECT '' AS "54", d1 as "timestamp", + date_part( 'isoyear', d1) AS isoyear, date_part( 'week', d1) AS week, + date_part( 'dow', d1) AS dow + FROM TIMESTAMP_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01'; + 54 | timestamp | isoyear | week | dow +----+-----------------------------+---------+------+----- + | Thu Jan 01 00:00:00 1970 | 1970 | 1 | 4 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:02 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01.40 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01.50 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01.60 1997 | 1997 | 7 | 1 + | Thu Jan 02 00:00:00 1997 | 1997 | 1 | 4 + | Thu Jan 02 03:04:05 1997 | 1997 | 1 | 4 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Tue Jun 10 17:32:01 1997 | 1997 | 24 | 2 + | Sat Sep 22 18:19:20 2001 | 2001 | 38 | 6 + | Wed Mar 15 08:14:01 2000 | 2000 | 11 | 3 + | Wed Mar 15 13:14:02 2000 | 2000 | 11 | 3 + | Wed Mar 15 12:14:03 2000 | 2000 | 11 | 3 + | Wed Mar 15 03:14:04 2000 | 2000 | 11 | 3 + | Wed Mar 15 02:14:05 2000 | 2000 | 11 | 3 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:00 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Tue Jun 10 18:32:01 1997 | 1997 | 24 | 2 + | Mon Feb 10 17:32:01 1997 | 1997 | 7 | 1 + | Tue Feb 11 17:32:01 1997 | 1997 | 7 | 2 + | Wed Feb 12 17:32:01 1997 | 1997 | 7 | 3 + | Thu Feb 13 17:32:01 1997 | 1997 | 7 | 4 + | Fri Feb 14 17:32:01 1997 | 1997 | 7 | 5 + | Sat Feb 15 17:32:01 1997 | 1997 | 7 | 6 + | Sun Feb 16 17:32:01 1997 | 1997 | 7 | 0 + | Sun Feb 16 17:32:01 1997 | 1997 | 7 | 0 + | Wed Feb 28 17:32:01 1996 | 1996 | 9 | 3 + | Thu Feb 29 17:32:01 1996 | 1996 | 9 | 4 + | Fri Mar 01 17:32:01 1996 | 1996 | 9 | 5 + | Mon Dec 30 17:32:01 1996 | 1997 | 1 | 1 + | Tue Dec 31 17:32:01 1996 | 1997 | 1 | 2 + | Wed Jan 01 17:32:01 1997 | 1997 | 1 | 3 + | Fri Feb 28 17:32:01 1997 | 1997 | 9 | 5 + | Sat Mar 01 17:32:01 1997 | 1997 | 9 | 6 + | Tue Dec 30 17:32:01 1997 | 1998 | 1 | 2 + | Wed Dec 31 17:32:01 1997 | 1998 | 1 | 3 + | Fri Dec 31 17:32:01 1999 | 1999 | 52 | 5 + | Sat Jan 01 17:32:01 2000 | 1999 | 52 | 6 + | Sun Dec 31 17:32:01 2000 | 2000 | 52 | 0 + | Mon Jan 01 17:32:01 2001 | 2001 | 1 | 1 +(55 rows) + -- TO_CHAR() SELECT '' AS to_char_1, to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon') FROM TIMESTAMPTZ_TBL; @@ -1374,77 +1437,147 @@ SELECT '' AS to_char_9, to_char(d1, 'YYYY A.D. YYYY a.d. YYYY bc HH:MI:SS P.M. H | 2001 A.D. 2001 a.d. 2001 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm (66 rows) -SELECT '' AS to_char_10, to_char(d1, 'YYYY WW IYYY IYY IY I IW') - FROM TIMESTAMPTZ_TBL; - to_char_10 | to_char -------------+-------------------------- +SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID') + FROM TIMESTAMP_TBL; + to_char_10 | to_char +------------+------------------------ | | - | 1969 53 1970 970 70 0 01 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 01 1997 997 97 7 01 - | 1997 01 1997 997 97 7 01 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 23 1997 997 97 7 24 - | 2001 38 2001 001 01 1 38 - | 2000 11 2000 000 00 0 11 - | 2000 11 2000 000 00 0 11 - | 2000 11 2000 000 00 0 11 - | 2000 11 2000 000 00 0 11 - | 2000 11 2000 000 00 0 11 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 28 1997 997 97 7 28 - | 1997 23 1997 997 97 7 24 - | 1997 06 1997 997 97 7 07 - | 1997 06 1997 997 97 7 07 - | 1997 07 1997 997 97 7 07 - | 1997 07 1997 997 97 7 07 - | 1997 07 1997 997 97 7 07 - | 1997 07 1997 997 97 7 07 - | 1997 07 1997 997 97 7 07 - | 0097 07 0097 097 97 7 07 - | 0097 07 0097 097 97 7 07 - | 0597 07 0597 597 97 7 07 - | 1097 07 1097 097 97 7 07 - | 1697 07 1697 697 97 7 07 - | 1797 07 1797 797 97 7 07 - | 1897 07 1897 897 97 7 07 - | 1997 07 1997 997 97 7 07 - | 2097 07 2097 097 97 7 07 - | 1996 09 1996 996 96 6 09 - | 1996 09 1996 996 96 6 09 - | 1996 09 1996 996 96 6 09 - | 1996 53 1997 997 97 7 01 - | 1996 53 1997 997 97 7 01 - | 1997 01 1997 997 97 7 01 - | 1997 09 1997 997 97 7 09 - | 1997 09 1997 997 97 7 09 - | 1997 52 1998 998 98 8 01 - | 1997 53 1998 998 98 8 01 - | 1999 53 1999 999 99 9 52 - | 2000 01 1999 999 99 9 52 - | 2000 53 2000 000 00 0 52 - | 2001 01 2001 001 01 1 01 -(66 rows) + | 1970 970 70 0 01 004 4 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 01 004 4 + | 1997 997 97 7 01 004 4 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 24 163 2 + | 2001 001 01 1 38 265 6 + | 2000 000 00 0 11 073 3 + | 2000 000 00 0 11 073 3 + | 2000 000 00 0 11 073 3 + | 2000 000 00 0 11 073 3 + | 2000 000 00 0 11 073 3 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 24 163 2 + | 1997 997 97 7 07 043 1 + | 1997 997 97 7 07 044 2 + | 1997 997 97 7 07 045 3 + | 1997 997 97 7 07 046 4 + | 1997 997 97 7 07 047 5 + | 1997 997 97 7 07 048 6 + | 1997 997 97 7 07 049 7 + | 0097 097 97 7 07 044 2 + | 0097 097 97 7 07 048 6 + | 0597 597 97 7 07 046 4 + | 1097 097 97 7 07 044 2 + | 1697 697 97 7 07 048 6 + | 1797 797 97 7 07 046 4 + | 1897 897 97 7 07 044 2 + | 1997 997 97 7 07 049 7 + | 2097 097 97 7 07 048 6 + | 1996 996 96 6 09 059 3 + | 1996 996 96 6 09 060 4 + | 1996 996 96 6 09 061 5 + | 1997 997 97 7 01 001 1 + | 1997 997 97 7 01 002 2 + | 1997 997 97 7 01 003 3 + | 1997 997 97 7 09 061 5 + | 1997 997 97 7 09 062 6 + | 1998 998 98 8 01 002 2 + | 1998 998 98 8 01 003 3 + | 1999 999 99 9 52 362 5 + | 1999 999 99 9 52 363 6 + | 2000 000 00 0 52 364 7 + | 2001 001 01 1 01 001 1 +(65 rows) + +SELECT '' AS to_char_11, to_char(d1, 'FMIYYY FMIYY FMIY FMI FMIW FMIDDD FMID') + FROM TIMESTAMP_TBL; + to_char_11 | to_char +------------+------------------------ + | + | + | 1970 970 70 0 1 4 4 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 1 4 4 + | 1997 997 97 7 1 4 4 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 24 163 2 + | 2001 001 01 1 38 265 6 + | 2000 000 00 0 11 73 3 + | 2000 000 00 0 11 73 3 + | 2000 000 00 0 11 73 3 + | 2000 000 00 0 11 73 3 + | 2000 000 00 0 11 73 3 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 24 163 2 + | 1997 997 97 7 7 43 1 + | 1997 997 97 7 7 44 2 + | 1997 997 97 7 7 45 3 + | 1997 997 97 7 7 46 4 + | 1997 997 97 7 7 47 5 + | 1997 997 97 7 7 48 6 + | 1997 997 97 7 7 49 7 + | 97 097 97 7 7 44 2 + | 97 097 97 7 7 48 6 + | 597 597 97 7 7 46 4 + | 1097 097 97 7 7 44 2 + | 1697 697 97 7 7 48 6 + | 1797 797 97 7 7 46 4 + | 1897 897 97 7 7 44 2 + | 1997 997 97 7 7 49 7 + | 2097 097 97 7 7 48 6 + | 1996 996 96 6 9 59 3 + | 1996 996 96 6 9 60 4 + | 1996 996 96 6 9 61 5 + | 1997 997 97 7 1 1 1 + | 1997 997 97 7 1 2 2 + | 1997 997 97 7 1 3 3 + | 1997 997 97 7 9 61 5 + | 1997 997 97 7 9 62 6 + | 1998 998 98 8 1 2 2 + | 1998 998 98 8 1 3 3 + | 1999 999 99 9 52 362 5 + | 1999 999 99 9 52 363 6 + | 2000 000 00 0 52 364 7 + | 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'); @@ -1531,16 +1664,46 @@ SELECT '' AS to_timestamp_14, to_timestamp('995-1116', 'YYY-MMDD'); | Thu Nov 16 00:00:00 1995 PST (1 row) -SELECT '' AS to_timestamp_15, to_timestamp('200401', 'IYYYIW'); +SELECT '' AS to_timestamp_15, to_timestamp('2005426', 'YYYYWWD'); to_timestamp_15 | to_timestamp -----------------+------------------------------ - | Mon Dec 29 00:00:00 2003 PST + | Sat Oct 15 00:00:00 2005 PDT (1 row) -SELECT '' AS to_timestamp_16, to_timestamp('200401', 'YYYYWW'); +SELECT '' AS to_timestamp_16, to_timestamp('2005300', 'YYYYDDD'); to_timestamp_16 | to_timestamp -----------------+------------------------------ - | Thu Jan 01 00:00:00 2004 PST + | 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; diff --git a/src/test/regress/sql/timestamp.sql b/src/test/regress/sql/timestamp.sql index 34689564da..81be5b8f33 100644 --- a/src/test/regress/sql/timestamp.sql +++ b/src/test/regress/sql/timestamp.sql @@ -171,6 +171,11 @@ SELECT '' AS "54", d1 as "timestamp", date_part( 'usec', d1) AS usec FROM TIMESTAMP_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01'; +SELECT '' AS "54", d1 as "timestamp", + date_part( 'isoyear', d1) AS isoyear, date_part( 'week', d1) AS week, + date_part( 'dow', d1) AS dow + FROM TIMESTAMP_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01'; + -- TO_CHAR() SELECT '' AS to_char_1, to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon') FROM TIMESTAMP_TBL; @@ -199,6 +204,12 @@ SELECT '' AS to_char_8, to_char(d1, 'YYYYTH YYYYth Jth') SELECT '' AS to_char_9, to_char(d1, 'YYYY A.D. YYYY a.d. YYYY bc HH:MI:SS P.M. HH:MI:SS p.m. HH:MI:SS pm') FROM TIMESTAMP_TBL; +SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID') + FROM TIMESTAMP_TBL; + +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'); @@ -230,4 +241,18 @@ 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; diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql index fc597a6b2c..6ef216a53a 100644 --- a/src/test/regress/sql/timestamptz.sql +++ b/src/test/regress/sql/timestamptz.sql @@ -169,6 +169,11 @@ SELECT '' AS "54", d1 as timestamptz, date_part( 'usec', d1) AS usec FROM TIMESTAMPTZ_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01'; +SELECT '' AS "54", d1 as "timestamp", + date_part( 'isoyear', d1) AS isoyear, date_part( 'week', d1) AS week, + date_part( 'dow', d1) AS dow + FROM TIMESTAMP_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01'; + -- TO_CHAR() SELECT '' AS to_char_1, to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon') FROM TIMESTAMPTZ_TBL; @@ -197,8 +202,11 @@ SELECT '' AS to_char_8, to_char(d1, 'YYYYTH YYYYth Jth') SELECT '' AS to_char_9, to_char(d1, 'YYYY A.D. YYYY a.d. YYYY bc HH:MI:SS P.M. HH:MI:SS p.m. HH:MI:SS pm') FROM TIMESTAMPTZ_TBL; -SELECT '' AS to_char_10, to_char(d1, 'YYYY WW IYYY IYY IY I IW') - FROM TIMESTAMPTZ_TBL; +SELECT '' AS to_char_10, to_char(d1, 'IYYY IYY IY I IW IDDD ID') + FROM TIMESTAMP_TBL; + +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'); @@ -231,9 +239,18 @@ 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('200401', 'IYYYIW'); +SELECT '' AS to_timestamp_15, to_timestamp('2005426', 'YYYYWWD'); -SELECT '' AS to_timestamp_16, to_timestamp('200401', 'YYYYWW'); +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;