git: 1ca7f6618536 - main - ncal(1): handle Sweden's transitional calendar (1700-1712)
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 13 Oct 2026 00:30:31 UTC
The branch main has been updated by asomers:
URL: https://cgit.FreeBSD.org/src/commit/?id=1ca7f6618536febba5b500c050cddaf06bd2342a
commit 1ca7f6618536febba5b500c050cddaf06bd2342a
Author: Juan Michelini <juan@juan.com.uy>
AuthorDate: 2026-10-09 14:28:25 +0000
Commit: Alan Somers <asomers@FreeBSD.org>
CommitDate: 2026-10-13 00:30:07 +0000
ncal(1): handle Sweden's transitional calendar (1700-1712)
Sweden used a unique intermediate calendar during 1700-1712. In 1700,
Sweden omitted the Julian leap day (Feb 29, 1700) to begin a gradual
transition to the Gregorian calendar. The transition was abandoned
mid-way due to the Great Northern War; to revert to the Julian calendar,
an extra day "Feb 30, 1712" was added. Sweden finally adopted the
Gregorian calendar in 1753 (already handled correctly by ncal).
ncal previously displayed Feb 1700 as a 29-day month and Feb 1712 as a
29-day month, both incorrect for the Swedish (-s SE) calendar mode.
Add flag_sweden, which is set when the SE country code is selected (via
-s SE or the locale) and cleared by -J, since -J selects the plain
Julian calendar. When active, sndaysr() and sdater() apply the one-day
offset that characterised the Swedish transitional calendar:
- Feb 1700: displayed with 28 days (no leap day)
- 1700-03-01 to 1712-02-30: dates run one day ahead of Julian, so
weekdays are correctly anchored to the actual solar day
- Feb 1712: displayed with 30 days (the unique "Feb 30" day)
- 1712-03-01 onward: back to Julian until the 1753 Gregorian switch
Add ATF tests covering the 3-month and Julian-day views around both
boundaries and the -J override.
Reported-by: John Costello <https://joxn.org>
Signed-off-by: Juan Michelini <juan@juan.com.uy>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reviewed by: asomers, js
MFC after: 2 weeks
Pull Request: https://github.com/freebsd/freebsd-src/pull/2353
---
usr.bin/ncal/ncal.c | 24 +++++++++++++++
usr.bin/ncal/tests/Makefile | 5 ++++
usr.bin/ncal/tests/ncal_test.sh | 36 +++++++++++++++++++++++
usr.bin/ncal/tests/regress.se-J-170002-nhl.out | 8 +++++
usr.bin/ncal/tests/regress.se-r-3-1700-nhl.out | 8 +++++
usr.bin/ncal/tests/regress.se-r-3-1712-nhl.out | 8 +++++
usr.bin/ncal/tests/regress.se-r-jd-170003-nhl.out | 8 +++++
usr.bin/ncal/tests/regress.se-r-jd-171202-nhl.out | 8 +++++
8 files changed, 105 insertions(+)
diff --git a/usr.bin/ncal/ncal.c b/usr.bin/ncal/ncal.c
index dc50dd60bf0b..e4f2b96524a2 100644
--- a/usr.bin/ncal/ncal.c
+++ b/usr.bin/ncal/ncal.c
@@ -164,6 +164,7 @@ static int nswitch; /* user defined switch date */
static int nswitchb; /* switch date for backward compatibility */
static int highlightdate;
static bool flag_monday; /* user wants week starts on Monday */
+static bool flag_sweden; /* Sweden, 1700-1712 */
static char *center(char *s, char *t, int w);
static wchar_t *wcenter(wchar_t *s, wchar_t *t, int w);
@@ -219,6 +220,7 @@ main(int argc, char *argv[])
flag_highlight = isatty(STDOUT_FILENO);
flag_weeks = 0;
flag_monday = false;
+ flag_sweden = false;
/*
* Use locale to determine the country code,
@@ -243,6 +245,7 @@ main(int argc, char *argv[])
} else {
nswitch = ndaysj(&p->dt);
dftswitch = p;
+ flag_sweden = (strcmp(p->cc, "SE") == 0);
}
@@ -285,6 +288,7 @@ main(int argc, char *argv[])
usage();
nswitch = ndaysj(&never);
flag_julian_cal = 1;
+ flag_sweden = false;
break;
case 'C':
flag_backward = 1;
@@ -342,6 +346,7 @@ main(int argc, char *argv[])
errx(EX_USAGE,
"%s: invalid country code", optarg);
nswitch = ndaysj(&(p->dt));
+ flag_sweden = (strcmp(p->cc, "SE") == 0);
break;
case 'w':
if (flag_backward)
@@ -1015,6 +1020,11 @@ static int
sndaysr(struct date *d)
{
+ /* Sweden skipped Feb 29, 1700 and added Feb 30, 1712. */
+ if (flag_sweden && d->y * 12 + d->m >= 1700 * 12 + 3 &&
+ d->y * 12 + d->m < 1712 * 12 + 3)
+ return (ndaysj(d) - 1);
+
if (nswitch != 0)
if (nswitch < ndaysj(d))
return (ndaysg(d));
@@ -1043,6 +1053,20 @@ static struct date *
sdater(int nd, struct date *d)
{
+ /* Inverse of the Sweden case in sndaysr(). */
+ if (flag_sweden) {
+ date start = { 1700, 2, 29 }, end = { 1712, 3, 1 };
+
+ if (nd >= ndaysj(&start) && nd < ndaysj(&end)) {
+ jdate(nd + 1, d);
+ if (d->y == 1712 && d->m == 3) {
+ d->m = 2;
+ d->d = 30;
+ }
+ return (d);
+ }
+ }
+
if (nswitch < nd)
return (gdate(nd, d));
else
diff --git a/usr.bin/ncal/tests/Makefile b/usr.bin/ncal/tests/Makefile
index c270e28b12f2..8e4c38d00317 100644
--- a/usr.bin/ncal/tests/Makefile
+++ b/usr.bin/ncal/tests/Makefile
@@ -91,5 +91,10 @@ ${PACKAGE}FILES+= regress.s-r-B-nhl.out
${PACKAGE}FILES+= regress.s-r-gmgy-nhl.out
${PACKAGE}FILES+= regress.s-r-m-nhl.out
${PACKAGE}FILES+= regress.s-r-mgy-nhl.out
+${PACKAGE}FILES+= regress.se-J-170002-nhl.out
+${PACKAGE}FILES+= regress.se-r-3-1700-nhl.out
+${PACKAGE}FILES+= regress.se-r-3-1712-nhl.out
+${PACKAGE}FILES+= regress.se-r-jd-170003-nhl.out
+${PACKAGE}FILES+= regress.se-r-jd-171202-nhl.out
.include <bsd.test.mk>
diff --git a/usr.bin/ncal/tests/ncal_test.sh b/usr.bin/ncal/tests/ncal_test.sh
index 51bc99a888cc..bd49fd061957 100644
--- a/usr.bin/ncal/tests/ncal_test.sh
+++ b/usr.bin/ncal/tests/ncal_test.sh
@@ -136,6 +136,39 @@ ncal_options_body()
ncal_out s-r-gmgy-nhl -N -d 2008.03 1 2007
}
+atf_test_case sweden
+sweden_head()
+{
+ atf_set "descr" "Sweden's 1700-1712 transitional calendar"
+}
+sweden_body()
+{
+ # February 1700 has no leap day and February 1712 has 30 days.
+ ncal_out se-r-3-1700-nhl -N -h -3 -s SE -d 1700.02
+ ncal_out se-r-3-1712-nhl -N -h -3 -s SE -d 1712.02
+}
+
+atf_test_case sweden_jd
+sweden_jd_head()
+{
+ atf_set "descr" "Sweden's transitional calendar in Julian-day format"
+}
+sweden_jd_body()
+{
+ ncal_out se-r-jd-170003-nhl -N -h -j -s SE 3 1700
+ ncal_out se-r-jd-171202-nhl -N -h -j -s SE 2 1712
+}
+
+atf_test_case sweden_julian
+sweden_julian_head()
+{
+ atf_set "descr" "-J overrides the Swedish transitional calendar"
+}
+sweden_julian_body()
+{
+ ncal_out se-J-170002-nhl -N -h -s SE -J 2 1700
+}
+
atf_init_test_cases()
{
atf_add_test_case year_md
@@ -145,4 +178,7 @@ atf_init_test_cases()
atf_add_test_case invalid_args
atf_add_test_case cal_options
atf_add_test_case ncal_options
+ atf_add_test_case sweden
+ atf_add_test_case sweden_jd
+ atf_add_test_case sweden_julian
}
diff --git a/usr.bin/ncal/tests/regress.se-J-170002-nhl.out b/usr.bin/ncal/tests/regress.se-J-170002-nhl.out
new file mode 100644
index 000000000000..0a1b0248da5b
--- /dev/null
+++ b/usr.bin/ncal/tests/regress.se-J-170002-nhl.out
@@ -0,0 +1,8 @@
+ February 1700
+Mo 5 12 19 26
+Tu 6 13 20 27
+We 7 14 21 28
+Th 1 8 15 22 29
+Fr 2 9 16 23
+Sa 3 10 17 24
+Su 4 11 18 25
diff --git a/usr.bin/ncal/tests/regress.se-r-3-1700-nhl.out b/usr.bin/ncal/tests/regress.se-r-3-1700-nhl.out
new file mode 100644
index 000000000000..ca2998159319
--- /dev/null
+++ b/usr.bin/ncal/tests/regress.se-r-3-1700-nhl.out
@@ -0,0 +1,8 @@
+ January 1700 February 1700 March 1700
+Mo 1 8 15 22 29 5 12 19 26 5 12 19 26
+Tu 2 9 16 23 30 6 13 20 27 6 13 20 27
+We 3 10 17 24 31 7 14 21 28 7 14 21 28
+Th 4 11 18 25 1 8 15 22 1 8 15 22 29
+Fr 5 12 19 26 2 9 16 23 2 9 16 23 30
+Sa 6 13 20 27 3 10 17 24 3 10 17 24 31
+Su 7 14 21 28 4 11 18 25 4 11 18 25
diff --git a/usr.bin/ncal/tests/regress.se-r-3-1712-nhl.out b/usr.bin/ncal/tests/regress.se-r-3-1712-nhl.out
new file mode 100644
index 000000000000..ec508304fef8
--- /dev/null
+++ b/usr.bin/ncal/tests/regress.se-r-3-1712-nhl.out
@@ -0,0 +1,8 @@
+ January 1712 February 1712 March 1712
+Mo 1 8 15 22 29 5 12 19 26 3 10 17 24 31
+Tu 2 9 16 23 30 6 13 20 27 4 11 18 25
+We 3 10 17 24 31 7 14 21 28 5 12 19 26
+Th 4 11 18 25 1 8 15 22 29 6 13 20 27
+Fr 5 12 19 26 2 9 16 23 30 7 14 21 28
+Sa 6 13 20 27 3 10 17 24 1 8 15 22 29
+Su 7 14 21 28 4 11 18 25 2 9 16 23 30
diff --git a/usr.bin/ncal/tests/regress.se-r-jd-170003-nhl.out b/usr.bin/ncal/tests/regress.se-r-jd-170003-nhl.out
new file mode 100644
index 000000000000..3989c4a49823
--- /dev/null
+++ b/usr.bin/ncal/tests/regress.se-r-jd-170003-nhl.out
@@ -0,0 +1,8 @@
+ March 1700
+Mo 64 71 78 85
+Tu 65 72 79 86
+We 66 73 80 87
+Th 60 67 74 81 88
+Fr 61 68 75 82 89
+Sa 62 69 76 83 90
+Su 63 70 77 84
diff --git a/usr.bin/ncal/tests/regress.se-r-jd-171202-nhl.out b/usr.bin/ncal/tests/regress.se-r-jd-171202-nhl.out
new file mode 100644
index 000000000000..1efdfa24c994
--- /dev/null
+++ b/usr.bin/ncal/tests/regress.se-r-jd-171202-nhl.out
@@ -0,0 +1,8 @@
+ February 1712
+Mo 36 43 50 57
+Tu 37 44 51 58
+We 38 45 52 59
+Th 32 39 46 53 60
+Fr 33 40 47 54 61
+Sa 34 41 48 55
+Su 35 42 49 56