From dffd8cac3dd8fb99ed4299bf2ef7eddba6eeaba2 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Tue, 29 Aug 2000 04:41:48 +0000 Subject: [PATCH] * to_char: - full support for IW (ISO week) and vice versa conversion for IW too (the to_char 'week' support is now complete and I hope correct). Thomas, I use for IW code from timestamp.c, for this I create separate function date2isoweek() from original 'case DTK_WEEK:' code in the timestamp_part(). I mean will better use one code for same feature in date_part() and in to_char(). The isoweek2date() is added to timestamp.c too. Right? IMHO in 7.1 will all to_char's features complete. It is cca 41 templates for date/time and cca 21 for numbers. * to_ascii: - gcc, is it correct now? :-) In the patch is documentation for to_char's IW and for to_ascii(). Karel --- doc/src/sgml/func.sgml | 13 ++++ src/backend/utils/adt/formatting.c | 92 ++++++++++++++++++------- src/backend/utils/adt/pg_locale.c | 12 ++-- src/backend/utils/adt/timestamp.c | 106 +++++++++++++++++++++-------- src/include/utils/timestamp.h | 5 +- 5 files changed, 168 insertions(+), 60 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index aa7e2b0989..9f8fdd8932 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -355,6 +355,12 @@ + + to_ascii(text [,name|int]) + text + convert text from multibyte encoding to ASCII + to_ascii('Karel') + char(text) char @@ -447,6 +453,9 @@ Most functions explicitly defined for text will work for char() and varchar() arguments. + + The to_ascii() support conversion from LATIN1, LATIN2, WIN1250 (CP1250) only. + @@ -803,6 +812,10 @@ WW week number of year (1-53) where first week start on the first day of the year + + IW + ISO week number of year + CC century (2 digits) diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 864c3867ba..8dcce7f1d9 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- * formatting.c * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.20 2000/07/29 03:26:41 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.21 2000/08/29 04:41:47 momjian Exp $ * * * Portions Copyright (c) 1999-2000, PostgreSQL, Inc @@ -344,24 +344,24 @@ static int NUMCounter = 0; * ---------- */ typedef struct { - int hh, am, pm, mi, ss, ssss, d, dd, ddd, mm, yyyy, bc, ww, w, cc, q, j; + int hh, am, pm, mi, ss, ssss, d, dd, ddd, mm, yyyy, bc, iw, ww, w, cc, q, j; } TmFromChar; #define ZERO_tmfc( _X ) \ do { \ (_X)->hh= (_X)->am= (_X)->pm= (_X)->mi= (_X)->ss= (_X)->ssss= \ (_X)->d= (_X)->dd= (_X)->ddd= (_X)->mm= (_X)->yyyy= (_X)->bc= \ - (_X)->ww= (_X)->w= (_X)->cc= (_X)->q= (_X)->j= 0; \ + (_X)->iw= (_X)->ww= (_X)->w= (_X)->cc= (_X)->q= (_X)->j= 0; \ } while(0) #ifdef DEBUG_TO_FROM_CHAR #define NOTICE_TMFC \ - 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\nyyyy %d\nbc %d\nww %d\nw %d\ncc %d\nq %d\nj %d", \ + 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\nyyyy %d\nbc %d\niw %d\nww %d\nw %d\ncc %d\nq %d\nj %d", \ tmfc->hh, tmfc->am, tmfc->pm, tmfc->mi, tmfc->ss, \ tmfc->ssss, tmfc->d, tmfc->dd, tmfc->ddd, tmfc->mm, \ - tmfc->yyyy, tmfc->bc, tmfc->ww, tmfc->w, tmfc->cc, \ - tmfc->q, tmfc->j); + tmfc->yyyy, tmfc->bc, tmfc->iw, tmfc->ww, tmfc->w, \ + tmfc->cc, tmfc->q, tmfc->j); #define NOTICE_TM \ elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\ @@ -487,6 +487,7 @@ typedef enum DCH_HH24, DCH_HH12, DCH_HH, + DCH_IW, DCH_J, DCH_MI, DCH_MM, @@ -524,6 +525,7 @@ typedef enum DCH_hh24, DCH_hh12, DCH_hh, + DCH_iw, DCH_j, DCH_mi, DCH_mm, @@ -596,14 +598,14 @@ typedef enum * ---------- */ static KeyWord DCH_keywords[] = { -/* keyword, len, func. type is in Index */ +/* keyword,len,func.type is in Index */ {"A.D.", 4, dch_date, DCH_A_D}, /* A */ {"A.M.", 4, dch_time, DCH_A_M}, {"AD", 2, dch_date, DCH_AD}, {"AM", 2, dch_time, DCH_AM}, {"B.C.", 4, dch_date, DCH_B_C}, /* B */ {"BC", 2, dch_date, DCH_BC}, - {"CC", 2, dch_date, DCH_CC},/* C */ + {"CC", 2, dch_date, DCH_CC}, /* C */ {"DAY", 3, dch_date, DCH_DAY}, /* D */ {"DDD", 3, dch_date, DCH_DDD}, {"DD", 2, dch_date, DCH_DD}, @@ -615,7 +617,8 @@ static KeyWord DCH_keywords[] = { {"HH24", 4, dch_time, DCH_HH24}, /* H */ {"HH12", 4, dch_time, DCH_HH12}, {"HH", 2, dch_time, DCH_HH}, - {"J", 1, dch_date, DCH_J}, /* J */ + {"IW", 2, dch_date, DCH_IW}, /* I */ + {"J", 1, dch_date, DCH_J}, /* J */ {"MI", 2, dch_time, DCH_MI}, {"MM", 2, dch_date, DCH_MM}, {"MONTH", 5, dch_date, DCH_MONTH}, @@ -624,12 +627,12 @@ static KeyWord DCH_keywords[] = { {"Mon", 3, dch_date, DCH_Mon}, {"P.M.", 4, dch_time, DCH_P_M}, /* P */ {"PM", 2, dch_time, DCH_PM}, - {"Q", 1, dch_date, DCH_Q}, /* Q */ - {"RM", 2, dch_date, DCH_RM},/* R */ + {"Q", 1, dch_date, DCH_Q}, /* Q */ + {"RM", 2, dch_date, DCH_RM}, /* R */ {"SSSS", 4, dch_time, DCH_SSSS}, /* S */ {"SS", 2, dch_time, DCH_SS}, {"TZ", 2, dch_time, DCH_TZ}, /* T */ - {"WW", 2, dch_date, DCH_WW},/* W */ + {"WW", 2, dch_date, DCH_WW}, /* W */ {"W", 1, dch_date, DCH_W}, {"Y,YYY", 5, dch_date, DCH_Y_YYY}, /* Y */ {"YYYY", 4, dch_date, DCH_YYYY}, @@ -642,7 +645,7 @@ static KeyWord DCH_keywords[] = { {"am", 2, dch_time, DCH_am}, {"b.c.", 4, dch_date, DCH_b_c}, /* b */ {"bc", 2, dch_date, DCH_bc}, - {"cc", 2, dch_date, DCH_CC},/* c */ + {"cc", 2, dch_date, DCH_CC}, /* c */ {"day", 3, dch_date, DCH_day}, /* d */ {"ddd", 3, dch_date, DCH_DDD}, {"dd", 2, dch_date, DCH_DD}, @@ -652,19 +655,20 @@ static KeyWord DCH_keywords[] = { {"hh24", 4, dch_time, DCH_HH24}, /* h */ {"hh12", 4, dch_time, DCH_HH12}, {"hh", 2, dch_time, DCH_HH}, - {"j", 1, dch_time, DCH_J}, /* j */ - {"mi", 2, dch_time, DCH_MI},/* m */ + {"iw", 2, dch_date, DCH_IW}, /* i */ + {"j", 1, dch_time, DCH_J}, /* j */ + {"mi", 2, dch_time, DCH_MI}, /* m */ {"mm", 2, dch_date, DCH_MM}, {"month", 5, dch_date, DCH_month}, {"mon", 3, dch_date, DCH_mon}, {"p.m.", 4, dch_time, DCH_p_m}, /* p */ {"pm", 2, dch_time, DCH_pm}, - {"q", 1, dch_date, DCH_Q}, /* q */ - {"rm", 2, dch_date, DCH_rm},/* r */ + {"q", 1, dch_date, DCH_Q}, /* q */ + {"rm", 2, dch_date, DCH_rm}, /* r */ {"ssss", 4, dch_time, DCH_SSSS}, /* s */ {"ss", 2, dch_time, DCH_SS}, {"tz", 2, dch_time, DCH_tz}, /* t */ - {"ww", 2, dch_date, DCH_WW},/* w */ + {"ww", 2, dch_date, DCH_WW}, /* w */ {"w", 1, dch_date, DCH_W}, {"y,yyy", 5, dch_date, DCH_Y_YYY}, /* y */ {"yyyy", 4, dch_date, DCH_YYYY}, @@ -735,10 +739,10 @@ static 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, -1, DCH_J, -1, -1, DCH_MI, -1, -1, + DCH_FX, -1, DCH_HH24, DCH_IW, DCH_J, -1, -1, DCH_MI, -1, -1, DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, -1, -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, -1, DCH_j, -1, -1, DCH_mi, + DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iw, DCH_j, -1, -1, DCH_mi, -1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, -1, -1, DCH_ww, -1, DCH_y_yyy, -1, -1, -1, -1 @@ -1526,8 +1530,8 @@ dch_global(int arg, char *inout, int suf, int flag, FormatNode *node) /* ---------- * Master function of TIME for: - * TO_CHAR - write (inout) formated string - * FROM_CHAR - scan (inout) string by course of FormatNode + * TO_CHAR - write (inout) formated string + * FROM_CHAR - scan (inout) string by course of FormatNode * ---------- */ static int @@ -1772,7 +1776,7 @@ do { \ /* ---------- * Master of DATE for: - * TO_CHAR - write (inout) formated string + * TO_CHAR - write (inout) formated string * FROM_CHAR - scan (inout) string by course of FormatNode * ---------- */ @@ -2086,6 +2090,33 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return 1 + SKIP_THth(suf); } } + break; + case DCH_IW: + if (flag == TO_CHAR) + { + sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, + date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday)); + if (S_THth(suf)) + str_numth(p_inout, inout, S_TH_TYPE(suf)); + if (S_FM(suf) || S_THth(suf)) + return strlen(p_inout) - 1; + else + return 1; + + } + else if (flag == FROM_CHAR) + { + if (S_FM(suf)) + { + sscanf(inout, "%d", &tmfc->iw); + return int4len((int4) tmfc->iw) - 1 + SKIP_THth(suf); + } + else + { + sscanf(inout, "%02d", &tmfc->iw); + return 1 + SKIP_THth(suf); + } + } break; case DCH_Q: if (flag == TO_CHAR) @@ -2687,19 +2718,29 @@ to_timestamp(PG_FUNCTION_ARGS) case 4: tm->tm_mday = 1; tm->tm_mon = 10; break; } - if (tmfc->j) - j2date(tmfc->j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); if (tmfc->yyyy) tm->tm_year = tmfc->yyyy; + + if (tmfc->j) + j2date(tmfc->j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + if (tmfc->bc && tm->tm_year > 0) tm->tm_year = -(tm->tm_year); + if (tm->tm_year < 0) tm->tm_year = tm->tm_year + 1; + + if (tmfc->iw) + 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) tm->tm_yday = tmfc->ddd; if (tmfc->mm) tm->tm_mon = tmfc->mm; + /* + * we not ignore DDD + */ if (tmfc->ddd && (tm->tm_mon <=1 || tm->tm_mday <=1)) { /* count mday and mon from yday */ @@ -2726,6 +2767,7 @@ to_timestamp(PG_FUNCTION_ARGS) tm->tm_mday = i == 0 ? tm->tm_yday : tm->tm_yday - y[i-1]; } + /* -------------------------------------------------------------- */ #ifdef DEBUG_TO_FROM_CHAR diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index d176a8fd23..31e791170f 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -2,7 +2,7 @@ /* ----------------------------------------------------------------------- * pg_locale.c * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.5 2000/06/29 01:19:36 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.6 2000/08/29 04:41:47 momjian Exp $ * * * Portions Copyright (c) 1999-2000, PostgreSQL, Inc @@ -26,6 +26,8 @@ /* #define DEBUG_LOCALE_UTILS */ +static struct lconv *CurrentLocaleConv = NULL; + /*------ * Return in PG_LocaleCategories current locale setting *------ @@ -119,7 +121,9 @@ struct lconv * PGLC_localeconv(void) { PG_LocaleCategories lc; - struct lconv *lconv; + + if (CurrentLocaleConv) + return CurrentLocaleConv; /* Save current locale setting to lc */ PGLC_current(&lc); @@ -128,12 +132,12 @@ PGLC_localeconv(void) setlocale(LC_ALL, ""); /* Get numeric formatting information */ - lconv = localeconv(); + CurrentLocaleConv = localeconv(); /* Set previous original locale */ PGLC_setlocale(&lc); - return lconv; + return CurrentLocaleConv; } diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 0730d56147..8894f60d54 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.34 2000/07/17 03:05:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.35 2000/08/29 04:41:47 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1796,7 +1796,81 @@ interval_trunc(PG_FUNCTION_ARGS) PG_RETURN_INTERVAL_P(result); } +/* isoweek2date() + * + * Convert ISO week of year number to date. An year must be already set. + * karel 2000/08/07 + */ +void +isoweek2date( int woy, int *year, int *mon, int *mday) +{ + int day0, day4, dayn; + + if (!*year) + elog(ERROR, "isoweek2date(): can't convert 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) % 7); + + dayn = ((woy - 1) * 7) + (day4 - day0); + + j2date(dayn, year, mon, mday); +} + +/* date2isoweek() + * + * Returns ISO week number of year. + */ +int +date2isoweek(int year, int mon, int mday) +{ + float8 result; + int day0, day4, dayn; + + /* current day */ + dayn = date2j(year, mon, mday); + + /* fourth day of current year */ + day4 = date2j(year, 1, 4); + + /* day0 == offset to first day of week (Monday) */ + day0 = (j2day(day4 - 1) % 7); + + /* We need the first week containing a Thursday, + * otherwise this day falls into the previous year + * for purposes of counting weeks + */ + if (dayn < (day4 - day0)) + { + day4 = date2j((year - 1), 1, 4); + + /* day0 == offset to first day of week (Monday) */ + day0 = (j2day(day4 - 1) % 7); + } + + result = (((dayn - (day4 - day0)) / 7) + 1); + + /* Sometimes the last few days in a year will fall into + * the first week of the next year, so check for this. + */ + if (result >= 53) + { + day4 = date2j((year + 1), 1, 4); + + /* day0 == offset to first day of week (Monday) */ + day0 = (j2day(day4 - 1) % 7); + + if (dayn >= (day4 - day0)) + result = (((dayn - (day4 - day0)) / 7) + 1); + } + + return (int) result; +} + + /* timestamp_part() * Extract specified field from timestamp. */ @@ -1897,35 +1971,7 @@ timestamp_part(PG_FUNCTION_ARGS) break; case DTK_WEEK: - { - int day0, day4, dayn; - dayn = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); - day4 = date2j(tm->tm_year, 1, 4); - /* day0 == offset to first day of week (Monday) */ - day0 = (j2day(day4 - 1) % 7); - /* We need the first week containing a Thursday, - * otherwise this day falls into the previous year - * for purposes of counting weeks - */ - if (dayn < (day4 - day0)) - { - day4 = date2j((tm->tm_year - 1), 1, 4); - /* day0 == offset to first day of week (Monday) */ - day0 = (j2day(day4 - 1) % 7); - } - result = (((dayn - (day4 - day0)) / 7) + 1); - /* Sometimes the last few days in a year will fall into - * the first week of the next year, so check for this. - */ - if (result >= 53) - { - day4 = date2j((tm->tm_year + 1), 1, 4); - /* day0 == offset to first day of week (Monday) */ - day0 = (j2day(day4 - 1) % 7); - if (dayn >= (day4 - day0)) - result = (((dayn - (day4 - day0)) / 7) + 1); - } - } + result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday); break; case DTK_YEAR: diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index b848c894a0..5ee3575d1f 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: timestamp.h,v 1.9 2000/07/17 03:05:32 tgl Exp $ + * $Id: timestamp.h,v 1.10 2000/08/29 04:41:48 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -190,4 +190,7 @@ extern int timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, extern Timestamp SetTimestamp(Timestamp timestamp); +extern void isoweek2date( int woy, int *year, int *mon, int *mday); +extern int date2isoweek(int year, int mon, int mday); + #endif /* TIMESTAMP_H */