]> err.no Git - util-linux/commitdiff
cal: determine the first day of week from the locale
authorPádraig Brady <P@draigBrady.com>
Wed, 4 Mar 2009 10:07:29 +0000 (10:07 +0000)
committerKarel Zak <kzak@redhat.com>
Tue, 10 Mar 2009 12:01:39 +0000 (13:01 +0100)
Previously it defaulted to Sunday rather than using
the value from the locale. Lauri Nurmi <lanurmi@iki.fi>
provided the detailed argument for this change while
Samuel Thibault <samuel.thibault@ens-lyon.org> provided
the information on how to read the first day of the week
from the locale correctly.

[kzak@redhat.com: - fix "cast from pointer to integer",
                    nl_langinfo(_NL_TIME_WEEK_1STDAY) call)]

Signed-off-by: Pádraig Brady <P@draigBrady.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/cal.1
misc-utils/cal.c

index 53a6299280ad6141efa01bf5d47f1213be910c45..8f604ef09af78c1cdd1863d035b906f6053e1dd0 100644 (file)
@@ -58,7 +58,6 @@ Display single month output.
 Display prev/current/next month output.
 .It Fl s
 Display Sunday as the first day of the week.
-(This is the default.)
 .It Fl m
 Display Monday as the first day of the week.
 .It Fl j
@@ -81,7 +80,7 @@ and the day will be highlighted if the calendar is displayed on a terminal.
 If no parameters are specified, the current month's calendar is
 displayed.
 .Pp
-A year starts on Jan 1.
+A year starts on Jan 1. The first day of the week is determined by the locale.
 .Pp
 The Gregorian Reformation is assumed to have occurred in 1752 on the 3rd
 of September.
index 82603b1b07f5d95ccba61f2f3d9865387df10287..753cc24c4495310279a2cb29135d66ab72d36491 100644 (file)
@@ -205,9 +205,9 @@ int sep1752[MAXDAYS] = {
 
 /* utf-8 can have up to 6 bytes per char; and an extra byte for ending \0 */
 char day_headings[WEEK_LEN*6+1];
-/* week1stday = 1  =>   " M Tu  W Th  F  S  S " */
+/* weekstart = 1  =>   " M Tu  W Th  F  S  S " */
 char j_day_headings[J_WEEK_LEN*6+1];
-/* week1stday = 1  =>   "  M  Tu   W  Th   F   S   S " */
+/* weekstart = 1  =>   "  M  Tu   W  Th   F   S   S " */
 const char *full_month[12];
 
 /* leap year -- account for gregorian reformation in 1752 */
@@ -227,8 +227,8 @@ const char *full_month[12];
 #define        leap_years_since_year_1(yr) \
        ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
 
-/* 0 => sunday (default), 1 => monday */
-int week1stday=0;
+/* 0 => sunday, 1 => monday */
+int weekstart=0;
 int julian;
 
 #define TODAY_FLAG             0x400           /* flag day for highlighting */
@@ -285,26 +285,39 @@ main(int argc, char **argv) {
        }
 #endif
 
-#if 0                          /* setting week1stday is against man page */
 /*
- * What *is* the first day of the week? Note that glibc does not
- * provide any information today, it (almost) always answers Monday.
- * Sunday is the Jewish and Christian tradition.
- * Sometimes an answer is built into the language:
- * German calls Wednesday "Mittwoch", so starts at Sunday.
- * Portuguese calls Monday "segunda-feira", so starts at Sunday.
- * Russian calls Friday "pyatnitsa", so starts at Monday.
- * ISO 8601 decided to start at Monday.
- *
- * The traditional Unix cal utility starts at Sunday.
- * We start at Sunday and have an option -m for starting at Monday.
- *
- * At some future time this may become -s for Sunday, -m for Monday,
- * no option for glibc-determined locale-dependent version.
+ * The traditional Unix cal utility starts the week at Sunday,
+ * while ISO 8601 starts at Monday. We read the start day from
+ * the locale database, which can be overridden with the
+ * -s (Sunday) or -m (Monday) options.
  */
 #ifdef HAVE_LANGINFO_H
-       week1stday = (int)(nl_langinfo(_NL_TIME_FIRST_WEEKDAY))[0];
-#endif
+       /*
+        * You need to use 2 locale variables to get the first day of the week.
+        * This is needed to support first_weekday=2 and first_workday=1 for
+        * the rare case where working days span across 2 weeks.
+        * This shell script shows the combinations and calculations involved:
+
+        for LANG in en_US ru_RU fr_FR csb_PL POSIX; do
+          printf "%s:\t%s + %s -1 = " $LANG $(locale week-1stday first_weekday)
+          date -d"$(locale week-1stday) +$(($(locale first_weekday)-1))day" +%w
+        done
+
+        en_US:  19971130 + 1 -1 = 0  #0 = sunday
+        ru_RU:  19971130 + 2 -1 = 1
+        fr_FR:  19971201 + 1 -1 = 1
+        csb_PL: 19971201 + 2 -1 = 2
+        POSIX:  19971201 + 7 -1 = 0
+        */
+       {
+               int wfd;
+               union { unsigned int word; char *string; } val;
+               val.string = nl_langinfo(_NL_TIME_WEEK_1STDAY);
+
+               wfd = val.word;
+               wfd = day_in_week(wfd % 100, (wfd / 100) % 100, wfd / (100 * 100));
+               weekstart = (wfd + *nl_langinfo(_NL_TIME_FIRST_WEEKDAY) - 1) % 7;
+       }
 #endif
 
        yflag = 0;
@@ -317,10 +330,10 @@ main(int argc, char **argv) {
                        num_months = 3;
                        break;
                case 's':
-                       week1stday = 0;         /* default */
+                       weekstart = 0;          /* default */
                        break;
                case 'm':
-                       week1stday = 1;
+                       weekstart = 1;
                        break;
                case 'j':
                        julian = 1;
@@ -403,7 +416,7 @@ void headers_init(void)
 
   for(i = 0 ; i < 7 ; i++ ) {
      ssize_t space_left;
-     wd = (i + week1stday) % 7;
+     wd = (i + weekstart) % 7;
 
      if (i)
         strcat(cur_dh++, " ");
@@ -618,7 +631,7 @@ day_array(int day, int month, int year, int *days) {
 
        if (month == 9 && year == 1752) {
                d_sep1752 = julian ? j_sep1752 : sep1752;
-               memcpy(days, d_sep1752 + week1stday, MAXDAYS * sizeof(int));
+               memcpy(days, d_sep1752 + weekstart, MAXDAYS * sizeof(int));
                for (dm=0; dm<MAXDAYS; dm++)
                        if (j_sep1752[dm] == day)
                                days[dm] |= TODAY_FLAG;
@@ -626,7 +639,7 @@ day_array(int day, int month, int year, int *days) {
        }
        memcpy(days, empty, MAXDAYS * sizeof(int));
        dm = days_in_month[leap_year(year)][month];
-       dw = (day_in_week(1, month, year) - week1stday + 7) % 7;
+       dw = (day_in_week(1, month, year) - weekstart + 7) % 7;
        julday = day_in_year(1, month, year);
        daynum = julian ? julday : 1;
        while (dm--) {