Article 8986 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:8986
Path: feenix.metronet.com!news.ecn.bgu.edu!usenet.ins.cwru.edu!howland.reston.ans.net!xlink.net!rz.uni-karlsruhe.de!news.uni-stuttgart.de!zrzr0111
From: zrzr0111@helpdesk.rus.uni-stuttgart.de (Kurt Jaeger aka PI)
Newsgroups: comp.lang.perl
Subject: Re: Julian Date?
Date: 17 Dec 1993 20:05:59 GMT
Organization: Comp.Center (RUS), U of Stuttgart, FRG
Lines: 291
Message-ID: <2et3f7$1reu@info2.rus.uni-stuttgart.de>
References: <DLOPATA.93Dec17142249@marlin.stat.ufl.edu>
NNTP-Posting-Host: helpdesk.rus.uni-stuttgart.de

In article <DLOPATA.93Dec17142249@marlin.stat.ufl.edu>,
David Lopata <dlopata@stat.ufl.edu> wrote:
>	I assume converting the standard date line to a julian number
>(am I phrasing this right?) and then subtracting the two numbers would
>be the most efficient way.
>
>	Does anyone know how to acccomplish this in Perl?

Yes, give the source following below a try.

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 12/17/1993 20:05 UTC by zrzr0111@helpdesk
# Source directory /helpdesk/z/zr/0111/zrzr/src
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   1468 -rw-r--r-- day-of-year/README
#   1463 -rw-r--r-- day-of-year/day-of-year.c
#   3213 -rwxr-xr-x day-of-year/day-of-year.perl
#
# ============= day-of-year/README ==============
if test ! -d 'day-of-year'; then
    echo 'x - creating directory day-of-year'
    mkdir 'day-of-year'
fi
if test -f 'day-of-year/README' -a X"$1" != X"-c"; then
	echo 'x - skipping day-of-year/README (File already exists)'
else
echo 'x - extracting day-of-year/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'day-of-year/README' &&
XFrom: ism@metagen.uucp (Ian Miller)
Subject: Re: Determining the Day of the Week
Message-ID: <184@babbage.metagen.uucp>
Date: 25 May 93 18:01:23 GMT
Organization: Meta_Generics Ltd, Cambridge, UK
X
The simplest technique is probably to convert to a Julian Day number and
then take the result mod7.  This has the advantage that you can
do a lot of other things with Julian Day number as well.  The best
algorithm I know of was published as a letter from Henry F Fliegel and
Thomas C van Flandern in the October 1968 (vol 11 #10) issue of the 
Communications of the ACM.
X
Julian Day Number = day - 32075 + 1461 * (year + 4800 - (14 - month)/12)/4 +
X      367 * (month - 2 + (14 - month)/12*12)/12 -
X      3 * ((year + 4900 - (14 - month)/12)/100)/4
X
This is valid for all dates in the Gregorian Calendar up to 28 Feb 4000.
(I have modified this algorithm slightly from the original to avoid dividing
negative numbers.  The original only worked in FORTRAN.  The modified version
should work in any language.)
X
They also quote the following reverse algorithm:-
X
temp1 = julian_date + 68569
temp2 = 4*temp1/146097
temp1 = temp1 - (146097 * temp2 + 3) / 4
year  = 4000 * (temp1 + 1) / 1461001
temp1 = temp1 - 1461 * year/4 + 31
month = 80 * temp1 / 2447
day   = temp1 - 247 * month / 80
temp1 = month / 11
month = month + 2 - 12 * temp1
year  = 100 * (temp2 - 49) + year + temp1
X
They do work.  Don't ask me how.
X
X
-- 
Ian Miller   Any replies to: ian_m@cix.compulink.co.uk
X
SHAR_EOF
chmod 0644 day-of-year/README ||
echo 'restore of day-of-year/README failed'
Wc_c="`wc -c < 'day-of-year/README'`"
test 1468 -eq "$Wc_c" ||
	echo 'day-of-year/README: original size 1468, current size' "$Wc_c"
fi
# ============= day-of-year/day-of-year.c ==============
if test -f 'day-of-year/day-of-year.c' -a X"$1" != X"-c"; then
	echo 'x - skipping day-of-year/day-of-year.c (File already exists)'
else
echo 'x - extracting day-of-year/day-of-year.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'day-of-year/day-of-year.c' &&
#include <stdio.h>
X
int julian_day(int, int, int);
void inverse_julian_day(int, int*,int*,int*);
X
main()
{
X    int offset;		/* offset into the julian day */
X    int y,m,d;		/* invers jul day */
X    int i,j,k;		/* loop for year/month/day */
X    int erg;
X    int old;
X
X    offset=julian_day(1988,1,1);
X
/*    printf("off: %d\n",offset); */
X
X    for(i=1988; i<=1998; i++) {
X    for(j=1; j<=12; j++) {
X	erg=julian_day(i,j,1);
X        inverse_julian_day(erg,&y,&m,&d);
X	printf("Y: %4d ergabs: %6d ergrel: %5d Y: %4d M: %2d D: %2d\n",
X               i,erg,erg-offset,y,m,d);
X    }
X    }
X
}
X
/*
X    this works, indeed !
X    from a given date, gives a continous day-number relative to some
X    date in the past, correcting leap-years etc.
*/
int julian_day(int year, int month, int day)
{
X
X    int tmp;
X
X    tmp = day - 32075 + 1461 * (year + 4800 - (14 - month)/12)/4 +
X       367 * (month - 2 + (14 - month)/12*12)/12 -
X       3 * ((year + 4900 - (14 - month)/12)/100)/4;
X 
X    return(tmp);
X
}
X
void inverse_julian_day(int jul_day, int *year, int *month, int *day)
{
X    int temp1,temp2;
X
X    temp1 = jul_day + 68569;
X    temp2 = 4*temp1/146097;
X    temp1 = temp1 - (146097 * temp2 + 3) / 4;
X    *year = 4000 * (temp1 + 1) / 1461001;
X    temp1 = temp1 - 1461 * (*year)/4 + 31;
X    *month= 80 * temp1 / 2447;
X    *day  = temp1 - 247 * (*month) / 80;
X    temp1 = (*month) / 11;
X    *month= (*month) + 2 - 12 * temp1;
X    *year = 100 * (temp2 - 49) + (*year) + temp1;
X
}
X
SHAR_EOF
chmod 0644 day-of-year/day-of-year.c ||
echo 'restore of day-of-year/day-of-year.c failed'
Wc_c="`wc -c < 'day-of-year/day-of-year.c'`"
test 1463 -eq "$Wc_c" ||
	echo 'day-of-year/day-of-year.c: original size 1463, current size' "$Wc_c"
fi
# ============= day-of-year/day-of-year.perl ==============
if test -f 'day-of-year/day-of-year.perl' -a X"$1" != X"-c"; then
	echo 'x - skipping day-of-year/day-of-year.perl (File already exists)'
else
echo 'x - extracting day-of-year/day-of-year.perl (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'day-of-year/day-of-year.perl' &&
#!/usr/bin/perl
X
$offset=&julian_day("1988","1","1");
X
for $j (1988..1998) {
X    for $i (1..12) {
X	$erg=&julian_day($j,$i,"1");
X	($y,$m,$d) = &inverse_julian_day($erg);
X	printf "Y: %4d ergabs: %5d ergrel: %5d Y: %4d M: %2d D: %3d\n",
X               $j,$erg,$erg-$offset,$y,$m,$d;
X    }
}
X
Xexit 0;
X
# calculate the julian day, given $year, $month and $day
sub julian_day
{
X    local($year, $month, $day) = @_;
X    local($tmp);
X
X    $tmp = $day - 32075
X      + int(
X            1461*($year + 4800 - int(
X                                     (
X                                      14 - $month
X                                     )/12
X                                    )
X                 )/4
X           )
X      + int(
X            367*($month -2 + int(
X                                 (14 - $month
X                                 )/12
X                                )*12
X                )/12
X           )
X      - int(
X            3*(
X               (
X                $year + 4900 - (
X                                14 - $month
X                               )/12
X               )/100
X              )/4
X           )
X      ;
X
X    return($tmp);
X
}
X
sub inverse_julian_day
{
X    local($julian_day) = @_;
X    local($year,$month,$day);
X    local($temp1,$temp2);
X
X    $temp1 = $julian_day + 68569;
X    $temp2 = int(4*$temp1/146097);
X    $temp1 = $temp1 - int((146097 * $temp2 + 3) / 4);
X    $year  = int(4000 * ($temp1 + 1) / 1461001);
X    $temp1 = $temp1 - int(1461 * $year/4) + 31;
X    $month = int(80 * $temp1 / 2447);
X    $day   = $temp1 - int(247 * $month / 80);
X    $temp1 = int($month / 11);
X    $month = $month + 2 - 12 * $temp1;
X    $year  = 100 * ($temp2 - 49) + $year + $temp1;
X
X    return($year, $month, $day);
X
}
X
# From: ian_m@cix.compulink.co.uk (Ian Miller)
# Subject: Re: Determining the Day of the Week
# Message-ID: <184@babbage.metagen.uucp>
# Date: 25 May 93 18:01:23 GMT
# Organization: Meta_Generics Ltd, Cambridge, UK
# 
# The simplest technique is probably to convert to a Julian Day number and
# then take the result mod7.  This has the advantage that you can
# do a lot of other things with Julian Day number as well.  The best
# algorithm I know of was published as a letter from Henry F Fliegel and
# Thomas C van Flandern in the October 1968 (vol 11 #10) issue of the 
# Communications of the ACM.
#
# Julian Day Number = day - 32075 + 1461 * (year + 4800 - (14 - month)/12)/4 +
#       367 * (month - 2 + (14 - month)/12*12)/12 -
#       3 * ((year + 4900 - (14 - month)/12)/100)/4
# 
# This is valid for all dates in the Gregorian Calendar up to 28 Feb 4000.
# (I have modified this algorithm slightly from the original to avoid dividing
# negative numbers.  The original only worked in FORTRAN.  The modified version
# should work in any language.)
# 
# They also quote the following reverse algorithm:-
# 
# temp1 = julian_date + 68569
# temp2 = 4*temp1/146097
# temp1 = temp1 - (146097 * temp2 + 3) / 4
# year  = 4000 * (temp1 + 1) / 1461001
# temp1 = temp1 - 1461 * year/4 + 31
# month = 80 * temp1 / 2447
# day   = temp1 - 247 * month / 80
# temp1 = month / 11
# month = month + 2 - 12 * temp1
# year  = 100 * (temp2 - 49) + year + temp1
# 
# They do work.  Don't ask me how.
# 
X
SHAR_EOF
chmod 0755 day-of-year/day-of-year.perl ||
echo 'restore of day-of-year/day-of-year.perl failed'
Wc_c="`wc -c < 'day-of-year/day-of-year.perl'`"
test 3213 -eq "$Wc_c" ||
	echo 'day-of-year/day-of-year.perl: original size 3213, current size' "$Wc_c"
fi
exit 0

-- 
PI at the User Help Desk Comp.Center U of Stuttgart, FRG      27 years to go ! 
EMail: pi@rus.uni-stuttgart.de
Phone: +49 711 685-4828                (aka Kurt Jaeger)


