Fix to_char() locale handling to honor LC_TIME, not LC_MESSAGES.
authorBruce Momjian
Fri, 24 Nov 2006 15:26:18 +0000 (15:26 +0000)
committerBruce Momjian
Fri, 24 Nov 2006 15:26:18 +0000 (15:26 +0000)
Euler Taveira de Oliveira

src/backend/utils/adt/formatting.c
src/backend/utils/adt/pg_locale.c

index d97c1bf405a6b23dd2be497f9945da082b8f2cd8..93aad1a90157c1711db75a7f01ae1888f7ad23a9 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------
  * formatting.c
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.113 2006/10/04 00:29:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.114 2006/11/24 15:26:18 momjian Exp $
  *
  *
  *  Portions Copyright (c) 1999-2006, PostgreSQL Global Development Group
@@ -73,7 +73,7 @@
 #include 
 #include 
 #include 
-#include <locale.h>
+#include <time.h>
 
 #include "utils/builtins.h"
 #include "utils/date.h"
@@ -83,8 +83,6 @@
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
-#define _(x)   gettext((x))
-
 /* ----------
  * Routines type
  * ----------
@@ -163,7 +161,6 @@ struct FormatNode
 
 /* ----------
  * Full months
- * This needs to be NLS-localized someday.
  * ----------
  */
 static char *months_full[] = {
@@ -942,10 +939,6 @@ static NUMCacheEntry *NUM_cache_search(char *str);
 static NUMCacheEntry *NUM_cache_getnew(char *str);
 static void NUM_cache_remove(NUMCacheEntry *ent);
 
-static char *localize_month_full(int index);
-static char *localize_month(int index);
-static char *localize_day_full(int index);
-static char *localize_day(int index);
 
 /* ----------
  * Fast sequential search, use index for data selection which
@@ -2074,6 +2067,17 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
    struct pg_tm *tm = NULL;
    TmFromChar *tmfc = NULL;
    TmToChar   *tmtc = NULL;
+   char       *save_loc = NULL;
+
+   /*
+    * Set the LC_TIME only to do some operation (strftime) and then 
+    * set it back. See pg_locale.c for explanations.
+    */
+   if (S_TM(suf))
+   {
+       save_loc = setlocale(LC_TIME, NULL);
+       setlocale(LC_TIME, locale_time);
+   }
 
    if (is_to_char)
    {
@@ -2189,9 +2193,20 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
            if (!tm->tm_mon)
                return -1;
            if (S_TM(suf))
-               strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
+           {
+               /*
+                * tm_mon in 'pg_tm struct' based on one, but rather POSIX 'tm struct' based on zero.
+                * See notes at the top of this file.
+                */
+               tm->tm_mon = tm->tm_mon - 1;
+               strftime(workbuff, sizeof(workbuff), "%B", (struct tm *) tm);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                strcpy(workbuff, months_full[tm->tm_mon - 1]);
+           }
            sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
            return strlen(p_inout);
 
@@ -2200,9 +2215,22 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
            if (!tm->tm_mon)
                return -1;
            if (S_TM(suf))
-               sprintf(inout, "%*s", 0, localize_month_full(tm->tm_mon - 1));
+           {
+               /*
+                * tm_mon in 'pg_tm struct' based on one, but rather POSIX 'tm struct' based on zero.
+                * See notes at the top of this file.
+                */
+               tm->tm_mon = tm->tm_mon - 1;
+               strftime(inout, 32, "%B", (struct tm *) tm);
+               /* capitalize output */
+               inout[0] = pg_toupper((unsigned char) inout[0]);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
+           }
            return strlen(p_inout);
 
        case DCH_month:
@@ -2210,9 +2238,20 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
            if (!tm->tm_mon)
                return -1;
            if (S_TM(suf))
-               sprintf(inout, "%*s", 0, localize_month_full(tm->tm_mon - 1));
+           {
+               /*
+                * tm_mon in 'pg_tm struct' based on one, but rather POSIX 'tm struct' based on zero.
+                * See notes at the top of this file.
+                */
+               tm->tm_mon = tm->tm_mon - 1;
+               strftime(inout, 32, "%B", (struct tm *) tm);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
+           }
            *inout = pg_tolower((unsigned char) *inout);
            return strlen(p_inout);
 
@@ -2221,9 +2260,20 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
            if (!tm->tm_mon)
                return -1;
            if (S_TM(suf))
-               strcpy(inout, localize_month(tm->tm_mon - 1));
+           {
+               /*
+                * tm_mon in 'pg_tm struct' based on one, but rather POSIX 'tm struct' based on zero.
+                * See notes at the top of this file.
+                */
+               tm->tm_mon = tm->tm_mon - 1;
+               strftime(inout, 32, "%b", (struct tm *) tm);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                strcpy(inout, months[tm->tm_mon - 1]);
+           }
            str_toupper(inout);
            return strlen(p_inout);
 
@@ -2232,9 +2282,22 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
            if (!tm->tm_mon)
                return -1;
            if (S_TM(suf))
-               strcpy(inout, localize_month(tm->tm_mon - 1));
+           {
+               /*
+                * tm_mon in 'pg_tm struct' based on one, but rather POSIX 'tm struct' based on zero.
+                * See notes at the top of this file.
+                */
+               tm->tm_mon = tm->tm_mon - 1;
+               strftime(inout, 32, "%b", (struct tm *) tm);
+               /* capitalize output */
+               inout[0] = pg_toupper((unsigned char) inout[0]);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                strcpy(inout, months[tm->tm_mon - 1]);
+           }
            return strlen(p_inout);
 
        case DCH_mon:
@@ -2242,9 +2305,20 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
            if (!tm->tm_mon)
                return -1;
            if (S_TM(suf))
-               strcpy(inout, localize_month(tm->tm_mon - 1));
+           {
+               /*
+                * tm_mon in 'pg_tm struct' based on one, but rather POSIX 'tm struct' based on zero.
+                * See notes at the top of this file.
+                */
+               tm->tm_mon = tm->tm_mon - 1;
+               strftime(inout, 32, "%b", (struct tm *) tm);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                strcpy(inout, months[tm->tm_mon - 1]);
+           }
            *inout = pg_tolower((unsigned char) *inout);
            return strlen(p_inout);
 
@@ -2273,52 +2347,92 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
        case DCH_DAY:
            INVALID_FOR_INTERVAL;
            if (S_TM(suf))
-               strcpy(workbuff, localize_day_full(tm->tm_wday));
+           {
+               strftime(workbuff, sizeof(workbuff), "%A", (struct tm *) tm);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                strcpy(workbuff, days[tm->tm_wday]);
+           }
            sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
            return strlen(p_inout);
 
        case DCH_Day:
            INVALID_FOR_INTERVAL;
            if (S_TM(suf))
-               sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
+           {
+               strftime(inout, 32, "%A", (struct tm *) tm);
+               /* capitalize output */
+               inout[0] = pg_toupper((unsigned char) inout[0]);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
+           }
            return strlen(p_inout);
 
        case DCH_day:
            INVALID_FOR_INTERVAL;
            if (S_TM(suf))
-               sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
+           {
+               strftime(inout, 32, "%A", (struct tm *) tm);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
+           }
            *inout = pg_tolower((unsigned char) *inout);
            return strlen(p_inout);
 
        case DCH_DY:
            INVALID_FOR_INTERVAL;
            if (S_TM(suf))
-               strcpy(inout, localize_day(tm->tm_wday));
+           {
+               strftime(inout, 32, "%a", (struct tm *) tm);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                strcpy(inout, days_short[tm->tm_wday]);
+           }
            str_toupper(inout);
            return strlen(p_inout);
 
        case DCH_Dy:
            INVALID_FOR_INTERVAL;
            if (S_TM(suf))
-               strcpy(inout, localize_day(tm->tm_wday));
+           {
+               strftime(inout, 32, "%a", (struct tm *) tm);
+               /* capitalize output */
+               inout[0] = pg_toupper((unsigned char) inout[0]);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                strcpy(inout, days_short[tm->tm_wday]);
+           }
            return strlen(p_inout);
 
        case DCH_dy:
            INVALID_FOR_INTERVAL;
            if (S_TM(suf))
-               strcpy(inout, localize_day(tm->tm_wday));
+           {
+               strftime(inout, 32, "%a", (struct tm *) tm);
+               /* set it back; see comments in pg_locale.c */
+               setlocale(LC_TIME, save_loc);
+           }
            else
+           {
                strcpy(inout, days_short[tm->tm_wday]);
+           }
            *inout = pg_tolower((unsigned char) *inout);
            return strlen(p_inout);
 
@@ -2860,167 +2974,6 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval)
    return res;
 }
 
-static char *
-localize_month_full(int index)
-{
-   char       *m = NULL;
-
-   switch (index)
-   {
-       case 0:
-           m = _("January");
-           break;
-       case 1:
-           m = _("February");
-           break;
-       case 2:
-           m = _("March");
-           break;
-       case 3:
-           m = _("April");
-           break;
-       case 4:
-           m = _("May");
-           break;
-       case 5:
-           m = _("June");
-           break;
-       case 6:
-           m = _("July");
-           break;
-       case 7:
-           m = _("August");
-           break;
-       case 8:
-           m = _("September");
-           break;
-       case 9:
-           m = _("October");
-           break;
-       case 10:
-           m = _("November");
-           break;
-       case 11:
-           m = _("December");
-           break;
-   }
-
-   return m;
-}
-
-static char *
-localize_month(int index)
-{
-   char       *m = NULL;
-
-   switch (index)
-   {
-       case 0:
-           m = _("Jan");
-           break;
-       case 1:
-           m = _("Feb");
-           break;
-       case 2:
-           m = _("Mar");
-           break;
-       case 3:
-           m = _("Apr");
-           break;
-       case 4:
-           m = _("May");
-           break;
-       case 5:
-           m = _("Jun");
-           break;
-       case 6:
-           m = _("Jul");
-           break;
-       case 7:
-           m = _("Aug");
-           break;
-       case 8:
-           m = _("Sep");
-           break;
-       case 9:
-           m = _("Oct");
-           break;
-       case 10:
-           m = _("Nov");
-           break;
-       case 11:
-           m = _("Dec");
-           break;
-   }
-
-   return m;
-}
-
-static char *
-localize_day_full(int index)
-{
-   char       *d = NULL;
-
-   switch (index)
-   {
-       case 0:
-           d = _("Sunday");
-           break;
-       case 1:
-           d = _("Monday");
-           break;
-       case 2:
-           d = _("Tuesday");
-           break;
-       case 3:
-           d = _("Wednesday");
-           break;
-       case 4:
-           d = _("Thursday");
-           break;
-       case 5:
-           d = _("Friday");
-           break;
-       case 6:
-           d = _("Saturday");
-           break;
-   }
-
-   return d;
-}
-
-static char *
-localize_day(int index)
-{
-   char       *d = NULL;
-
-   switch (index)
-   {
-       case 0:
-           d = _("Sun");
-           break;
-       case 1:
-           d = _("Mon");
-           break;
-       case 2:
-           d = _("Tue");
-           break;
-       case 3:
-           d = _("Wed");
-           break;
-       case 4:
-           d = _("Thu");
-           break;
-       case 5:
-           d = _("Fri");
-           break;
-       case 6:
-           d = _("Sat");
-           break;
-   }
-
-   return d;
-}
 
 /****************************************************************************
  *             Public routines
index da81d79f392576a4bba5ecbb64ae6ba9fd533603..9ffe9acc038491d7bfa1336d0e1c777a7413bb66 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Portions Copyright (c) 2002-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.37 2006/10/04 00:29:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.38 2006/11/24 15:26:18 momjian Exp $
  *
  *-----------------------------------------------------------------------
  */
@@ -26,8 +26,7 @@
  * required information obtained from localeconv(), and set them back.
  * The cached information is only used by the formatting functions
  * (to_char, etc.) and the money type. For the user, this should all be
- * transparent.  (Actually, LC_TIME doesn't do anything at all right
- * now.)
+ * transparent.
  *
  * !!! NOW HEAR THIS !!!
  *