As a part of my general interest in time management, I wanted to take a look into the default calendar on UNIX and Linux systems. Its name is CALENDAR, which is a reminder service, that is used on the console. It basically reads one or more calendars and lists events, that fall into the specified date range.
What is CALENDAR?
CALENDAR is a reminder service, that is installed by default on FreeBSD, UNIX and Linux operating systems. CALENDAR offers simple, versatile, effective and secure time management for systems administrators and users. CALENDAR is based on text files, which makes it easy to update, synchronize and backup. The UNIX calendar reminder service is highly fleksible and easy to combine with other default UNIX utilities. You might even find it to be superior to modern calendars.
$ calendar
Aug 20 Weather forecast says 11-17 °C 💧
Aug 20* Daily coffee meeting with David Lightman at 15:00
Aug 20 Patch WOPR mainframe in data center
Aug 20 Simulate first-strike on WOPR
Aug 20 Change password for listing games on WOPR
Calendar files
The CALENDAR reminder service uses one or more calendar files. Much like the good old days, when you would have one or more calendars. You might have a private one for personal events, one for recurring birthdays, a shared one for family events and a shared one for project events. Each calendar can hold tasks, recurring events.
By default, CALENDAR will search for a calendar file in the user home. If that is not found, then it will look for a calendar file in the hidden dot calendar directory and the following shared directories. The default name for a calendar is “calendar”.
~
~/.calendar
/usr/local/share/calendar
/usr/share/calendar
Creating calendar files
I recommend, that the hidden calendar directory is used. This will protect your calendars from accidental deletion. In this example, a set of calendars are created.
$ mkdir -m 700 -p ~/.calendar
$ touch ~/.calendar/calendar
$ touch ~/.calendar/calendar.archived
$ touch ~/.calendar/calendar.recurring
$ touch ~/.calendar/calendar.weather
$ chmod 600 ~/.calendar/*
Calendar file syntax and format
The calendar file format is text based and consist of a list of dates and description. These are separated by a tab. Other calendars can be included.
$ nano -T 12 ~/calendar/calendar
#include <calender.archived>
#include <calender.recurring>
#include <calendar.freebsd>
#include <calendar.weather>
10/2 2nd day of October
2025/9/15 15th day of September 2025
Thursday Every Thursday
15 * Every 15th day
July Every 1st day of July
04/TueLast Every last Tuesday in April
Fri+1 Every 1st Friday of every month
Using CALENDAR
If you want to see todays calendar events, then run CALENDAR without any arguments. CALENDAR will read the calendar, and any included calendars, and output todays events. You might want to format the date to your local preference in the shell configuration or on the command line.
$ calendar
Aug 20* Daily coffee meeting with David Lightman at 15:00
Aug 21 Patch WOPR mainframe in data center
By default, next day or weekend will also be listed. This is to avoid overlooking a post midnight event. This feature can be disabled.
$ calendar -W 0
Aug 20* Daily coffee meeting with David Lightman at 15:00
If you use a wrapper script or shell alias, you might want to show time and date along with the events.
$ date "+%H:%M %A %d %B %Y"; calendar -W 0
13:37 Wednesday 20 August 2025
Aug 20* Daily coffee meeting with David Lightman at 15:00
Format output to program
Because the calendar outputs plain text to the console, you can pipe the output through formatting utilities. In this example, the first columns are removed and the events are sorted. This can be used, if your events has a leading time and you want a program for the day. Events with no time will be listed as all-day events below the program.
$ cat .calendar/calendar
Aug 20 09:00 Meeting with management
Aug 20 10:00 Upgrade chess game on WOPR
Aug 20 12:00 Lunch with Lightman
$ calendar -W 0 | cut -c9- | sort
09:00 Meeting with management
10:00 Upgrade chess game on WOPR
12:00 Lunch with Lightman
List events for specific date
In this example, the events for a specific date is listed.
$ calendar -W 0 -t 21.08.2025
Aug 21* Daily coffee meeting with David Lightman at 15:00
Aug 21 Test Tic-Tac-Toe game on WOPR
If you want to list the events for a date, that is an amount of days away from todays date, you can use the DATE utility for relative argument. In this example, the events for tomorrow are listed.
$ calendar -W 0 -t $(date -v+1d +%d.%m.%Y)
Thursday 21 August 2025
If you use a wrapper script or shell alias, you might want to show date along with the events.
$ date -v+1d "+%A %d %B %Y"; calendar -W 0 -t $(date -v+1d +%d.%m.%Y)
Thursday 21 August 2025
Aug 21* Daily coffee meeting with David Lightman at 15:00
Aug 21 Test Tic-Tac-Toe game on WOPR
List events for date range
If you want to see all events, that is planned days ahead in time, or happened days back in time, you can use the ahead argument -A and back argument -B. They can be also combined for a date range.
$ calendar -B 1 -A 3
Aug 20* Daily coffee meeting with David Lightman at 15:00
Aug 21* Daily coffee meeting with David Lightman at 15:00
Aug 21 Test Tic-Tac-Toe game on WOPR
Aug 22 Patch WOPR mainframe in data center
Search for past and future events
In this example, the output will be past operations on WOPR in the past 90 days.
$ calendar -B 90 | grep WOPR
Jan 1 Confirm time on WOPR
Aug 19 Change password for Lightman on WOPR
Aug 21 Test Tic-Tac-Toe game on WOPR
In this example, the output will be planned operations on WOPR in the next 3 days.
$ calendar -A 3 | grep WOPR
Dec 1 Evaluate simulation of run-away situation on WOPR
Documentation for CALENDAR
The manual is very well written.
$ man calendar
Default system calendars
On FreeBSD, UNIX and Linux operaing systems, there can be default system calendars, which are included by default or can be included manually. FreeBSD offers a a calendar with birthdays of FreeBSD contributers. Ubuntu offers several calendars, such as historic events.
$ ls /usr/share/calendar/calendar* $ grep Percival /usr/share/calendar/calendar.freebsd 02/24 Colin Percival <> born in Burnaby, Canada, 1981
Todays events at login
If you would like, that each user gets todays events at the login console, then configure it in the global shell configuration. In this example, the SH is configured.
# nano /etc/profile
events=$(calendar -W 0 2> /dev/null)
if [ -n "$events" ]; then
echo "$events"
fi
Todays events via email
If you want an automatic daily email with todays events, you can configure CRON to do this. In the following example, CRON on a FreeBSD server is configured to automatically send todays events to each system user.
# nano /etc/crontab
0 8 * * * root LC_TIME=C /usr/bin/calendar -a
Todays weather forecast in calendar
If you want to include todays weather forecast, for today and the next days, you can use an online service, that generate ICS calendar files and convert them to CALENDAR format.
In this example, a special URL to the weather forecast was generated on the brilliant website of Meteomatics, which is a free service. The weather forecast comes as a file in ICS format. This file contains the weather forecast for each day through 15 days. Python is used to convert it to CALENDAR format and saved as an optional calender, that local users can include in their calendars.
# nano ~/bin/meteomatics
#!/usr/bin/env python3.11
from icalendar import Calendar
from datetime import datetime
import re
with open("/tmp/meteomat.ics", "rb") as f:
cal = Calendar.from_ical(f.read())
for component in cal.walk("vevent"):
dtstart = component.decoded("dtstart")
if isinstance(dtstart, datetime):
dt = dtstart.date()
else:
dt = dtstart
desc = component.get("description")
if not desc:
continue
temps = [int(x) for x in re.findall(r"([-]?\d+)°C", desc)]
if not temps:
continue
tmin, tmax = min(temps), max(temps)
rain = "💧" if "💧" in desc else ""
print(f"{dt.month}/{dt.day}\tWeather forecast says {tmin}-{tmax} °C {rain}")
CRON is used to update the weather forecast calendar automatically. In this example, it happens daily at 13:37.
# nano /etc/crontab
37 13 * * * root fetch -o /tmp/meteomat.ics "https://ical.meteomatics.com/calendar/Knippelsbro%202%2C%201409%20K%C3%B8benhavn%20K%2C%20Denmark/55.674679_12.587408/en/meteomat.ics" && /root/bin/meteomatics > /usr/share/calendar/calendar.weather
Synchronizing CALENDAR with Unison
The calendar can be synchronized between devices and systems with a synchronization utility, such as RSYNC or Unison.
In the following example, Unison is installed and configured for synchronizing the calender via SSH to a remote UNIX system, that also has Unison installed.
# pkg install unison-nox11
$ nano .unison/calendar.prf
$ cat .unison/calendar.prf
root = /home/lightman/.calendar
root = ssh://lightman@wopr//home/lightman/.calendar
batch = true
$ unison calendar
The options prefer, auto and batch are used, so conflicts are solved automatically. An example of a conflict could be, that local and remote calendars were changed. Unison can not merge changes.
$ man unison
unison – a multi-platform bi-directional file synchronization tool
unison profilename [options]
batch When this is set to true, the user interface will ask no
questions at all. Non-conflicting changes will be propagated;
conflicts will be skipped.
root xxx
Each use of this preference names the root of one of the replicas
for Unison to synchronize. Exactly two roots are needed, so
normal modes of usage are either to give two values for root in
the profile, or to give no values in the profile and provide two
on the command line. Details of the syntax of roots can be found
in Section “Roots” in the manual. The two roots can be given in
either order; Unison will sort them into a canonical order before
doing anything else. It also tries to `canonize' the machine
names and paths that appear in the roots, so that, if Unison is
invoked later with a slightly different name for the same root,
it will be able to locate the correct archives.
Send CALENDAR to devices with SCP
In the following example, the events for the next 21 days are sent via SCP to a remote device, such as an SSH server on port 1337 on an Android phone, and stored as a text file. The directory on the remote device is the default, which can be configured on the SSH server on the remote device.
$ ssh-copy-id -s lightman@android
$ calendar -W 21 > ~/.calendar/calendar.txt
$ scp -P 1337 ~/.calendar/calendar.txt lightman@android:


















