summaryrefslogtreecommitdiff
path: root/usr.bin/cal
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2009-01-01 21:07:18 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2009-01-01 21:07:18 +0000
commit2343ea0ca4e58b33971b9c5aed47c1ebe6b7ec84 (patch)
treef55f206935b32b617df05e3e807f84cda82f5a5f /usr.bin/cal
parent9954e182a5952c5bca225576c1ec5332a29fcb01 (diff)
Fix iso weekno calculation by using a different algorithm. Still hard
to follow, but this one has a documented origin at least; ok pyr@ jasper@
Diffstat (limited to 'usr.bin/cal')
-rw-r--r--usr.bin/cal/cal.c63
1 files changed, 38 insertions, 25 deletions
diff --git a/usr.bin/cal/cal.c b/usr.bin/cal/cal.c
index 93391d06c90..9d65b68f81e 100644
--- a/usr.bin/cal/cal.c
+++ b/usr.bin/cal/cal.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cal.c,v 1.23 2008/04/18 14:41:04 pyr Exp $ */
+/* $OpenBSD: cal.c,v 1.24 2009/01/01 21:07:17 otto Exp $ */
/* $NetBSD: cal.c,v 1.6 1995/03/26 03:10:24 glass Exp $ */
/*
@@ -40,7 +40,7 @@ static const char copyright[] =
#if 0
static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94";
#else
-static const char rcsid[] = "$OpenBSD: cal.c,v 1.23 2008/04/18 14:41:04 pyr Exp $";
+static const char rcsid[] = "$OpenBSD: cal.c,v 1.24 2009/01/01 21:07:17 otto Exp $";
#endif
#endif /* not lint */
@@ -146,6 +146,7 @@ void day_array(int, int, int *);
int day_in_week(int, int, int);
int day_in_year(int, int, int);
int week(int, int, int);
+int isoweek(int, int, int);
void j_yearly(int);
void monthly(int, int);
void trim_trailing_spaces(char *);
@@ -251,39 +252,22 @@ main(int argc, char *argv[])
int
week(int day, int month, int year)
{
- int leap;
- int prevleap;
int yearday;
int firstweekday;
int weekday;
int firstday;
int firstsunday;
int shift;
+
+ if (mflag)
+ return isoweek(day, month, year);
yearday = day_in_year(day, month, year);
firstweekday = day_in_week(1, 1, year) + 1;
weekday = day_in_week(day, month, year) + 1;
- leap = leap_year(year);
- prevleap = leap_year(year - 1);
- firstday = firstsunday = day_in_year(1, 1, year);
+ firstday = day_in_year(1, 1, year);
firstsunday = firstday + (8 - firstweekday);
- if (!mflag)
- goto sunbased;
-
- if (yearday <= (8 - firstweekday) && firstweekday > 4) {
- if (firstweekday == 5 || (firstweekday == 6 && prevleap))
- return (53);
- return (52);
- }
-
- if (((leap ? 366 : 365) - yearday) < (4 - weekday))
- return (1);
-
- return (((yearday + (7 - weekday) + (firstweekday - 1)) / 7)
- - (firstweekday > 4));
-
-sunbased:
shift = 1;
if (yearday < firstsunday)
return (1);
@@ -292,6 +276,35 @@ sunbased:
return ((((yearday + 1) - (weekday - 1)) / 7) + shift);
}
+int
+isoweek(int day, int month, int year)
+{
+ /* http://www.tondering.dk/claus/cal/node8.html */
+ int a, b, c, s, e, f, g, d, n;
+
+ a = month <= 2 ? year - 1 : year;
+ b = a/4 - a/100 + a/400;
+ c = (a-1)/4 - (a-1)/100 + (a-1)/400;
+ s = b - c;
+ if (month <= 2) {
+ e = 0;
+ f = day - 1 + 31 * (month-1);
+ } else {
+ e = s + 1;
+ f = day + ((153 * (month-3) + 2) / 5) + 58 + s;
+ }
+ g = (a + b) % 7;
+ d = (f + g - e) % 7;
+ n = f + 3 - d;
+
+ if (n < 0)
+ return 53 - (g - s) / 5;
+ else if (n > 364 + s)
+ return 1;
+ else
+ return n/7 + 1;
+}
+
void
monthly(int month, int year)
{
@@ -317,7 +330,7 @@ monthly(int month, int year)
trim_trailing_spaces(lineout);
(void)printf("%-20s", lineout);
if (wflag && firstday != SPACE)
- printf(" [%2d]", week(firstday - mflag, month, year));
+ printf(" [%2d]", week(firstday, month, year));
printf("\n");
}
}
@@ -394,7 +407,7 @@ yearly(int year)
ascii_day(p, *dp++);
}
if (wflag && firstday != SPACE) {
- wn = week(firstday - mflag,
+ wn = week(firstday,
month + which_cal + 1, year);
(void)snprintf(p, 5, "[%2d]", wn);
p += strlen(p);