Discordian date: Difference between revisions

From Rosetta Code
Content added Content deleted
(add Ruby)
Line 944: Line 944:
Setting Orange, The Aftermath 73, 3177
Setting Orange, The Aftermath 73, 3177
</pre>
</pre>

=={{header|Ruby}}==
<lang ruby>require 'date'

class DiscordianDate
SEASON_NAMES = ["Chaos","Discord","Confusion","Bureaucracy","The Aftermath"]
DAY_NAMES = ["Sweetmorn","Boomtime","Pungenday","Prickle-Prickle","Setting Orange"]
YEAR_OFFSET = 1166
DAYS_PER_SEASON = 73
DAYS_PER_WEEK = 5
ST_TIBS_DAY_OF_YEAR = 60

def initialize(year, month, day)
gregorian_date = Date.new(year, month, day)
@day_of_year = gregorian_date.yday

@st_tibs = false
if gregorian_date.leap?
if @day_of_year == ST_TIBS_DAY_OF_YEAR
@st_tibs = true
elsif @day_of_year > ST_TIBS_DAY_OF_YEAR
@day_of_year -= 1
end
end

@season, @day = @day_of_year.divmod(DAYS_PER_SEASON)
@year = gregorian_date.year + YEAR_OFFSET
end
attr_reader :year, :day

def season
SEASON_NAMES[@season]
end

def weekday
if @st_tibs
"St. Tib's Day"
else
DAY_NAMES[(@day_of_year - 1) % DAYS_PER_WEEK]
end
end

def to_s
%Q{#{@st_tibs ? "St. Tib's Day" : "%s, %s %d" % [weekday, season, day]}, #{year} YOLD}
end
end</lang>

Testing:
<lang ruby>[[2012, 2, 28], [2012, 2, 29], [2012, 3, 1], [2011, 10, 5]].each do |date|
dd = DiscordianDate.new(*date)
p ["%4d-%02d-%02d" % date, dd.to_s]
end</lang>
Outputs:
<pre>["2012-02-28", "Prickle-Prickle, Chaos 59, 3178 YOLD"]
["2012-02-29", "St. Tib's Day, 3178 YOLD"]
["2012-03-01", "Setting Orange, Chaos 60, 3178 YOLD"]
["2011-10-05", "Pungenday, Bureaucracy 59, 3177 YOLD"]</pre>


=={{header|Scala}}==
=={{header|Scala}}==

Revision as of 19:12, 5 October 2011

Task
Discordian date
You are encouraged to solve this task according to the task description, using any language you may know.

Convert a given date from the Gregorian calendar to the Discordian calendar.

See Also

Ada

discordian.adb: <lang Ada>with Ada.Calendar.Arithmetic; with Ada.Text_IO; procedure Discordian is

  use Ada.Calendar;
  subtype Year_Number is Integer range 3067 .. 3565;
  type Seasons is (Chaos, Discord, Confusion, Bureaucracy, The_Aftermath);
  subtype Day_Number is Integer range 1 .. 73;
  type Discordian_Date is record
     Year        : Year_Number;
     Season      : Seasons;
     Day         : Day_Number;
     Is_Tibs_Day : Boolean := False;
  end record;
  procedure Convert (From : Time; To : out Discordian_Date) is
     use Ada.Calendar.Arithmetic;
     First_Day   : Time;
     Number_Days : Day_Count;
  begin
     First_Day   := Time_Of (Year => Year (From), Month => 1, Day => 1);
     Number_Days := From - First_Day;
     To.Year        := Year (Date => From) + 1166;
     To.Is_Tibs_Day := False;
     if (To.Year - 2) mod 4 = 0 then
        if Number_Days > 59 then
           Number_Days := Number_Days - 1;
        elsif Number_Days = 59 then
           To.Is_Tibs_Day := True;
        end if;
     end if;
     To.Day := Day_Number (Number_Days mod 73 + 1);
     case Number_Days / 73 is
        when 0 => To.Season := Chaos;
        when 1 => To.Season := Discord;
        when 2 => To.Season := Confusion;
        when 3 => To.Season := Bureaucracy;
        when 4 => To.Season := The_Aftermath;
        when others => raise Constraint_Error;
     end case;
  end Convert;
  procedure Put (Item : Discordian_Date) is
  begin
     Ada.Text_IO.Put ("YOLD" & Integer'Image (Item.Year));
     if Item.Is_Tibs_Day then
        Ada.Text_IO.Put (", St. Tib's Day");
     else
        Ada.Text_IO.Put (", " & Seasons'Image (Item.Season));
        Ada.Text_IO.Put (" " & Integer'Image (Item.Day));
     end if;
     Ada.Text_IO.New_Line;
  end Put;
  Test_Day  : Time;
  Test_DDay : Discordian_Date;

begin

  Test_Day := Clock;
  Convert (From => Test_Day, To => Test_DDay);
  Put (Test_DDay);
  Test_Day := Time_Of (Year => 2012, Month => 2, Day => 28);
  Convert (From => Test_Day, To => Test_DDay);
  Put (Test_DDay);
  Test_Day := Time_Of (Year => 2012, Month => 2, Day => 29);
  Convert (From => Test_Day, To => Test_DDay);
  Put (Test_DDay);
  Test_Day := Time_Of (Year => 2012, Month => 3, Day => 1);
  Convert (From => Test_Day, To => Test_DDay);
  Put (Test_DDay);
  Test_Day := Time_Of (Year => 2010, Month => 7, Day => 22);
  Convert (From => Test_Day, To => Test_DDay);
  Put (Test_DDay);
  Test_Day := Time_Of (Year => 2012, Month => 9, Day => 2);
  Convert (From => Test_Day, To => Test_DDay);
  Put (Test_DDay);
  Test_Day := Time_Of (Year => 2012, Month => 12, Day => 31);
  Convert (From => Test_Day, To => Test_DDay);
  Put (Test_DDay);

end Discordian;</lang>

Output:

YOLD 3177, CHAOS  21
YOLD 3178, CHAOS  59
YOLD 3178, St. Tib's Day
YOLD 3178, CHAOS  60
YOLD 3176, CONFUSION  56
YOLD 3178, BUREAUCRACY  25
YOLD 3178, THE_AFTERMATH  73

AWK

<lang AWK>

  1. DDATE.AWK - Gregorian to Discordian date contributed by Dan Nielsen
  2. syntax: GAWK -f DDATE.AWK [YYYYMMDD | YYYY-MM-DD | MM-DD-YYYY | DDMMMYYYY | YYYY] ...
  3. examples:
  4. GAWK -f DDATE.AWK today
  5. GAWK -f DDATE.AWK 20110722 one date
  6. GAWK -f DDATE.AWK 20110722 20120229 two dates
  7. GAWK -f DDATE.AWK 2012 yearly calendar

BEGIN {

   split("Chaos,Discord,Confusion,Bureaucracy,The Aftermath",season_arr,",")
   split("Sweetmorn,Boomtime,Pungenday,Prickle-Prickle,Setting Orange",weekday_arr,",")
   split("Mungday,Mojoday,Syaday,Zaraday,Maladay",apostle_holyday_arr,",")
   split("Chaoflux,Discoflux,Confuflux,Bureflux,Afflux",season_holyday_arr,",")
   split("31,28,31,30,31,30,31,31,30,31,30,31",days_in_month,",") # days per month in non leap year
   split("0   31  59  90  120 151 181 212 243 273 304 334",rdt," ") # relative day table
   mmm = "JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC"
  1. 1 2 3 4 5 6 7 8 9 10 11 12
   if (ARGV[1] == "") { # use current date
     ARGV[ARGC++] = strftime("%Y%m%d") # GAWK only
   # ARGV[ARGC++] = dos_date() # any AWK
   # timetab(arr); ARGV[ARGC++] = sprintf("%04d%02d%02d",arr["YEAR"],arr["MONTH"],arr["DAY"]) # TAWK only
   }
   for (argno=1; argno<=ARGC-1; argno++) { # validate command line arguments
     print("")
     x = toupper(ARGV[argno])
     if (x ~ /^[0-9][0-9][0-9][0-9][01][0-9][0-3][0-9]$/) { # YYYYMMDD
       main(x)
     }
     else if (x ~ /^[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9]$/) { # YYYY-MM-DD
       gsub(/-/,"",x)
       main(x)
     }
     else if (x ~ /^[01][0-9]-[0-3][0-9]-[0-9][0-9][0-9][0-9]$/) { # MM-DD-YYYY
       main(substr(x,7,4) substr(x,1,2) substr(x,4,2))
     }
     else if (x ~ /^[0-3][0-9](JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)[0-9][0-9][0-9][0-9]$/) { # DDMMMYYYY
       main(sprintf("%04d%02d%02d",substr(x,6,4),int((match(mmm,substr(x,3,3))/4)+1),substr(x,1,2)))
     }
     else if (x ~ /^[0-9][0-9][0-9][0-9]$/) { # YYYY
       yearly_calendar(x)
     }
     else {
       error("begin")
     }
   }
   if (errors == 0) { exit(0) } else { exit(1) }

} function main(x, d,dyear,m,season_day,season_nbr,text,weekday_nbr,y,year_day) {

   y = substr(x,1,4) + 0
   m = substr(x,5,2) + 0
   d = substr(x,7,2) + 0
   days_in_month[2] = (leap_year(y) == 1) ? 29 : 28
   if (m < 1 || m > 12 || d < 1 || d > days_in_month[m]+0) {
     error("main")
     return
   }
   year_day = rdt[m] + d
   dyear = y + 1166 # Discordian year
   season_nbr = int((year_day - 1 ) / 73) + 1
   season_day = ((year_day - 1) % 73) + 1
   weekday_nbr = ((year_day - 1 ) % 5) + 1
   if (season_day == 5) {
     text = ", " apostle_holyday_arr[season_nbr]
   }
   else if (season_day == 50) {
     text = ", " season_holyday_arr[season_nbr]
   }
   if (leap_year(y) && m == 2 && d == 29) {
     printf("%04d-%02d-%02d is St. Tib's day, Year of Our Lady of Discord %s\n",y,m,d,dyear)
   }
   else {
     printf("%04d-%02d-%02d is %s, %s %s, Year of Our Lady of Discord %s%s\n",
     y,m,d,weekday_arr[weekday_nbr],season_arr[season_nbr],season_day,dyear,text)
   }

} function leap_year(y) { # leap year: 0=no, 1=yes

   return (y % 400 == 0 || (y % 4 == 0 && y % 100)) ? 1 : 0

} function yearly_calendar(y, d,m) {

   days_in_month[2] = (leap_year(y) == 1) ? 29 : 28
   for (m=1; m<=12; m++) {
     for (d=1; d<=days_in_month[m]; d++) {
       main(sprintf("%04d%02d%02d",y,m,d))
     }
   }

} function dos_date( cmd,x) { # under Microsoft Windows XP

   cmd = "DATE <NUL"
   cmd | getline x # The current date is: MM/DD/YYYY
   close(cmd) # close pipe
   return sprintf("%04d%02d%02d",substr(x,28,4),substr(x,22,2),substr(x,25,2))

} function error(x) {

   printf("error: argument %d is invalid, %s, in %s\n",argno,ARGV[argno],x)
   errors++

} </lang>

output:

GAWK -f DDATE.AWK
2011-08-22 is Prickle-Prickle, Bureaucracy 15, Year of Our Lady of Discord 3177

GAWK -f DDATE.AWK 20110722 20120229
2011-07-22 is Pungenday, Confusion 57, Year of Our Lady of Discord 3177
2012-02-29 is St. Tib's day, Year of Our Lady of Discord 3178

C

<lang C>#include <string.h>

  1. include <malloc.h>
  2. include <stdlib.h>
  3. include <stdio.h>
  4. include <time.h>
  1. define season( x ) ((x) == 0 ? "Chaos" :\
                   (x) == 1 ? "Discord" :\
                   (x) == 2 ? "Confusion" :\
                   (x) == 3 ? "Bureaucracy" :\
                   "The Aftermath")
  1. define date( x ) ((x)%73 == 0 ? 73 : (x)%73)
  1. define leap_year( x ) ((x) % 400 == 0 || (((x) % 4) == 0 && (x) % 100))

char * ddate( int y, int d ){

 int dyear = 1166 + y;
 char * result = malloc( 100 * sizeof( char ) );
 if( leap_year( y ) ){
   if( d == 60 ){
     sprintf( result, "St. Tib's Day, YOLD %d", dyear );
     return result;
   } else if( d >= 60 ){
     -- d;
   }
 }
 sprintf( result, "%s %d, YOLD %d", season( d/73 ), date( d ), dyear );
 return result;

}


int day_of_year( int y, int m, int d ){

 int month_lengths[ 12 ] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
 for( ; m > 1; m -- ){
   d += month_lengths[ m - 2 ];
   if( m == 3 && leap_year( y ) ){
     ++ d;
   }
 }
 return d;

}


int main( int argc, char * argv[] ){

 time_t now;
 struct tm * now_time;
 int year, doy;
 if( argc == 1 ){
   now = time( NULL );
   now_time = localtime( &now );
   year = now_time->tm_year + 1900; doy = now_time->tm_yday + 1;
 } else if( argc == 4 ){
   year = atoi( argv[ 1 ] ); doy = day_of_year( atoi( argv[ 1 ] ), atoi( argv[ 2 ] ), atoi( argv[ 3 ] ) );
 }
 
 printf( "%s\n", ddate( year, doy ) );
 return 0;

}</lang>

Demonstration:

$ ./ddate #today is Jan 7th, 2011
Chaos 7, YOLD 3177
$ ./ddate 2011 1 7
Chaos 7, YOLD 3177
$ ./ddate 2012 2 28
Chaos 59, YOLD 3178
$ ./ddate 2012 2 29
St. Tib's Day, YOLD 3178
$ ./ddate 2012 3 1
Chaos 60, YOLD 3178
$ ./ddate 2010 7 22
Confusion 57, YOLD 3176

D

<lang d>import std.stdio, std.datetime, std.conv, std.string;

immutable seasons = ["Chaos", "Discord", "Confusion", "Bureaucracy", "The Aftermath"]; immutable weekday = ["Sweetmorn", "Boomtime", "Pungenday", "Prickle-Prickle", "Setting Orange"]; immutable apostle = ["Mungday", "Mojoday", "Syaday", "Zaraday", "Maladay"]; immutable holiday = ["Chaoflux", "Discoflux", "Confuflux", "Bureflux", "Afflux"];

string discordianDate(in Date date) {

   auto dyear = to!string(date.year + 1166);
   auto isLeapYear = date.isLeapYear;
   if (isLeapYear && date.month == 2 && date.day == 29)
       return "St. Tib's Day, in the YOLD " ~ dyear;
   auto doy = date.dayOfYear;
   if (isLeapYear && doy >= 60)
       doy--;
   auto dsday = doy % 73; // season day
   if (dsday == 5)  return apostle[doy / 73] ~ ", in the YOLD " ~ dyear;
   if (dsday == 50) return holiday[doy / 73] ~ ", in the YOLD " ~ dyear;
   auto dseas = seasons[doy / 73];
   auto dwday = weekday[(doy-1) % 5];
   return format("%s, day %s of %s in the YOLD %s", dwday, dsday, dseas, dyear);

}

void main() {

   auto today = cast(Date)Clock.currTime();
   auto ddate = discordianDate(today);
   writeln(ddate);

} </lang>

<lang d>unittest {

   assert(discordianDate(Date(2010,7,22)) == "Pungenday, day 57 of Confusion in the YOLD 3176");
   assert(discordianDate(Date(2012,2,28)) == "Prickle-Prickle, day 59 of Chaos in the YOLD 3178");
   assert(discordianDate(Date(2012,2,29)) == "St. Tib's Day, in the YOLD 3178");
   assert(discordianDate(Date(2012,3, 1)) == "Setting Orange, day 60 of Chaos in the YOLD 3178");
   assert(discordianDate(Date(2010,1, 5)) == "Mungday, in the YOLD 3176");
   assert(discordianDate(Date(2011,5, 3)) == "Discoflux, in the YOLD 3177");

}</lang>

Euphoria

Translation of: D

<lang euphoria>function isLeapYear(integer year)

   return remainder(year,4)=0 and remainder(year,100)!=0 or remainder(year,400)=0

end function

constant YEAR = 1, MONTH = 2, DAY = 3, DAY_OF_YEAR = 8

constant month_lengths = {31,28,31,30,31,30,31,31,30,31,30,31} function dayOfYear(sequence Date)

   integer d
   if length(Date) = DAY_OF_YEAR then
       d = Date[DAY_OF_YEAR]
   else
       d = Date[DAY]
       for i = Date[MONTH]-1 to 1 by -1 do
           d += month_lengths[i]
           if i = 2 and isLeapYear(Date[YEAR]) then
               d += 1
           end if
       end for
   end if
   return d

end function

constant seasons = {"Chaos", "Discord", "Confusion", "Bureaucracy", "The Aftermath"} constant weekday = {"Sweetmorn", "Boomtime", "Pungenday", "Prickle-Prickle", "Setting Orange"} constant apostle = {"Mungday", "Mojoday", "Syaday", "Zaraday", "Maladay"} constant holiday = {"Chaoflux", "Discoflux", "Confuflux", "Bureflux", "Afflux"}

function discordianDate(sequence Date)

   sequence dyear, dseas, dwday
   integer  leap, doy, dsday
   dyear = sprintf("%d",Date[YEAR]+1166)
   leap = isLeapYear(Date[YEAR])
   if leap and Date[MONTH] = 2 and Date[DAY] = 29 then
       return "St. Tib's Day, in the YOLD " & dyear
   end if
   
   doy = dayOfYear(Date)
   if leap and doy >= 60 then
       doy -= 1
   end if
   
   dsday = remainder(doy,73)
   if dsday = 5 then
       return apostle[doy/73+1] & ", in the YOLD " & dyear
   elsif dsday = 50 then
       return holiday[doy/73+1] & ", in the YOLD " & dyear
   end if
   
   dseas = seasons[doy/73+1]
   dwday = weekday[remainder(doy-1,5)+1]
   
   return sprintf("%s, day %d of %s in the YOLD %s", {dwday, dsday, dseas, dyear})

end function

sequence today today = date() today[YEAR] += 1900 puts(1, discordianDate(today))</lang>

F#

<lang F#>open System

let seasons = [| "Chaos"; "Discord"; "Confusion"; "Bureaucracy"; "The Aftermath" |]

let ddate (date:DateTime) =

   let dyear = date.Year + 1166
   let leapYear = DateTime.IsLeapYear(date.Year)
   
   if leapYear && date.Month = 2 && date.Day = 29 then
       sprintf "St. Tib's Day, %i YOLD" dyear
   else
       // compensate for St. Tib's Day
       let dayOfYear = if leapYear && date.DayOfYear >= 60 then date.DayOfYear - 1 else date.DayOfYear
       let season, dday = Math.DivRem(dayOfYear, 73)
       sprintf "%s %i, %i YOLD" seasons.[season] dday dyear</lang>

Go

A package modeled after the time package in the Go standard library <lang go>package ddate

import (

   "strconv"
   "strings"
   "time"

)

// Predefined formats for DiscDate.Format const (

   DefaultFmt = "Pungenday, Discord 5, 3131 YOLD"
   OldFmt     = `Today is Pungenday, the 5th day of Discord in the YOLD 3131

Celebrate Mojoday` )

// Formats passed to DiscDate.Format are protypes for formated dates. // Format replaces occurrences of prototype elements (the constant strings // listed here) with values corresponding to the date being formatted. // If the date is St. Tib's Day, the string from the first date element // through the last is replaced with "St. Tib's Day". const (

   protoLongSeason  = "Discord"
   protoShortSeason = "Dsc"
   protoLongDay     = "Pungenday"
   protoShortDay    = "PD"
   protoOrdDay      = "5"
   protoCardDay     = "5th"
   protoHolyday     = "Mojoday"
   protoYear        = "3131"

)

var (

   longDay = []string{"Sweetmorn", "Boomtime", "Pungenday",
       "Prickle-Prickle", "Setting Orange"}
   shortDay   = []string{"SM", "BT", "PD", "PP", "SO"}
   longSeason = []string{
       "Chaos", "Discord", "Confusion", "Bureaucracy", "The Aftermath"}
   shortSeason = []string{"Chs", "Dsc", "Cfn", "Bcy", "Afm"}
   holyday     = [][]string{{"Mungday", "Chaoflux"}, {"Mojoday", "Discoflux"},
       {"Syaday", "Confuflux"}, {"Zaraday", "Bureflux"}, {"Maladay", "Afflux"}}

)

type DiscDate struct {

   StTibs bool
   Dayy   int // zero based day of year, meaningless if StTibs is true
   Year   int // gregorian + 1166

}

func New(eris *time.Time) DiscDate {

   t := *eris
   t.Month = 1
   t.Day = 1
   bob := int(eris.Seconds()-t.Seconds()) / (24 * 60 * 60)
   raw := int(eris.Year)
   hastur := DiscDate{Year: raw + 1166}
   if raw%4 == 0 && (raw%100 != 0 || raw%400 == 0) {
       if bob > 59 {
           bob--
       } else if bob == 59 {
           hastur.StTibs = true
           return hastur
       }
   }
   hastur.Dayy = bob
   return hastur

}

func (dd DiscDate) Format(f string) (r string) {

   var st, snarf string
   var dateElement bool
   f6 := func(proto, wibble string) {
       if !dateElement {
           snarf = r
           dateElement = true
       }
       if st > "" {
           r = ""
       } else {
           r += wibble
       }
       f = f[len(proto):]
   }
   f4 := func(proto, wibble string) {
       if dd.StTibs {
           st = "St. Tib's Day"
       }
       f6(proto, wibble)
   }
   season, day := dd.Dayy/73, dd.Dayy%73
   for f > "" {
       switch {
       case strings.HasPrefix(f, protoLongDay):
           f4(protoLongDay, longDay[dd.Dayy%5])
       case strings.HasPrefix(f, protoShortDay):
           f4(protoShortDay, shortDay[dd.Dayy%5])
       case strings.HasPrefix(f, protoCardDay):
           funkychickens := "th"
           if day/10 != 1 {
               switch day % 10 {
               case 0:
                   funkychickens = "st"
               case 1:
                   funkychickens = "nd"
               case 2:
                   funkychickens = "rd"
               }
           }
           f4(protoCardDay, strconv.Itoa(day+1)+funkychickens)
       case strings.HasPrefix(f, protoOrdDay):
           f4(protoOrdDay, strconv.Itoa(day+1))
       case strings.HasPrefix(f, protoLongSeason):
           f6(protoLongSeason, longSeason[season])
       case strings.HasPrefix(f, protoShortSeason):
           f6(protoShortSeason, shortSeason[season])
       case strings.HasPrefix(f, protoHolyday):
           if day == 4 {
               r += holyday[season][0]
           } else if day == 49 {
               r += holyday[season][1]
           }
           f = f[len(protoHolyday):]
       case strings.HasPrefix(f, protoYear):
           r += strconv.Itoa(dd.Year)
           f = f[4:]
       default:
           r += f[:1]
           f = f[1:]
       }
   }
   if st > "" {
       r = snarf + st + r
   }
   return

}</lang> Example program using above package <lang go>package main

import (

   "ddate"
   "fmt"
   "os"
   "strings"
   "time"

)

func main() {

   pi := 1
   fnord := ddate.DefaultFmt
   if len(os.Args) > 1 {
       switch os.Args[1][0] {
       case '+':
           pi++
           fnord = os.Args[1][1:]
       case '-':
           usage()
       }
   }
   var eris *time.Time
   switch len(os.Args) - pi {
   case 0:
       eris = time.LocalTime()
   case 3:
       var err os.Error
       eris, err = time.Parse("2 1 2006", strings.Join(os.Args[pi:pi+3], " "))
       if err != nil {
           fmt.Println(err)
           usage()
       }
   default:
       usage()
   }
   fmt.Println(ddate.New(eris).Format(fnord))

}

func usage() {

   fmt.Fprintf(os.Stderr, "usage: %s [+format] [day month year]\n", os.Args[0])
   os.Exit(1)

}</lang> Example output:

> ddate
Pungenday, Confusion 62, 3177 YOLD

> ddate 29 2 2012
St. Tib's Day, 3178 YOLD

Haskell

<lang haskell>import Data.List import Data.Time import Data.Time.Calendar.MonthDay

seasons = words "Chaos Discord Confusion Bureaucracy The_Aftermath"

discordianDate (y,m,d) = do

 let doy = monthAndDayToDayOfYear (isLeapYear y) m d
     (season, dday) = divMod doy 73
     dos = dday - fromEnum (isLeapYear y && m >2)
     dDate

| isLeapYear y && m==2 && d==29 = "St. Tib's Day, " ++ show (y+1166) ++ " YOLD" | otherwise = seasons!!season ++ " " ++ show dos ++ ", " ++ show (y+1166) ++ " YOLD"

 putStrLn dDate</lang>

Examples:

*Main> mapM_ discordianDate [(2012,2,28),(2012,2,29),(2012,3,1),(2010,9,2),(2010,12,6)]
Chaos 59, 3178 YOLD
St. Tib's Day, 3178 YOLD
Chaos 60, 3178 YOLD
Bureaucracy 26, 3176 YOLD
The_Aftermath 48, 3176 YOLD

In GHCi we can also execute shell commands.

  • Using Linux utility ddate
*Main> :! ddate
Today is Setting Orange, the 26th day of Bureaucracy in the YOLD 3176

*Main> :! ddate 29 2 2012
Sint Tibs

*Main> :! ddate 2 9 2010
Setting Orange, Bureaucracy 26, 3176 YOLD

Icon and Unicon

This version is loosely based on a modified translation of the original ddate.c and like the original the leap year functionality is Julian not Gregorian. <lang Icon>link printf

procedure main()

  Demo(2010,1,1)
  Demo(2010,7,22)
  Demo(2012,2,28)
  Demo(2012,2,29)
  Demo(2012,3,1)
  Demo(2010,1,5)
  Demo(2011,5,3)
  Demo(2012,2,28)
  Demo(2012,2,29)
  Demo(2012,3,1)
  Demo(2010,7,22)
  Demo(2012,12,22)

end

procedure Demo(y,m,d) #: demo display

  printf("%i-%i-%i = %s\n",y,m,d,DiscordianDateString(DiscordianDate(y,m,d)))

end

record DiscordianDateRecord(year,yday,season,sday,holiday)

procedure DiscordianDate(year,month,day) #: Convert normal date to Discordian static cal initial cal := [31,28,31,30,31,30,31,31,30,31,30,31]

  ddate := DiscordianDateRecord(year+1166)
  every (ddate.yday := day - 1) +:= cal[1 to month-1]   # zero origin
  ddate.sday := ddate.yday
  
  if ddate.year % 4 = 2 &  month = 2 & day = 29 then 
     ddate.holiday := 1   # Note: st tibs is outside of weekdays
  else {
     ddate.season  := (ddate.yday / 73) + 1   
     ddate.sday := (ddate.yday % 73) + 1
     ddate.holiday := 1 + ddate.season * case ddate.sday of { 5 : 1; 50 : 2}    
  }
  return ddate

end

procedure DiscordianDateString(ddate) #: format a Discordian Date String static days,seasons,holidays initial {

  days := ["Sweetmorn","Boomtime","Pungenday","Prickle-Prickle","Setting Orange"]
  seasons := ["Chaos","Discord","Confusion","Bureaucracy","The Aftermath"]
  holidays := ["St. Tib's Day","Mungday","Chaoflux","Mojoday","Discoflux",
               "Syaday","Confuflux","Zaraday","Bureflux","Maladay","Afflux"]                     
  }
  
  return (( holidays[\ddate.holiday] || "," ) |
          ( days[1+ddate.yday%5] || ", day " || 
            ddate.sday || " of " || seasons[ddate.season])) ||
         " in the YOLD " || ddate.year

end</lang>

Output:

2010-1-1 = Sweetmorn, day 1 of Chaos in the YOLD 3176
2010-7-22 = Pungenday, day 57 of Confusion in the YOLD 3176
2012-2-28 = Prickle-Prickle, day 59 of Chaos in the YOLD 3178
2012-2-29 = St. Tib's Day, in the YOLD 3178
2012-3-1 = Setting Orange, day 60 of Chaos in the YOLD 3178
2010-1-5 = Mungday, in the YOLD 3176
2011-5-3 = Discoflux, in the YOLD 3177
2012-2-28 = Prickle-Prickle, day 59 of Chaos in the YOLD 3178
2012-2-29 = St. Tib's Day, in the YOLD 3178
2012-3-1 = Setting Orange, day 60 of Chaos in the YOLD 3178
2010-7-22 = Pungenday, day 57 of Confusion in the YOLD 3176
2012-12-22 = Sweetmorn, day 64 of The Aftermath in the YOLD 3178

J

<lang j>require'dates' leap=: _1j1 * 0 -/@:= 4 100 400 |/ {.@] bs=: ((#:{.) + 0 j. *@[ * {:@]) +. disc=: ((1+0 73 bs[ +^:(58<]) -/@todayno@(,: 1 1,~{.)@]) ,~1166+{.@])~ leap</lang>

Example use:

<lang> disc 2012 2 28 3178 1 59

  disc 2012 2 29

3178 1 59j1

  disc 2012 3 1

3178 1 60j1

  disc 2012 12 31

3178 5 73j1

  disc 2013 1 1

3179 1 1</lang>

see talk page. But, in essence, this version uses season ordinals with a single imaginary day after the 59th of the first season, on leap years. This is implemented so that that imaginary day has been passed for all remaining days of a leap year.

JavaScript

<lang javascript>/**

* All Hail Discordia! - this script prints Discordian date using system date.
* author: s1w_, lang: JavaScript
*/

function print_ddate(mod) {

 var p;
 switch(mod || 0) {// <--choose display pattern or pass option by parameter
  default:
   case 0:/* Sweetmorn, Day 57 of the Season of Confusion, Anno Mung 3177 */ p="{0}, [Day {1} of the Season of {2}], Anno Mung {3}"; break;
   case 1:/* Sweetmorn, The 57th Day of Confusion, 3177 YOLD              */ p="{0}, [The {1}th Day of {2}], {3} YOLD";              break;
   case 2:/* Sweetmorn, the 57th day of Confusion, AM 3177                */ p="{0}, [the {1}th day of {2}], AM {3}";                break;
   case 3:/* Sweetmorn / Confusion 57th / AM 3177                         */ p="{0} / [{2} {1}th] / AM {3}";                         break;
 }
 var ddateStr, curr, sum, extra, today, day, month, year, dSeason, dDay, season, ddate, dyear;
 format = function(s, $1, $2, $3, $4) {
   if ($2 != undefined) {
     var postfix;
     switch(parseInt($2.charAt($2.length-1))) {
       case 1: postfix = '}st'; break;
       case 2: postfix = '}nd'; break;
       case 3: postfix = '}rd'; break;
       default:postfix = '}th';
     }
     return p.replace(/\}th/, postfix).replace(/(\[|\])/g, ).format($1, $2, $3, $4);
   }
   else return p.replace(/\[.*?\]/,"{2}").format($1, $2, $3, $4);
 }
 
 String.prototype.format = function() {
   var pattern = /\{\d+\}/g;
   var args = arguments;
   return this.replace(pattern, function(capture){ return args[capture.match(/\d+/)]; });
 }
 dDay = new Array("Sweetmorn", "Boomtime", "Pungenday", "Prickle-Prickle", "Setting Orange");
 dSeason = new Array("Chaos", "Discord", "Confusion", "Bureaucracy", "Aftermath");
 curr = new Date(); extra = new Array(0,3,0,3,2,3,2,3,3,2,3,2);
 today = curr.getDate(); month = curr.getMonth(); year = curr.getFullYear();
 sum = month * 28;
 for(var i=0; i<=month; i++)
   sum += extra[i];
 sum += today;
 day = (sum - 1) % 5; ddate = sum % 73;
 season = (month==1)&&(today==29) ? "St. Tib\'s Day" : dSeason[Math.floor(sum/73)];
 dyear = year+1166;
 ddateStr = ""+dDay[day]+ddate+season+dyear;
 document.write(ddateStr.replace(/(\D+)(?:(\d+)(?!St)|(?:\d+))(\D+)(\d+)/i, format));

}</lang>

Example use:

<lang javascript>print_ddate() "Sweetmorn, Day 57 of the Season of Confusion, Anno Mung 3177" print_ddate(1) "Sweetmorn, The 57th Day of Confusion, 3177 YOLD" print_ddate(2) "Sweetmorn, the 57th day of Confusion, AM 3177" print_ddate(3) "Sweetmorn / Confusion 57th / AM 3177" </lang>

look at calendar; lern about holydays

Perl 6

<lang perl6>my @seasons = < Chaos Discord Confusion Bureaucracy >, 'The Aftermath'; my @days = < Sweetmorn Boomtime Pungenday Prickle-Prickle >, 'Setting Orange'; sub ordinal ( Int $n ) { $n ~ ( $n % 100 == 11|12|13

   ?? 'th' !! < th st nd rd th th th th th th >[$n % 10] ) }

sub ddate ( Str $ymd ) {

   my $d = DateTime.new: "{$ymd}T00:00:00Z" or die;
   my $yold = 'in the YOLD ' ~ $d.year + 1166;
   my $day_of_year0 = $d.day-of-year - 1;
   if $d.is-leap-year {
       return "St. Tib's Day, $yold" if $d.month == 2 and $d.day == 29;
       $day_of_year0-- if $day_of_year0 >= 60; # Compensate for St. Tib's Day
   }
   my $weekday    = @days[    $day_of_year0 mod  5     ];
   my $season     = @seasons[ $day_of_year0 div 73     ];
   my $season_day = ordinal(  $day_of_year0 mod 73 + 1 );
   return "$weekday, the $season_day day of $season $yold";

}

say "$_ is {.&ddate}" for < 2010-07-22 2012-02-28 2012-02-29 2012-03-01 >; </lang>

Output:

2010-07-22 is Pungenday, the 57th day of Confusion in the YOLD 3176
2012-02-28 is Prickle-Prickle, the 59th day of Chaos in the YOLD 3178
2012-02-29 is St. Tib's Day, in the YOLD 3178
2012-03-01 is Setting Orange, the 60th day of Chaos in the YOLD 3178

PicoLisp

Translation of: Python

<lang PicoLisp>(de disdate (Year Month Day)

  (let? Date (date Year Month Day)
     (let (Leap (date Year 2 29)  D (- Date (date Year 1 1)))
        (if (and Leap (= 2 Month) (= 29 Day))
           (pack "St. Tib's Day, YOLD " (+ Year 1166))
           (and Leap (>= D 60) (dec 'D))
           (pack
              (get
                 '("Chaos" "Discord" "Confusion" "Bureaucracy" "The Aftermath")
                 (inc (/ D 73)) )
              " "
              (inc (% D 73))
              ", YOLD "
              (+ Year 1166) ) ) ) ) )</lang>

Pike

Pike includes a Discordian calendar. dates can be converted from any calendar to any other. <lang Pike> > Calendar.Discordian.now()->format_ext_ymd();

Result: "Pungenday, 59 Bureaucracy 3177"

> Calendar.Discordian.Day(Calendar.Day(2011,11,11))->format_ext_ymd();

Result: "Setting Orange, 23 The Aftermath 3177"

> Calendar.Discordian.Day(Calendar.Badi.Day(168,13,9))->format_ext_ymd();

Result: "Setting Orange, 23 The Aftermath 3177"

> Calendar.Day((Calendar.Discordian.Month()+1)->day(1));

Result: Day(Thu 20 Oct 2011)

</lang>

PureBasic

<lang PureBasic>Procedure.s Discordian_Date(Y, M, D)

 Protected DoY=DayOfYear(Date(Y,M,D,0,0,0)), Yold$=Str(Y+1166)
 Dim S.s(4)
 S(0)="Chaos": S(1)="Discord": S(2)="Confusion": S(3)="Bureaucracy"
 S(4)="The Aftermath"
 If (Y%4=0 And Y%100) Or Y%400=0
   If M=2 And D=29
     ProcedureReturn "St. Tib's Day, YOLD " + Yold$
   ElseIf DoY>=2*30
     DoY-1
   EndIf
 EndIf
 ProcedureReturn S(DoY/73)+" "+Str(DoY%73)+", Yold "+Yold$

EndProcedure</lang>

Python

<lang python>import datetime, calendar

DISCORDIAN_SEASONS = ["Chaos", "Discord", "Confusion", "Bureaucracy", "The Aftermath"]

def ddate(year, month, day):

   today = datetime.date(year, month, day)
   is_leap_year = calendar.isleap(year)
   if is_leap_year and month == 2 and day == 29:
       return "St. Tib's Day, YOLD " + (year + 1166)
   
   day_of_year = today.timetuple().tm_yday - 1
   
   if is_leap_year and day_of_year >= 60:
       day_of_year -= 1 # Compensate for St. Tib's Day
   
   season, dday = divmod(day_of_year, 73)
   return "%s %d, YOLD %d" % (DISCORDIAN_SEASONS[season], dday + 1, year + 1166)

</lang>

REXX

<lang rexx> /*REXX program converts mm/dd/yyyy Gregorian date ───> Discordian date. */ /*Gregorian date may be m/d/yy ──or── m/d format. */

day.1='Sweetness' /*define 1st day-of-Discordian-week.*/ day.2='Boomtime' /*define 2nd day-of-Discordian-week.*/ day.3='Pungenday' /*define 3rd day-of-Discordian-week.*/ day.4='Prickle-Prickle' /*define 4th day-of-Discordian-week.*/ day.5='Setting Orange' /*define 5th day-of-Discordian-week.*/

seas.0="St. Tib's day," /*define the leap-day of Discordian yr.*/ seas.1='Chaos' /*define 1st season-of-Discordian-year.*/ seas.2='Discord' /*define 2nd season-of-Discordian-year.*/ seas.3='Confusion' /*define 3rd season-of-Discordian-year.*/ seas.4='Bureaucracy' /*define 4th season-of-Discordian-year.*/ seas.5='The Aftermath' /*define 5th season-of-Discordian-year.*/

parse arg gM '/' gD "/" gY . /*get the date specified. */ gY=left(right(date(),4),4-length(Gy))gY /*adjust for a 2-dig yr or none*/

                                      /*below:get day-of-year,adj LeapY*/

doy=date('d',gY||right(gM,2,0)right(gD,2,0),"s")-(leapyear(gY) & gM>2) dW=doy//5;if dW==0 then dW=5 /*compute the Discordian weekday.*/ dS=(doy-1)%73+1 /*compute the Discordian season. */ dD=doy//73;if dD==0 then dD=73; dD=dD',' /*Discordian day-of-month.*/ if leapyear(gY) & gM==02 & gD==29 then do; dD=; ds=0; end /*St. Tib's?*/ say space(day.dW',' seas.dS dD gY+1166) /*show and tell Discordian date*/ exit

/*─────────────────────────────────────LEAPYEAR subroutine──────────────*/ leapyear: procedure; arg y if y//4\==0 then return 0 /* not ≈ by 4? Not a leapyear.*/ return y//100\==0 | y//400==0 /*apply 100 and 400 year rule. */ </lang> Output when using the inputs of:

2/28/2012
2/29/2012
3/1/2012
7/22/2010
9/2/2012
12/31/2011

Prickle-Prickle, Chaos 59, 3178
Setting Orange, St. Tib's day, 3178
Setting Orange, Chaos 60, 3178
Pungenday, Confusion 57, 3176
Setting Orange, Bureaucracy 26, 3178
Setting Orange, The Aftermath 73, 3177

Ruby

<lang ruby>require 'date'

class DiscordianDate

 SEASON_NAMES = ["Chaos","Discord","Confusion","Bureaucracy","The Aftermath"]
 DAY_NAMES = ["Sweetmorn","Boomtime","Pungenday","Prickle-Prickle","Setting Orange"]
 YEAR_OFFSET = 1166
 DAYS_PER_SEASON = 73
 DAYS_PER_WEEK = 5
 ST_TIBS_DAY_OF_YEAR = 60
 def initialize(year, month, day)
   gregorian_date = Date.new(year, month, day)
   @day_of_year = gregorian_date.yday
   @st_tibs = false
   if gregorian_date.leap?
     if @day_of_year == ST_TIBS_DAY_OF_YEAR
       @st_tibs = true
     elsif @day_of_year > ST_TIBS_DAY_OF_YEAR
       @day_of_year -= 1
     end
   end
   @season, @day = @day_of_year.divmod(DAYS_PER_SEASON)
   @year = gregorian_date.year + YEAR_OFFSET
 end
 attr_reader :year, :day
 def season
   SEASON_NAMES[@season]
 end
 def weekday
   if @st_tibs
     "St. Tib's Day"
   else
     DAY_NAMES[(@day_of_year - 1) % DAYS_PER_WEEK]
   end
 end
 def to_s
   %Q{#{@st_tibs ? "St. Tib's Day" : "%s, %s %d" % [weekday, season, day]}, #{year} YOLD}
 end

end</lang>

Testing: <lang ruby>[[2012, 2, 28], [2012, 2, 29], [2012, 3, 1], [2011, 10, 5]].each do |date|

 dd = DiscordianDate.new(*date)
 p ["%4d-%02d-%02d" % date, dd.to_s]

end</lang> Outputs:

["2012-02-28", "Prickle-Prickle, Chaos 59, 3178 YOLD"]
["2012-02-29", "St. Tib's Day, 3178 YOLD"]
["2012-03-01", "Setting Orange, Chaos 60, 3178 YOLD"]
["2011-10-05", "Pungenday, Bureaucracy 59, 3177 YOLD"]

Scala

Translation of: Python

<lang scala>import java.util.{GregorianCalendar, Calendar}

val DISCORDIAN_SEASONS=Array("Chaos", "Discord", "Confusion", "Bureaucracy", "The Aftermath") def ddate(year:Int, month:Int, day:Int):String={

  val date=new GregorianCalendar(year, month-1, day)
  val dyear=year+1166
  val isLeapYear=date.isLeapYear(year)
  if(isLeapYear && month==2 && day==29)
     return "St. Tib's Day "+dyear+" YOLD"
  var dayOfYear=date.get(Calendar.DAY_OF_YEAR)
  if(isLeapYear && dayOfYear>=60)
     dayOfYear-=1	// compensate for St. Tib's Day
  val dday=dayOfYear%73
  val season=dayOfYear/73
  "%s %d, %d YOLD".format(DISCORDIAN_SEASONS(season), dday, dyear)

}</lang>

Tcl

<lang tcl>package require Tcl 8.5 proc disdate {year month day} {

   # Get the day of the year
   set now [clock scan [format %02d-%02d-%04d $day $month $year] -format %d-%m-%Y]
   scan [clock format $now -format %j] %d doy
   # Handle leap years
   if {!($year%4) && (($year%100) || !($year%400))} {

if {$doy == 60} { return "St. Tib's Day, [expr {$year + 1166}] YOLD" } elseif {$doy > 60} { incr doy -1 }

   }
   # Main conversion to discordian format now that special cases are handled
   incr doy -1; # Allow div/mod to work right
   set season [lindex {Chaos Discord Confusion Bureaucracy {The Aftermath}} \

[expr {$doy / 73}]]

   set dos [expr {$doy % 73 + 1}]
   incr year 1166
   return "$season $dos, $year YOLD"

}</lang> Demonstrating: <lang tcl>puts [disdate 2010 7 22]; # Today puts [disdate 2012 2 28] puts [disdate 2012 2 29] puts [disdate 2012 3 1]</lang> Output:

Confusion 57, 3176 YOLD
Chaos 59, 3178 YOLD
St. Tib's Day, 3178 YOLD
Chaos 60, 3178 YOLD