package DATETIME;
use strict;
use List::Util qw(sum);

our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION);

use Exporter;
$VERSION = 2008.166;
@ISA = qw(Exporter);

@EXPORT = qw(calday julday isleapyear); # symbols to autoexport (:DEFAULT tag)
@EXPORT_OK = qw(); # symbols to export on request
%EXPORT_TAGS = (
	date => [qw(calday julday isleapyear)],
	time => [],
);

# BEGIN CODE
###################################################################

# YEAR,JULDAY => MONTH,DAYOFMONTH
# NOTE: JULDAY,MONTH,DAYOFMONTH RANGE BEGINS WITH 0!!!
sub calday {
	# FORCE INTEGER
	my ($yr,$jday)=(int($_[0]),int($_[1]));
	
	# DEALING WITH LOW/HIGH JULDAY VALUES
	my $leap=isleapyear($yr);
	if ($jday<0) {$yr--; $jday+=365+isleapyear($yr); return calday($yr,$jday);}
	elsif ($jday>$leap+364) {$jday-=$leap+365; $yr++; return calday($yr,$jday);}
	
	# NUMBER OF DAYS PER MONTH
	my @ndays=(31,28+$leap,31,30,31,30,31,31,30,31,30,31);
	
	# CALENDAR DATE
	foreach (my $i=0; $i<=$#ndays; $i++) {
		if ($jday<$ndays[$i]) {return $i,$jday;}
		$jday-=$ndays[$i];
	}
}

# YEAR,MONTH,DAYOFMONTH => JULDAY
# NOTE: MONTH,DAYOFMONTH,JULDAY RANGE BEGINS WITH 0!!!
sub julday {
	# FORCE INTEGER
	my ($yr,$mon,$day)=(int($_[0]),int($_[1]),int($_[2]));
	
	# DEALING WITH LOW/HIGH MONTH VALUES
	if ($mon<0) {$yr--; $mon+=12; return julday($yr,$mon,$day);}
	elsif ($mon>11) {$yr++; $mon-=12; return julday($yr,$mon,$day);}
	
	# NUMBER OF DAYS PER MONTH
	my @ndays=(31,28+isleapyear($yr),31,30,31,30,31,31,30,31,30,31);
	
	# DEALING WITH LOW/HIGH DAYOFMONTH VALUES
	if ($day<0) {
		$mon--;
		if ($mon<0) {$yr--; $mon=11; $day+=31; return julday($yr,$mon,$day);}
		else {$day+=$ndays[$mon]; return julday($yr,$mon,$day);}
	} elsif ($day>=$ndays[$mon]) {
		$mon++;
		if ($mon>11) {$yr++; $mon=0; $day-=31; return julday($yr,$mon,$day);}
		else {$day-=$ndays[$mon]; return julday($yr,$mon,$day);}
	}
	
	# JULIAN DAY
	if ($mon==0) {return $day;}
	return sum(@ndays[0..$mon-1])+$day;
}

# ARE WE A LEAP YEAR? 1 IF SO, 0 IF NOT
sub isleapyear {
	# FORCE INTEGER
	my ($yr)=(int($_[0]));
	
	# EVERY 4 YEARS EXCEPT ON THE CENTURIES UNLESS IT IS DIVISIBLE
	# BY 400 (SO 1900 WAS NOT A LEAP YEAR, 1600 AND 2000 WERE)
	return !($yr%4) and ($yr%100 or !($yr%400));
}

###################################################################
1;
