Hacker News new | ask | show | jobs
by tzs 2067 days ago
Calendars can be fun. When I realized that my HP-48SX display had enough lines and was wide enough to display a one month calendar, I wrote one.

My first try was annoyingly slow, and I determined that the problem was with the code to actually draw the calendar. Going through each day and telling it "draw this number here" was just not efficient enough.

I switched to a string based approach. Here is what it would look like in Python. This draws a cal-style calendar or a month given the day of the week of the first day of the month (Sunday == 0, Monday == 1, ...) and the number of days in the month:

  def print_cal(first_day, num_days):
    hdr_str = "Su Mo Tu We Th Fr Sa "
    cal_str = "                  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 "
    offset = 3*(6-first_day)
    cal_flat = cal_str[offset:18+3*num_days]
    cal_flat += "                     "
    print(hdr_str)
    print(cal_flat[0:21])
    print(cal_flat[21:42])
    print(cal_flat[42:63])
    print(cal_flat[63:84])
    print(cal_flat[84:105])
All the string operations were primitives in the calculator's slow interpreted language, implemented in fast assembly language, so this was very fast.

Calculating the first day and number of days for a year/month was in the slow interpreted language, but that isn't much computation so it wasn't noticeable. In Python, it would be something like this:

  def first_and_length(year, month):
    # Correction for centuries 16, 17, 18, 19
    # Repeats every 4 centuries.
    century_table = [2, 0, 5, 3]
    # Correction for each month for years that are not leap years.
    # For leap years, need to subtract 1 for January and February.
    month_table = [4, 0, 0, 3, 5, 1, 3, 6, 2, 4, 0, 2]
    month_length = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    num_days = month_length[month-1]
    first_day_on = 1
    first_day_on += century_table[(year//100)%4]
    first_day_on += year%100 + (year%100)//4
    first_day_on += month_table[month-1]
    if month <= 2 and year%4 == 0:
        if year%400 == 0 or year%100 != 0:
            first_day_on -= 1
            if month == 2: num_days += 1
    return first_day_on%7, num_days