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 <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>
This commit is contained in:
Pádraig Brady 2009-03-04 10:07:29 +00:00 committed by Karel Zak
parent 7cfbafda9c
commit 0a9bead039
2 changed files with 40 additions and 28 deletions

View 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.

View 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--) {