Phyllotaxis and Fibonacci

Gormanian calendar shell utility

CAL++(1)                    BSD General Commands Manual                   CAL++(1)


NAME

    cal++ — displays The Gormanian Calendar

SYNOPSIS

    cal++ -h
    cal++ [-y] [[month] year]

DESCRIPTION

The cal++ utility displays a simple Gormanian calendar. The options are as follows:

-h      help
-y      [DEPRECATED]
Make Gormanian year match Gregorian year. This is deprecated as it causes Dave Gorman's birthday to inconveniently have different representations in the two calendars. However, the option is included for compatibility with some online calculators.

A single parameter specifies the year (1–9999) to be displayed; note the year must be fully specified: “cal++ 89” will not display a calendar for 1989. Two parameters denote the month and year; the month is either a number between 1 and 14 - where 14 represents the Intermission.  The current date is highlighed if it appears in the output.

A year starts on March 1.

SEE ALSO

cal(1)

HISTORY

The Gormanian calendar was invented by comedian Dave Gorman as a more rational alternative to the Gregorian calendar.  Years have 13 months each of which consists of 4 weeks starting at Monday and ending with Sunday.  Following the months is an Intermission day which lasts 48 hours on leap years and 24 hours - like all other days - on non-leap years.

AUTHORS

The cal++ command and manual was written by dorkscratchings.blogspot.com

BUGS

Thorough testing by me five minutes ago has found no bugs.

BSD Sept 21, 2020 BSD (Gor)


POSTSCRIPT

You can also use cal++ to convert between Gregorian and Gormanian calendars using faketime.  For example to find out what the Gormanian date of Dave Gorman's birthday:

Dave's birthday is the same date in both Gormanian and Gregorian calendars!

And if you want to install it, the code can be found below:
#!/usr/bin/env python3
#
# Prefix 'gor_' means Gormanian
# Prefix 'gre_' means Gregorian

import subprocess
import sys
from datetime import date

gor_months = ('March',     'April',    'May',       'June',
            'Quintilis', 'Sextilis', 'September', 'October',
            'November',  'December', 'January',   'February',
            'Gormanuary','Intermission')
gor_days = ('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')

# escape strings for highlighting text
hiliteON = subprocess.check_output(['tput','smso']).decode()
hiliteOFF = subprocess.check_output(['tput','rmso']).decode()
def hilite(text):
    return hiliteON + text + hiliteOFF

# Return printable string for month
def gor_month_str(month, year=None, today=None):
    idx = month - 1
    lines = []
    line = ' '.join(gor_days)
    lines.append(line)
    daynum2str = lambda k: '%2d'%k if k != today else hilite('%2d'%k)
    if idx < 13:
        for n in range(4):
            line = ' '.join(map(daynum2str, range(n*7+1,(n+1)*7+1)))
            lines.append(line)
    else:
        lines.append(daynum2str(1) + '\n\n\n\n')
    title = gor_months[idx]
    if year is not None:
        title += ' ' + str(year)
    s = (len(lines[0]) - len(title))
    line = (s//2)*' ' + title + ((s+1)//2) * ' '
    lines.insert(0,line)
    return '\n'.join(lines)

# Gorman was born 2/3/1971 in both Gregorian and Gormanian calendars,
# unless align is set in which case we opt to make the year in the
# two calendars always the same.
def gre_to_gor_date(gre_date, align=False):
    gre_mon_nyd = 1 if align else 3
    if gre_date.month >= gre_mon_nyd:
        gre_nyd = date(gre_date.year, gre_mon_nyd, 1)
        delta_days = (gre_date - gre_nyd).days
        gor_year = gre_date.year
        gor_month = 1 + delta_days//28
        gor_day = 1 + delta_days%28
    else:
        gre_nyd = date(gre_date.year-1, gre_mon_nyd, 1)
        delta_days = (gre_date - gre_nyd).days
        gor_year = gre_date.year-1
        gor_month = 1 + delta_days//28
        gor_day = 1 + delta_days%28
    if gor_month == 14 and gor_day > 1:
        assert gor_day == 2
        gor_day = 1
    return (gor_year, gor_month, gor_day)

def main():
    args = sys.argv[1:]
    gre_date = date.today()
    gor_d, gor_m, gor_y = None, None, None
    err = sys.stderr

    # Parse args
    if '-h' in args:
        print('Usage: cal++ [-hy] [[month] year]', file=err)
        print('  -h:  help', file=sys.stderr)
        print('  -y:  [deprecated] align Gormanian and Gregorian years', file=err)
        return 1

    if '-y' in args:
        args.remove('-y')
        gor_y_curr, gor_m_curr, gor_d_curr = gre_to_gor_date(gre_date, True)
    else:
        gor_y_curr, gor_m_curr, gor_d_curr = gre_to_gor_date(gre_date)

    if len(args) == 0:
        gor_y = gor_y_curr
        gor_m = gor_m_curr
    elif len(args) == 1:
        gor_y = int(args.pop(0))
    else:
        gor_m = int(args.pop(0))
        gor_y = int(args.pop(0))

    # Print calendar
    if gor_m is not None:
        if (gor_y == gor_y_curr and gor_m == gor_m_curr):
            gor_d = gor_d_curr
        print(gor_month_str(gor_m, gor_y, gor_d))
    else:
        lines = [f'                             {gor_y}']
        for i in range(1,15,3):
            months = []
            for gor_m in range(i,15)[:3]:
                today = None
                if gor_y == gor_y_curr and gor_m == gor_m_curr:
                    today = gor_d_curr
                months += [gor_month_str(gor_m, None, today).splitlines()]
            lines += ['  '.join(row) for row in zip(*months)] + ['']
        print('\n'.join(lines))
    return 0
    
if __name__ == '__main__':
    sys.exit(main())


Comments