From: Pádraig Brady
Date: Wed, 4 Mar 2009 10:07:29 +0000 (+0000)
Subject: cal: determine the first day of week from the locale
X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a9bead039d3d5c1445d94b9f439e8b1d08b4003;p=util-linux
cal: determine the first day of week from the locale
Previously it defaulted to Sunday rather than using
the value from the locale. Lauri Nurmi
provided the detailed argument for this change while
Samuel Thibault 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
Signed-off-by: Karel Zak
---
diff --git a/misc-utils/cal.1 b/misc-utils/cal.1
index 53a62992..8f604ef0 100644
--- a/misc-utils/cal.1
+++ b/misc-utils/cal.1
@@ -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.
diff --git a/misc-utils/cal.c b/misc-utils/cal.c
index 82603b1b..753cc24c 100644
--- a/misc-utils/cal.c
+++ b/misc-utils/cal.c
@@ -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