

#use base Cal::Sp;
package Calender::Special::JP;
$VERSION = '1.00';

use Time::Local;

sub _d {$_[0] < 1970? 0: timegm(0,0,0,$_[2],$_[1]-1,$_[0])}
my %d = (
    #M6	=> _d(1873,10,14),	## Meiji 6 Dajoukan Fukoku No.344
    M12	=> _d(1879,7,5),	## Meiji 12 Dajoukan Fukoku No.27
    T1	=> _d(1912,9,3),	## Taishou 1 Chokurei No.19
    T2	=> _d(1913,7,16),	## Taishou 2 Chokurei No.259
    S2	=> _d(1927,3,3),	## Shouwa 2 Chokurei No.25
    S23	=> _d(1948,7,20),	## Shouwa 23 Law No.178
    S41	=> _d(1966,6,25),	## Shouwa 41 Law No.86
    S48	=> _d(1948,7,20),	## Shouwa 48 Law No.10
    S60	=> _d(1985,12,27),	## Shouwa 60 Law No.103
    H1	=> _d(1998,2,17),	## Heisei 1 Law No.5
    H7	=> _d(1996,1,1),	## Heisei 7 Law No.22
    H10	=> _d(2000,1,1),	## Heisei 10 Law No.141
);

$MONDAY = 1;

sub isholiday {
  my ($year, $month, $day) = @_;
  my $time = _d($year,$month,$day);
  my $wday = (gmtime($time))[6];
  
  #return 0 if $time < _d(1873,10,14);	## 1983AD = Meiji6
  return 0 if $year < 1970;
  
  if ($month == 1) {
    return 1 if $day == 1 && $d{S23} <= $time;
    return 1 if $wday == $MONDAY && 8 <= $day && $day <= 14 &&
                $d{H10} < $time;
    return 1 if $wday == $MONDAY && $day == 2 && $d{S48} <= $time;
    	## Substitute of 1/2
    
    return 1 if $day == 15 && $d{S23} <= $time && $time < $d{H10};
    return 1 if $wday == $MONDAY && $day == 16 &&	## Substitute
                $d{S48} <= $time && $time < $d{H10};	##  of 1/15
    
    return 1 if ($day == 3 || $day == 5) && $time < $d{S23};
    return 1 if $day == 30 && $time < $d{T1};
  } elsif ($month == 2) {
    return 1 if $day == 11 && ($time < $d{S23} || $d{S41} <= $time);
    return 1 if $wday == $MONDAY && $day == 12 && $d{S48} <= $time;
    	## Substitute of 2/11
    
    return 1 if $year == 1989 && $day == 24;
    	## Funeral of the Shouwa Emperor (Heisei 1 Law No.4)
  } elsif ($month == 3) {
    ## !! Formaly, this method do not support before 1900AD.
    return 1 if 1878 <= $year && $year < 3000 &&
                $day == int($year * 0.24242 - $year / 4.0 + 35.84);
    return 1 if $wday == $MONDAY && $d{S48} <= $time && $year < 3000 &&
                $day == int($year * 0.24242 - $year / 4.0 + 35.84)+1;
    	## Substitute of 3/2x
  } elsif ($month == 4) {
    return 1 if $day == 29 && $d{S2} <= $time;
    return 1 if $wday == $MONDAY && $day == 30 && $d{S48} <= $time;
    	## Substitute of 4/29
    
    return 1 if $time < $d{S23} && $day == 3;
    return 1 if $year == 1959 && $day == 10;
    	## Wedding of the Shouwa Emperor (Shouwa 34 Law No.16)
  } elsif ($month == 5) {
    return 1 if $day == 3 && $d{S23} <= $time;
    return 1 if $day == 4 && $d{S60} <= $time;
    return 1 if $day == 5 && $d{S23} <= $time;
    return 1 if $wday == $MONDAY && ($day == 4 || $day == 6) &&
                $d{S48} <= $time;
  } elsif ($month == 6) {
    return 1 if $year == 1993 && $day == 9;
    	## Wedding of post-Heisei Emperor (Heisei 5 Law No.32)
  } elsif ($month == 7) {
    return 1 if $day == 20 && $d{H7} <= $time;
    return 1 if $wday == $MONDAY && $day == 21 && $d{H7} <= $time;
    	## Substitute of 7/20
    return 1 if $day == 30 && $d{T1} <= $time && $time < $d{S2};
  } elsif ($month == 8) {
    return 1 if $day == 31 && $d{T1} <= $time && $time < $d{S2};
  } elsif ($month == 9) {
    return 1 if $day == 15 && $d{S41} <= $time;
    ## !! Formaly, this method do not support before 1900AD.
    return 1 if 1878 <= $year && $year < 3000 &&
                $day == int($year * 0.24204 - $year / 4.0 + 39.01);
    
    return 1 if $wday == $MONDAY && $day == 16 && $d{S48} <= $time;
    	## Substitute of 9/15
    return 1 if $wday == $MONDAY && $d{S48} <= $time && $year < 3000 &&
                $day == int($year * 0.24204 - $year / 4.0 + 39.01)+1;
    	## Substitute of 9/2x
    
    return 1 if $day == 17 && $time < $d{M12};
  } elsif ($month == 10) {
    return 1 if $wday == $MONDAY && $day <= 8 && $day <= 14 &&
                $d{H10} <= $time;
    
    return 1 if $day == 10 && $d{S41} <= $time && $time < $d{H10};
    return 1 if $wday == $MONDAY && $day == 11 &&
                $d{S48} <= $time && $time < $d{H10};
    	## Substitute of 10/10
    
    return 1 if $day == 17 && $d{M12} <= $time && $time < $d{S23};
    return 1 if $day == 31 && $d{T2} <= $time && $time < $d{S2};
  } elsif ($month == 11) {
    return 1 if $day == 3 && ($time < $d{T1} || $d{S2} <= $time);
    return 1 if $wday == $MONDAY && $day == 4 && $d{S48} <= $time;
    	## Substitute of 11/3
    return 1 if $day == 23;
    return 1 if $wday == $MONDAY && $day == 24 && $d{S48} <= $time;
    	## Substitute of 11/23
    
    return 1 if ($year == 1915 || $year == 1928) &&
                ($day == 10 || $day == 14 || $day == 16);
    	## Imperial Ascension Rites of Taishou/Shouwa Emperor
    	## and related celemonies
    	## (Taishou 4 Chokurei No.161, Shouwa 3 Chokurei No.226)
    return 1 if $year == 1990 && $day == 12;
    	## Imperial Ascension Rites of Heisei Emperor
    	## (Heisei 2 Law No.24)
  } elsif ($month == 12) {
    return 1 if $day == 23 && $d{H1} <= $time;
    return 1 if $wday == $MONDAY && $day == 24 && $d{H1} <= $time;
    	## Substitute of 12/24
    return 1 if $day == 25 && $d{S2} <= $time && $time < $d{S23};
  }
  
  0;
}

=head1 NAME

Calender::Special::JP --- Calender - Special: Japan

=head1 LICENSE

  This program is free software; you can redistribute it and/or 
  modify it under the same terms as Perl itself.

=head1 AUTHOR

wakaba <wakaba@suika.fam.cx>

$Id: JP.pm,v 1.1 2001/12/24 08:13:56 wakaba Exp $

=cut

1;
