cal: add --saturday option to set Saturday as start of week · util-linux/util-linux@3ad7df1 · GitHub
Skip to content

Commit 3ad7df1

Browse files
committed
cal: add --saturday option to set Saturday as start of week
Add -t, --saturday option to display Saturday as the first day of the week, alongside the existing --sunday (-s) and --monday (-m) options. - Add -t/--saturday to getopt and longopts. - Fix cal_fill_month day alignment and remove the month_days increment that corrupted calendar grids when weekstart was Saturday. - Adjust firstwork index to 2 for workday/weekend color highlighting. - Generalize week_number and week_to_day calculations for weekstart. - Update bash-completion, man page, and regression tests. Fixes: #3861 Signed-off-by: MkP369 <kritarthprasad01@gmail.com>
1 parent 33dbb9c commit 3ad7df1

64 files changed

Lines changed: 1242 additions & 26 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎bash-completion/cal‎

Lines changed: 8 additions & 7 deletions

‎misc-utils/cal.1.adoc‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ Display _number_ of months, starting from the month containing the date.
7777
*-S, --span*::
7878
Display months spanning the date.
7979
80+
*-t*, *--saturday*::
81+
Display Saturday as the first day of the week.
82+
8083
*-s*, *--sunday*::
8184
Display Sunday as the first day of the week.
8285
@@ -151,7 +154,7 @@ Denote the _day_ (1-31), _month and year_, and the day will be highlighted if th
151154
152155
== NOTES
153156
154-
A year starts on January 1. The first day of the week is determined by the locale or the *--sunday* and *--monday* options.
157+
A year starts on January 1. The first day of the week is determined by the locale or the *--sunday*, *--monday* and *--saturday* options.
155158
156159
The week numbering depends on the choice of the first day of the week. If it is Sunday then the customary North American numbering is used, where 1 January is in week number 1. If it is Monday (*-m*) then the ISO 8601 standard week numbering is used, where the first Thursday is in week number 1.
157160

‎misc-utils/cal.c‎

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ int main(int argc, char **argv)
305305
static const struct option longopts[] = {
306306
{"one", no_argument, NULL, '1'},
307307
{"three", no_argument, NULL, '3'},
308+
{"saturday", no_argument, NULL, 't'},
308309
{"sunday", no_argument, NULL, 's'},
309310
{"monday", no_argument, NULL, 'm'},
310311
{"julian", no_argument, NULL, 'j'},
@@ -338,7 +339,7 @@ int main(int argc, char **argv)
338339
* The traditional Unix cal utility starts the week at Sunday,
339340
* while ISO 8601 starts at Monday. We read the start day from
340341
* the locale database, which can be overridden with the
341-
* -s (Sunday) or -m (Monday) options.
342+
* -t (Saturday), -s (Sunday) or -m (Monday) options.
342343
*/
343344
#if HAVE_DECL__NL_TIME_WEEK_1STDAY
344345
/*
@@ -369,7 +370,7 @@ int main(int argc, char **argv)
369370
ctl.weekstart = (wfd + *nl_langinfo(_NL_TIME_FIRST_WEEKDAY) - 1) % DAYS_IN_WEEK;
370371
}
371372
#endif
372-
while ((ch = getopt_long(argc, argv, "13mjn:sSywYvc:Vh", longopts, NULL)) != -1) {
373+
while ((ch = getopt_long(argc, argv, "13mjn:stSywYvc:Vh", longopts, NULL)) != -1) {
373374

374375
err_exclusive_options(ch, longopts, excl, excl_st);
375376

@@ -381,6 +382,9 @@ int main(int argc, char **argv)
381382
ctl.num_months = 3;
382383
ctl.span_months = 1;
383384
break;
385+
case 't':
386+
ctl.weekstart = SATURDAY;
387+
break;
384388
case 's':
385389
ctl.weekstart = SUNDAY; /* default */
386390
break;
@@ -726,13 +730,8 @@ static void cal_fill_month(struct cal_month *month, const struct cal_control *ct
726730
j = 1;
727731
month_days = j + days_in_month[leap_year(ctl, month->year)][month->month];
728732

729-
/* True when Sunday is not first day in the output week. */
730-
if (ctl->weekstart) {
731-
first_week_day -= ctl->weekstart;
732-
if (first_week_day < 0)
733-
first_week_day = DAYS_IN_WEEK - ctl->weekstart;
734-
month_days += ctl->weekstart - 1;
735-
}
733+
/* Offset when Sunday is not first day in the output week. */
734+
first_week_day = (first_week_day - ctl->weekstart + DAYS_IN_WEEK) % DAYS_IN_WEEK;
736735

737736
/* Fill day array. */
738737
for (i = 0; i < MAXDAYS; i++) {
@@ -873,7 +872,14 @@ static void cal_output_months(struct cal_month *month, const struct cal_control
873872
int reqday, week_line, d;
874873
int skip;
875874
struct cal_month *i;
876-
int firstwork = ctl->weekstart == SUNDAY ? 1 : 0; /* first workday in week */
875+
int firstwork; /* first workday in week */
876+
877+
if (ctl->weekstart == SUNDAY)
878+
firstwork = 1;
879+
else if (ctl->weekstart == SATURDAY)
880+
firstwork = 2;
881+
else
882+
firstwork = 0;
877883

878884
/* Let's keep sequence cached rather than search it for each day */
879885
const char *seq_wo_start = cal_get_color_sequence(CAL_COLOR_WORKDAY);
@@ -966,7 +972,14 @@ cal_vert_output_months(struct cal_month *month, const struct cal_control *ctl)
966972
int i, reqday, week, d;
967973
int skip;
968974
struct cal_month *m;
969-
int firstwork = ctl->weekstart == SUNDAY ? 1 : 0; /* first workday in week */
975+
int firstwork; /* first workday in week */
976+
977+
if (ctl->weekstart == SUNDAY)
978+
firstwork = 1;
979+
else if (ctl->weekstart == SATURDAY)
980+
firstwork = 2;
981+
else
982+
firstwork = 0;
970983

971984
const char *seq_wo_start = cal_get_color_sequence(CAL_COLOR_WORKDAY);
972985
const char *seq_wo_end = cal_get_color_disable_sequence(CAL_COLOR_WORKDAY);
@@ -1227,7 +1240,8 @@ static int week_number(int day, int month, int32_t year, const struct cal_contro
12271240
/* WEEK_NUM_US: Jan 1 is always First week, that may
12281241
* begin previous year. That means there is very seldom
12291242
* more than 52 weeks, */
1230-
fday = wday + 6;
1243+
int wday_offset = (wday - ctl->weekstart + DAYS_IN_WEEK) % DAYS_IN_WEEK;
1244+
fday = 6 + wday_offset;
12311245
}
12321246
/* For julian dates the month can be set to 1, the global julian
12331247
* variable cannot be relied upon here, because we may recurse
@@ -1261,22 +1275,25 @@ static int week_number(int day, int month, int32_t year, const struct cal_contro
12611275
* return the yday of the first day in a given week inside
12621276
* the given year. This may be something other than Monday
12631277
* for ISO-8601 modes. For North American numbering this
1264-
* always returns a Sunday.
1278+
* returns the first day of the week based on weekstart.
12651279
*/
12661280
static int week_to_day(const struct cal_control *ctl)
12671281
{
12681282
int yday, wday;
12691283

12701284
wday = day_in_week(ctl, 1, JANUARY, ctl->req.year);
1271-
yday = ctl->req.week * DAYS_IN_WEEK - wday;
1285+
1286+
if (ctl->weektype & WEEK_NUM_ISO) {
1287+
yday = ctl->req.week * DAYS_IN_WEEK - wday;
1288+
yday -= (wday >= FRIDAY ? -2 : 5);
1289+
} else {
1290+
int wday_offset = (wday - ctl->weekstart + DAYS_IN_WEEK) % DAYS_IN_WEEK;
1291+
yday = ctl->req.week * DAYS_IN_WEEK - (6 + wday_offset);
1292+
}
12721293

12731294
if (ctl->req.year == ctl->reform_year && yday >= YDAY_AFTER_MISSING)
12741295
yday += NUMBER_MISSING_DAYS;
12751296

1276-
if (ctl->weektype & WEEK_NUM_ISO)
1277-
yday -= (wday >= FRIDAY ? -2 : 5);
1278-
else
1279-
yday -= 6; /* WEEK_NUM_US */
12801297
if (yday <= 0)
12811298
return 1;
12821299

@@ -1363,6 +1380,7 @@ static void __attribute__((__noreturn__)) usage(void)
13631380
fputs(_(" -3, --three show three months spanning the date\n"), out);
13641381
fputs(_(" -n, --months <num> show num months starting with date's month\n"), out);
13651382
fputs(_(" -S, --span span the date when displaying multiple months\n"), out);
1383+
fputs(_(" -t, --saturday Saturday as first day of week\n"), out);
13661384
fputs(_(" -s, --sunday Sunday as first day of week\n"), out);
13671385
fputs(_(" -m, --monday Monday as first day of week\n"), out);
13681386
fputs(_(" -j, --julian use day-of-year for all calendars\n"), out);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Gregorian - Saturday-based month
2+
December 2147483646
3+
Sa Su Mo Tu We Th Fr
4+
1 2 3 4 5 6 7
5+
8 9 10 11 12 13 14
6+
15 16 17 18 19 20 21
7+
22 23 24 25 26 27 28
8+
29 30 31
9+

‎tests/expected/cal/bigyear-1t-year‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Gregorian - Saturday-based year
2+
January 2147483646
3+
Sa Su Mo Tu We Th Fr
4+
1 2 3 4 5
5+
6 7 8 9 10 11 12
6+
13 14 15 16 17 18 19
7+
20 21 22 23 24 25 26
8+
27 28 29 30 31
9+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Julian - Saturday-based month
2+
December 2147483646
3+
Sat Sun Mon Tue Wed Thu Fri
4+
335 336 337 338 339 340 341
5+
342 343 344 345 346 347 348
6+
349 350 351 352 353 354 355
7+
356 357 358 359 360 361 362
8+
363 364 365
9+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Julian - Saturday-based year
2+
January 2147483646
3+
Sat Sun Mon Tue Wed Thu Fri
4+
1 2 3 4 5
5+
6 7 8 9 10 11 12
6+
13 14 15 16 17 18 19
7+
20 21 22 23 24 25 26
8+
27 28 29 30 31
9+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Julian - Saturday-based month with weeks
2+
December 2147483646
3+
Sat Sun Mon Tue Wed Thu Fri
4+
49 335 336 337 338 339 340 341
5+
50 342 343 344 345 346 347 348
6+
51 349 350 351 352 353 354 355
7+
52 356 357 358 359 360 361 362
8+
53 363 364 365
9+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Julian - Saturday-based year with weeks
2+
January 2147483646
3+
Sat Sun Mon Tue Wed Thu Fri
4+
1 1 2 3 4 5
5+
2 6 7 8 9 10 11 12
6+
3 13 14 15 16 17 18 19
7+
4 20 21 22 23 24 25 26
8+
5 27 28 29 30 31
9+
Lines changed: 9 additions & 0 deletions

0 commit comments

Comments
 (0)