From efafeaf684a1d7cd7d65b205470d5438014be7cd Mon Sep 17 00:00:00 2001 From: Sami Kerola Date: Thu, 27 Aug 2015 14:21:26 +0100 Subject: cal: correct gregorian week numbering Jan 1 is always First week, and year always has 53 weeks. The week 53 may be cut short, e.g., it may and often has fewer than 7 days. Every year 28 year intervals US week numbering continues all the way to 54th week, such as 1972, 2000, and 2028. Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1249486 Reported-by: Michal Toth Signed-off-by: Sami Kerola --- misc-utils/cal.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'misc-utils/cal.c') diff --git a/misc-utils/cal.c b/misc-utils/cal.c index 548e56712..98ce43135 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -390,8 +390,8 @@ int main(int argc, char **argv) if (optarg) { ctl.req.week = strtos32_or_err(optarg, _("invalid week argument")); - if (ctl.req.week < 1 || 53 < ctl.req.week) - errx(EXIT_FAILURE,_("illegal week value: use 1-53")); + if (ctl.req.week < 1 || 54 < ctl.req.week) + errx(EXIT_FAILURE,_("illegal week value: use 1-54")); } ctl.weektype = WEEK_NUM_US; /* default per weekstart */ break; @@ -604,15 +604,13 @@ static void cal_fill_month(struct cal_month *month, const struct cal_control *ct int weeknum = week_number(1, month->month, month->year, ctl); weeklines = MAXDAYS / DAYS_IN_WEEK - weeklines / DAYS_IN_WEEK; for (i = 0; i < MAXDAYS / DAYS_IN_WEEK; i++) { - if (0 < weeklines) + if (0 < weeklines) { + if (52 < weeknum) + weeknum = week_number(month->days[i * DAYS_IN_WEEK], month->month, month->year, ctl); month->weeks[i] = weeknum++; - else + } else month->weeks[i] = SPACE; weeklines--; - if (i == 0 && (52 < weeknum || (month->year == 1753 && 51 < weeknum))) - weeknum = week_number(month->days[DAYS_IN_WEEK * (i + 1)], 1, month->year, ctl); - else if (52 < weeknum) - weeknum = week_number(31, 12, month->year, ctl); } } } @@ -839,7 +837,7 @@ static int day_in_week(int day, int month, int32_t year) /* * week_number - * return the week number of a given date, 1..53. + * return the week number of a given date, 1..54. * Supports ISO-8601 and North American modes. * Day may be given as Julian day of the year mode, in which * case the month is disregarded entirely. @@ -847,17 +845,16 @@ static int day_in_week(int day, int month, int32_t year) static int week_number(int day, int month, int32_t year, const struct cal_control *ctl) { int fday = 0, yday; - int wday = day_in_week(1, 1, year); + const int wday = day_in_week(1, 1, year); if (ctl->weektype & WEEK_NUM_ISO) fday = wday + (wday >= FRIDAY ? -2 : 5); - else - /* WEEK_NUM_US - * - according to gcal, the first Sun is in the first week - * - according to wikipedia, the first Sat is in the first week - */ - fday = wday + (wday == SUNDAY ? 6 : -1); - + else { + /* WEEK_NUM_US: Jan 1 is always First week, that may + * begin previous year. That means there is very seldom + * more than 52 weeks, */ + fday = wday + 6; + } /* For julian dates the month can be set to 1, the global julian * variable cannot be relied upon here, because we may recurse * internally for 31.12. which would not work. */ @@ -882,7 +879,7 @@ static int week_number(int day, int month, int32_t year, const struct cal_contro && day_in_week(day, month, year) <= WEDNESDAY && day_in_week(31, 12, year) >= MONDAY && day_in_week(31, 12, year) <= WEDNESDAY) - return week_number(1, 1, year + 1, ctl); + return week_number(1, 1, year + 1, ctl); return (yday + fday) / 7; } -- cgit v1.2.3-55-g7522