Discordian Dates in Java

Display mode

Back to Articles

The representation of dates is something that goes back many thousands of years: each tradition and religion has its own way of representing and calculating the calendar, and there is seldom an easy way to move between the calendars. Calculating a date in one calendar, given the same date in another calendar, can involve a laborious set of operations based on the phase of the moon, the orbital inclination and other such things.

The Discordian calendar

Discordianism uses a calendar inspired by the well-established Gregorian calendar, with prominence given to the number five. As opposed to twelve months, there are five seasons with a regular number of days in each season:

SeasonDays
Chaos73
Discord73
Confusion73
Bureaucracy73
The Aftermath73
Table 1: Seasons of the Discordian calendar

This results in a year of 365 days, in alignment with the Gregorian calendar; as a result, a given day in the Discordian calendar always corresponds to the same day in Gregorian.

In addition to there being five seasons, each week consists of five days: Sweetmorn, Boomtime, Pungenday, Prickle-Prickle and Setting Orange. Because the calendar is aligned to Gregorian, each Discordian year consists of 73 weeks of 5 days; because of this, each day in the calendar always has both the same day name and the same date.

In the Gregorian calendar, leap days are added in 97 out of 400 years, on a 4-yearly cycle. The same process applies in Discordianism, with St. Tib's day inserted between Chaos the 59th and 60th (February 28th and March 1st).

A final detail is that the Discordian calendar begins in 1166 BCE; years are counted in step with Gregorian since that time, and marked anno discordia, or "Years of Our Lady of Discord". A few examples of dates in both calendars follow.

Example dates in Discordian and Gregorian

Chaos 1st, 3000             = January 1st, 1834
Bureaucracy 70th, 3155      = October 16th, 1989
St. Tib's Day, 3178         = February 29th, 2012

Converting between the calendars

Because the Discordian calendar is very regular, conversion between Discordian and Gregorian dates is relatively simple. All that is required is to calculate the offsets for year, day and month.

Discordian date calculation, given year and day of year

DYear = Year + 1166

; Handle leap years
IF Year is-a-leap-year THEN
    IF Day = 59 THEN
        DSeasonday = "St. Tib's Day"
    ELSE IF Day > 59
        ; Days after Feb 29th need to be shifted up to make this
	; year into a regular 365-day year, for calculation purposes
	Day = Day - 1
    END IF
END IF

SeasonNames = ["Chaos", "Discord", "Confusion", "Bureaucracy", "The Aftermath"]
DayNames = ["Sweetmorn", "Boomtime", "Pungenday", "Prickle-Prickle", "Setting Orange"]

IF DSeasonday is-not-already-set THEN
    DSeason = SeasonNames[Day / 73]
    DWeekday = DayNames[Day MOD 5]
    DSeasonday = Day MOD 73
END IF

The above is a pseudocode sample for converting a date into Discordian, and takes account of the special case for leap years. Converting from Discordian back into Gregorian dates is similarly simple. The only complication involved is the leap-year case, where the date as reported by the Discordian calendar is one day ahead of where it would be in other years.

Gregorian day/year calculation from Discordian

Year = DYear - 1166
Day = (DSeasonNum - 1) * 73 + DSeasondayNum

IF Year is-a-leap-year THEN
    IF DSeasonday = "St. Tib's Day" THEN
        Day = 60
    ELSE IF Day >= 60
        Day = Day + 1
    END IF
END IF

Java implementation

Writing the above algorithms in Java is made very simple by the existence of java.util.Calendar, the date/calendar calculation class; in particular, the GregorianCalendar subclass allows for calculation of leap years in a quick and efficient manner. The following code implements conversions from one calendar to the other, providing a readable representation of the date in either case.

ddate.java: Discordian/Gregorian date conversion

import java.util.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class ddate
{
    private int _year, _season, _yearDay, _seasonDay, _weekDay;
    private boolean _isLeap;

    private String[] _seasonNames = {"Chaos","Discord","Confusion","Bureaucracy","The Aftermath"};
    private String[] _dayNames = {"Sweetmorn","Boomtime","Pungenday","Prickle-Prickle","Setting Orange"};

    public ddate(Date d)
    {
        GregorianCalendar gc = new GregorianCalendar();
	gc.setTime(d);

	_year = gc.get(Calendar.YEAR) + 1166;
	_yearDay = gc.get(Calendar.DAY_OF_YEAR);
	_isLeap = gc.isLeapYear(gc.get(Calendar.YEAR));

	int yd = _yearDay - 1;

	if(_isLeap && yd > 59)
	    yd--;

	_season = (yd / 73) + 1;
	_weekDay = (yd % 5) + 1;
	_seasonDay = (yd % 73) + 1;
    }

    public int getYear()          { return _year; }
    public int getSeason()        { return _season; }
    public int getYearDay()       { return _yearDay; }
    public int getSeasonDay()     { return _seasonDay; }
    public String getSeasonName() { return _seasonNames[_season-1]; }
    public String getDayName()    { return _dayNames[_yearDay-1]; }

    public String toString()
    {
        if(_isLeap && _yearDay == 59)
	{
	    return "St. Tib's Day, " + Integer.toString(_year);
	}
	else
	{
            return _dayNames[_weekDay-1] + ", " +
	           _seasonNames[_season-1] + " " +
	           Integer.toString(_seasonDay) + ", " +
	           Integer.toString(_year);
	}
    }

    public Date getTime()
    {
        GregorianCalendar gc = new GregorianCalendar();
	gc.set(Calendar.YEAR, _year - 1166);
	gc.set(Calendar.DAY_OF_YEAR, _yearDay);
	
	return gc.getTime();
    }
}

Sample usage of ddate.java

Calendar foo = new Calendar();
foo.setTime(new Date());
foo.add(Calendar.DAY, -1);

ddate bar = new ddate(foo.getTime());
System.out.println("Yesterday was " + bar.toString());

Extending the conversion

The conversion process detailed above doesn't include the ten Holy Days of the Discordian calendar: a Holy Day falls on the 5th and 50th of each season. Since these Days occur with such regularity, it poses no extra difficulty to provide an interface for this, and such an interface has been left out of the above code in the interest of brevity.

Imran Nazar <tf@imrannazar.com>, Mar 2010.