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
C
<lang C>#include <string.h>
- include <malloc.h>
- include <stdlib.h>
- include <stdio.h>
- include <time.h>
- define season( x ) ((x) == 0 ? "Chaos" :\
(x) == 1 ? "Discord" :\ (x) == 2 ? "Confusion" :\ (x) == 3 ? "Bureaucracy" :\ "The Aftermath")
- define date( x ) ((x)%73 == 0 ? 73 : (x)%73)
- 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(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 ddoy = date.dayOfYear; if (isLeapYear && ddoy >= 60) ddoy--;
auto sday = ddoy % 73; // season day if (sday == 5) return apostle[ddoy / 73] ~ ", in the YOLD " ~ dyear; if (sday == 50) return holiday[ddoy / 73] ~ ", in the YOLD " ~ dyear;
auto seas = seasons[ddoy / 73]; auto wday = weekday[(ddoy-1) % 5];
return format("%s, day %s of %s in the YOLD %s", wday, sday, seas, 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>
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>
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
J
<lang j>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 29 3178 1 59j1</lang>
see talk page.
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
<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>
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>
Ruby
Using *NIX's ddate. <lang ruby>puts `ddate`.to_s</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
Scala
<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