Make date(1) compatible to GNU date(1).

We have variable first day of weeks now! My week starts on Wednesday!
This commit is contained in:
Christoph Lohmann 2013-06-19 22:10:26 +02:00
parent 0f523ec9c6
commit b10b1da57d
2 changed files with 126 additions and 64 deletions

50
cal.1
View File

@ -3,13 +3,20 @@
cal \- print calendar cal \- print calendar
.SH SYNOPSIS .SH SYNOPSIS
.B cal .B cal
.RB [ \-1 ]
.RB [ \-3 ]
.RB [ \-m ]
.RB [ \-s ]
.RB [ \-y ]
.RB [ \-c .RB [ \-c
.IR columns ] .IR columns ]
.RB [ \-m .RB [ \-f
.IR month ] .IR firstday ]
.RB [ \-n .RB [ \-n
.IR number ] .IR nmonths ]
.RB [ \-y .RB [ [ [
.IR day ]
.IR month ]
.IR year ] .IR year ]
.SH DESCRIPTION .SH DESCRIPTION
Beginning with Beginning with
@ -20,23 +27,34 @@ print
.IR number .IR number
of calendars side by side. Each row of calendars contains at most of calendars side by side. Each row of calendars contains at most
.IR columns .IR columns
number of calendars. number of calendars. The defaults are obtained using
.IR localtime (3).
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-1
Print one single month.
.TP
.B \-3
Print prev/current/nexth month.
.TP
.B \-m
Print Monday as first day of week.
.TP
.B \-s
Print Sunday as first day of week.
.TP
.B \-y
Print a calendar of the current year.
.TP
.BI \-c " columns" .BI \-c " columns"
print Print
.IR columns .IR columns
number of calendars in a row. default is 3 number of calendars in a row. The default is 3.
.TP .TP
.BI \-m " month" .BI \-f " firstday"
starting month. default is obtained from Specify the first day of the week. 0 is Sunday and 6 is Saturday.
.IR localtime (3)
.TP .TP
.BI \-n " number" .BI \-n " nmonths"
number of calendars to print. default is 1 Specify the number months to print. The default is 1.
.TP
.BI \-y " year"
starting year. default is obtained from
.IR localtime (3)
.SH SEE ALSO .SH SEE ALSO
.IR localtime (3) .IR localtime (3)

140
cal.c
View File

@ -7,29 +7,30 @@
#define MONTHMAX 100 #define MONTHMAX 100
static void drawcal(int, int, int, int, int); static void drawcal(int, int, int, int, int, int);
static int dayofweek(int, int, int); static int dayofweek(int, int, int, int);
static bool isleap(int); static bool isleap(int);
static void usage(void); static void usage(void);
static void static void
drawcal(int year, int month, int day, int ncols, int nmons) drawcal(int year, int month, int day, int ncols, int nmons, int fday)
{ {
char str[21]; char str[21];
int count[MONTHMAX]; int count[MONTHMAX];
int d, i, r; int d, i, r, j;
int moff, yoff, cur, last, ndays, day1; int moff, yoff, cur, last, ndays, day1;
char *smon[]= { char *smon[] = {
" January", " February", " March", " January", " February", " March",
" April", " May", " June", " April", " May", " June",
" July", " August", " September", " July", " August", " September",
" October", " November", " December" }; " October", " November", " December" };
int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int row = 0; int row = 0;
char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", };
while (nmons > 0) { while(nmons > 0) {
last = MIN(nmons, ncols); last = MIN(nmons, ncols);
for (i = 0; i < last; i++) { for(i = 0; i < last; i++) {
moff = month + ncols * row + i - 1; moff = month + ncols * row + i - 1;
cur = moff % 12; cur = moff % 12;
yoff = year + moff / 12; yoff = year + moff / 12;
@ -40,24 +41,30 @@ drawcal(int year, int month, int day, int ncols, int nmons)
} }
printf("\n"); printf("\n");
for (i = 0; i < last; i++) for(i = 0; i < last; i++) {
printf("Su M Tu W Th F Sa "); for(j = fday; j < LEN(days); j++)
printf("%s ", days[j]);
for(j = 0; j < fday; j++)
printf("%s ", days[j]);
printf(" ");
}
printf("\n"); printf("\n");
for (r = 0; r < 6; r++) { for(r = 0; r < 6; r++) {
for (i = 0; i < last; i++) { for(i = 0; i < last; i++) {
moff = month + ncols * row + i - 1; moff = month + ncols * row + i - 1;
cur = moff % 12; cur = moff % 12;
yoff = year + moff / 12; yoff = year + moff / 12;
ndays = mdays[cur] + ((cur == 1) & isleap(yoff)); ndays = mdays[cur] + ((cur == 1) & isleap(yoff));
day1 = dayofweek(year, cur, 1); day1 = dayofweek(year, cur, 1, fday);
for (d = 0; d < 7; d++) for(d = 0; d < 7; d++) {
if ((r || d >= day1) && count[i] <= ndays) if((r || d >= day1) && count[i] <= ndays)
printf("%2d ", count[i]++); printf("%2d ", count[i]++);
else else
printf(" "); printf(" ");
}
printf(" "); printf(" ");
} }
printf("\n"); printf("\n");
@ -67,32 +74,19 @@ drawcal(int year, int month, int day, int ncols, int nmons)
} }
} }
static void
defaults(int *year, int *month, int *day, int *ncols, int *nmons)
{
time_t now;
struct tm *ltime;
now = time(NULL);
ltime = localtime(&now);
*year = ltime->tm_year + 1900;
*month = ltime->tm_mon + 1;
*day = ltime->tm_mday;
*ncols = 3;
*nmons = 1;
}
static int static int
dayofweek(int year, int month, int day) dayofweek(int year, int month, int day, int fday)
{ {
int a, y, m; int a, y, m, d;
month++; month++;
a = (14 - month) / 12; a = (14 - month) / 12;
y = year + 4800 - a; y = year + 4800 - a;
m = month + 12 * a -3; m = month + 12 * a - 3;
return (day + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 32045 + 1) % 7; d = (day + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y \
/ 400 - 32045 + 1) % 7;
return (fday > d)? (7 - d) : (d - fday);
} }
static bool static bool
@ -100,9 +94,12 @@ isleap(int year)
{ {
bool leap = false; bool leap = false;
if (year % 4 == 0) leap = true; if(year % 4 == 0)
if (year % 100 == 0) leap = false; leap = true;
if (year % 400 == 0) leap = true; if(year % 100 == 0)
leap = false;
if(year % 400 == 0)
leap = true;
return leap; return leap;
} }
@ -110,38 +107,85 @@ isleap(int year)
static void static void
usage(void) usage(void)
{ {
eprintf("usage: %s [-c columns] [-m month] [-n number] [-y year]\n", argv0); eprintf("usage: %s [-c columns] [-m month] [-n number] [-y year]\n",
exit(1); argv0);
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int year, month, day, ncols, nmons; int year, month, day, ncols, nmons, fday;
struct tm *ltime;
time_t now;
defaults(&year, &month, &day, &ncols, &nmons); now = time(NULL);
ltime = localtime(&now);
year = ltime->tm_year + 1900;
month = ltime->tm_mon + 1;
day = ltime->tm_mday;
fday = 0;
ncols = 3;
nmons = 1;
ARGBEGIN { ARGBEGIN {
case 'c': case '1':
ncols = (int) estrtol(EARGF(usage()), 0); nmons = 1;
break; break;
case 'm': case '3':
month = (int) estrtol(EARGF(usage()), 0); nmons = 3;
month -= 1;
if(month == 0) {
month = 12;
year--;
}
break;
case 'c':
ncols = estrtol(EARGF(usage()), 0);
break;
case 'f':
fday = estrtol(EARGF(usage()), 0);
break;
case 'm': /* Monday */
fday = 1;
break; break;
case 'n': case 'n':
nmons = (int) estrtol(EARGF(usage()), 0); nmons = estrtol(EARGF(usage()), 0);
break;
case 's': /* Sunday */
fday = 0;
break; break;
case 'y': case 'y':
year = (int) estrtol(EARGF(usage()), 0); month = 1;
nmons = 12;
break; break;
default: default:
usage(); usage();
} ARGEND; } ARGEND;
if (ncols < 0 || ncols > MONTHMAX || month < 1 || month > 12 || nmons < 1 || year > 9999) switch(argc) {
case 3:
day = estrtol(argv[0], 0);
argv++;
case 2:
month = estrtol(argv[0], 0);
argv++;
case 1:
year = estrtol(argv[0], 0);
break;
case 0:
break;
default:
usage(); usage();
}
if(ncols < 0 || ncols > MONTHMAX || month < 1 || month > 12 \
|| nmons < 1 || fday < 0 || fday > 6) {
usage();
}
drawcal(year, month, day, ncols, nmons, fday);
drawcal(year, month, day, ncols, nmons);
exit(0); exit(0);
} }