File Coverage

blib/lib/Date/Discordian.pm
Criterion Covered Total %
statement 77 91 84.6
branch 17 24 70.8
condition 2 3 66.6
subroutine 14 15 93.3
pod 1 9 11.1
total 111 142 78.1


line stmt bran cond sub pod time code
1             #$Header: /home/cvs/date-discordian/lib/Date/Discordian.pm,v 1.36 2003/06/08 01:54:03 rbowen Exp $
2             package Date::Discordian;
3 6     6   146449 use strict;
  6         19  
  6         339  
4 6     6   31 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK @SEASONS @DAYS @HOLYDAYS);
  6         11  
  6         667  
5             require Exporter;
6 6     6   9587 use Time::Local;
  6         11552  
  6         354  
7 6     6   4901 use Date::Leapyear qw();
  6         1483  
  6         105  
8 6     6   5845 use Date::ICal;
  6         88682  
  6         203  
9 6     6   6380 use Memoize;
  6         18370  
  6         9001  
10              
11             @ISA = qw(Exporter Date::ICal);
12             @EXPORT = qw( discordian inverse_discordian );
13             @EXPORT_OK = qw( @SEASONS @DAYS );
14             $VERSION = (qw'$Revision: 1.36 $')[1];
15              
16             @SEASONS = qw(Chaos Discord Confusion Bureaucracy Aftermath);
17             @DAYS =
18             ( 'Sweetmorn', 'Boomtime', 'Pungenday', 'Prickle Prickle', 'Setting Orange' );
19              
20             @HOLYDAYS = (
21             [ 'Mungoday', 'Chaoflux' ], [ 'Mojoday', 'Discoflux' ],
22             [ 'Syaday', 'Confuflux' ], [ 'Zaraday', 'Bureflux' ],
23             [ 'Maladay', 'Afflux' ],
24             );
25              
26             # sub new {{{
27              
28             sub new { # There is nothing new under the sun.
29 17     17 1 83 my $class = shift;
30 17         59 my %args = @_;
31 17         25 my $self;
32              
33 17 100       52 $args{discordian} = $args{disco} if defined $args{disco};
34 17 50       41 $args{epoch} = $args{EPOCH} if defined $args{EPOCH};
35              
36             # Discordian date?
37 17 100       39 if ( $args{discordian} ) {
38              
39 1         5 $self = $class->SUPER::new(
40             epoch => from_discordian( $args{discordian} ) );
41             } else {
42              
43 16         99 $self = $class->SUPER::new(%args);
44             }
45              
46 17         1248 bless $self, $class;
47 17         54 return $self;
48             } #}}}
49              
50             # sub discordian {{{
51              
52             sub discordian { # Not to be confused with sub genius.
53 22 100   22 0 191 if ( ref $_[0] ) {
54 17         25 my $self = shift;
55 17         56 my $d = discohash( $self->year, $self->month, $self->day );
56 17         249 return $d->{disco};
57             } else {
58 5         17 return to_discordian( $_[0] );
59             }
60             # Fnord!
61             } #}}}
62              
63             # sub to_discordian {{{
64              
65             sub to_discordian { # Be careful. It's hard to get back.
66 5     5 0 7 my $datetime = shift;
67 5 100       15 $datetime = time unless defined $datetime;
68 5         26 my $d = Date::ICal->new( epoch => $datetime );
69              
70 5         193 my $discohash = discohash( $d->year, $d->month, $d->day );
71 5         190 return $discohash->{disco};
72             }
73              
74             memoize('discohash');
75             sub discohash { # Is that something you smoke at a disco?
76             my ( $year, $month, $d ) = @_;
77              
78             # my $datetime = shift;
79             my ( $season, $day, $dow, $yold, $holyday, $datestring );
80              
81             my $yday = Date::ICal::days_this_year( $d, $month, $year ) + 1;
82              
83             # It *says* it's an internal method, but I'm not buying it.
84              
85             if ( Date::Leapyear::isleap($year) ) {
86             if ( $yday <= 59 ) {
87              
88             # nothing changes
89             } elsif ( $yday == 60 )
90             {
91              
92             # leap day!
93             $datestring = "St. Tibb's Day";
94             } else {
95              
96             # The rest of the year after leap day
97             $yday--;
98             }
99             } # End leap year stuff
100              
101             $season = int( ( $yday - 1 ) / 73 );
102             $day = ( $yday % 73 ) || 73;
103             $dow = $yday % 5;
104             $yold = $year + 1166;
105              
106             if ( $day == 5 ) { $holyday = $HOLYDAYS[$season][0]; }
107             elsif ( $day == 50 ) { $holyday = $HOLYDAYS[$season][1]; }
108             else { $holyday = undef; }
109              
110             unless ($datestring) {
111             if ($holyday) {
112             $datestring =
113             $DAYS[ $dow - 1 ] . ' (' . $holyday . '), ' . $SEASONS[$season]
114             . ' ' . $day;
115             } else {
116             $datestring =
117             $DAYS[ $dow - 1 ] . ', ' . $SEASONS[$season] . ' ' . $day;
118             }
119             }
120              
121             $datestring .= " YOLD $yold";
122              
123             my $discohash = {
124             disco => $datestring,
125             season => $SEASONS[$season],
126             yold => $yold,
127             holyday => $holyday,
128             seasonday => $day,
129             discoday => $DAYS[ $dow - 1 ],
130             };
131              
132             return $discohash;
133             } #}}}
134              
135             # sub inverse_discordian {{{
136              
137             sub inverse_discordian { # Sounds like a wrestling hold.
138 4 50   4 0 15 if ( ref $_[0] ) {
139 0         0 my $self = shift;
140 0         0 return $self->epoch;
141             } else {
142 4         12 return from_discordian( $_[0] );
143             }
144             } #}}}
145              
146             # sub from_discordian {{{
147              
148             sub from_discordian { # You only think it's possible.
149 5     5 0 10 my $discordian = shift;
150 5         5 my $epoch;
151              
152 5         10 for ($discordian) {
153              
154             # The day does not really matter ...
155 5         54 s/sweetmorn|boomtime|setting orange|prickle prickle|pungenday//i;
156 5         19 s/,//g;
157 5         19 s/YOLD//i;
158 5         27 s/\s+/ /g;
159 5         12 s/\(.*?\)//; # Holydays
160 5         20 s/^\s+//;
161             }
162              
163             # Special case - St. Tibb's Day
164 5 100       19 if ( $discordian =~ /st\.? tibb'?s day/i ) {
165 1         3 $discordian =~ m/(\d{4})/;
166 1         3 my $year = $1;
167 1         3 $year -= 1166;
168 1         3 $epoch = timegm( 0, 0, 0, 29, 1, $year );
169             } else {
170              
171             # With any luck, we now have "season day year"
172 4         18 my ( $season, $day, $year ) = split / /, $discordian;
173 4         11 $year -= 1166;
174 4         9 $season = lc($season);
175 4         19 my %seasons = (
176             chaos => 0,
177             discord => 1,
178             confusion => 2,
179             bureaucracy => 3,
180             aftermath => 4
181             );
182 4         13 my $doy = $seasons{$season} * 73 + $day;
183 4 100 66     21 $doy++ if ( $doy >= 60 && Date::Leapyear::isleap($year) );
184 4         26 $epoch = ( $doy - 1 ) * 86400 + timegm( 0, 0, 0, 1, 0, $year );
185             }
186              
187 5         175 return $epoch;
188             } #}}}
189              
190             # sub season {{{
191              
192             sub season { # For everything, there is a season.
193 2     2 0 4 my $d = shift;
194 2         3 my $h;
195              
196 2 50       6 if ( ref $d ) {
197 2         8 $h = discohash( $d->year, $d->month, $d->day );
198             } else {
199 0         0 $h = to_discordian($d);
200             }
201 2         179 return $h->{season}; # turn, turn, turn
202             } #}}}
203              
204             # sub discoday {{{
205              
206             sub discoday { # Stayin' alive
207 2     2 0 1062 my $d = shift;
208 2         3 my $h;
209              
210 2 50       6 if ( ref $d ) {
211 2         26 $h = discohash( $d->year, $d->month, $d->day );
212 2         105 return $h->{discoday};
213             } else {
214 0         0 $h = to_discordian($d);
215 0         0 return $h->{discoday};
216             }
217             } # }}}
218              
219             # sub yold {{{
220              
221             sub yold {
222              
223             # Some folks say the epoch begins in 4000 BC. This is heresy. Spurn
224             # these people. Or at least make strange chicken noises at them.
225              
226 2     2 0 5 my $d = shift;
227 2         4 my $h;
228              
229 2 50       8 if ( ref $d ) {
230 2         6 $h = discohash( $d->year, $d->month, $d->day );
231 2         178 return $h->{yold};
232             } else {
233 0           $h = to_discordian($d);
234 0           return $h->{yold};
235             }
236             } #}}}
237              
238             # sub holyday {{{
239              
240             sub holyday { # Eat a hot dog
241 0     0 0   my $d = shift;
242 0           my $h;
243              
244 0 0         if ( ref $d ) {
245 0           $h = discohash( $d->year, $d->month, $d->day );
246 0           return $h->{holyday};
247             } else {
248 0           $h = to_discordian($d);
249 0           return $h->{holyday};
250             }
251             } #}}}
252              
253             'Hail Eris!';
254              
255             # Docs {{{
256              
257             =head1 NAME
258              
259             Date::Discordian - Calculate the Discordian date of a particular day
260              
261             =head1 SYNOPSIS
262              
263             use Date::Discordian;
264             $discordian = discordian(time);
265             $epochtime = inverse_discordian('bureaucracy 47, 3166');
266              
267             Or, the OO interface ...
268              
269             use Date::Discordian;
270             my $disco = Date::Discordian->new( epoch => time );
271             $discordian = $disco->discordian;
272              
273             my $date = Date::Discordian->new(
274             discordian => 'bureaucracy 47, 3166');
275             $epoch = $date->epoch;
276             $ical = $date->ical;
277             $discordian = $date->discordian;
278              
279             $season = $date->season;
280             $discoday = $date->discoday; # eg 'Pungenday'
281             $yold = $date->yold;
282             $holyday = $date->holyday;
283              
284             Or, for dates outside of the epoch:
285              
286             my $disco = Date::Discordian->new( ical => '17760704Z' );
287             $discordian = $disco->discordian;
288              
289             Note that a Date::Discordian object ISA Date::ICal object, so see the
290             docs for Date::ICal as well.
291              
292             =head1 DESCRIPTION
293              
294             Calculate the Discordian date of a particular 'real' date.
295              
296             Date::Discordian exports two functions - discordian(), and
297             inverse_discordian. C,
298             when given a time value, returns a string, giving the Discordian
299             date for the given day. I, given a
300             Discordian date in the same format that C emits,
301             returns an epoch time value. It is pretty picky about time
302             format. Pity.
303              
304             I'm really not sure how this would ever be used, so if you actually use
305             this, send me a note.
306              
307             =head1 Bugs/To Do
308              
309             There are no bugs. Only misinterpretation of the documentation.
310             Accept C-style input. And possibly output the same format as
311             ddate, since that seems more widely accepted
312             Perhaps an option of some variety to be able to create dates to use
313             the 4000bc epoch rather than the 1166bc epoch
314             Get mentioned in more articles about the cool things you can do with
315             Perl (http://www.perl.com/pub/a/2001/10/31/lighter.html)
316              
317             =head1 General comments
318              
319             When I first started working on this module, it was purely as an
320             exercise to get started on Date:: modules in general. Since that time, I
321             have become alarmingly aware of how the events of real life seem to
322             follow the Discordian calendrical rhythm. Perhaps this is just because
323             everything sucks all of the time, but it seems to be a little deeper
324             than this.
325              
326             You can find out more about the Discordian Calendar at
327             http://jubal.westnet.com/hyperdiscordia/discordian_calendar.html
328             and at a plethora of other sites on the Internet.
329              
330             It is related to the Principia Discordia
331             (http://members.xoom.com/ffungo/titlepage.html)
332             and the "religion" of Discordianism. I suppose that there are people
333             that actually take this sort of thing seriously. But then, there are
334             people that collect Beanie Babies, so what do you expect?
335              
336             =head1 AUTHOR
337              
338             Rich Bowen (DrBacchus)
339             -- (doubter of the wisdom of Discordianism)
340             Matt Cashner
341             -- (Sungo the Funky)
342              
343             =head1 SEE ALSO
344              
345             Date::ICal
346              
347             Reefknot (www.reefknot.org)
348              
349             datetime@perl.org (http://lists.perl.org/showlist.cgi?name=datetime)
350              
351             Calendrical Calculations, by Reingold and Dershowitz. Not that it has
352             anything to do with this calendar, but it is a great resource if you are
353             interested in algorithmic calendars. And, on that same note, the Oxford
354             Companion to the Year is a wonderful book too.
355              
356             =cut
357              
358             #}}}
359