#include <stdlib.h>
#include <time.h>
#include "julian.h"
/* See julian.h for license and documentation */
#ifdef TEST
#include <stdio.h>
#endif
static int is_leap_year (int year)
{
if (year % 4)
{
return 0;
}
if (year < 1582)
{
return 1;
}
if ((year % 100) || (!(year % 400)))
{
return 1;
}
return 0;
}
static long s_days_in_month[2][12] =
{
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
long get_julian_date( int dd, int mm, int yy)
{
long julian;
/* Account all preceding years */
julian = (yy - 1) * 365L;
/* Account the leap years */
julian += (yy - 1) / 4L;
if (yy - 1 > 1582L)
{
/* Subtract all xx00 years */
julian -= (yy - 1) / 100L;
/* But all xx00 years that can be divided by 400 are leap years! */
julian += (yy - 1) / 400L;
/* Account for the centuries before 1582, which all were leap years */
julian += 12L; /* 100, 200, 300, 500, 600, 700, 900,
1000, 1100, 1300, */
}
if (mm)
{
/* mm > 0: assume dd is day number in month */
/* add the days of the current year */
while (--mm)
{
julian += s_days_in_month[is_leap_year(yy)][mm-1];
}
/* days in current month */
julian += dd;
}
else
{
/* mm == 0: assume dd is day number in year as per fts */
julian += dd;
}
/* adjust for the cut from oct 4 to oct 15, 1582 */
if (julian > 577737L)
{
julian -= 10L;
}
/* By now, we have days since Jan 1, 1 (AC). Now convert to Julian day
numbers, which by convention start at Jan 1, 4713 (BC) */
julian += (2299161L - 577738L);
return julian;
}
void decode_julian_date(long julian, int *pdd, int *pmm, int *pyy,
int *pddiny)
{
int yy, dd, mm; long days;
int i;
/* convert to days since B.C. */
julian -= (2299161L - 577738L);
/* undo the oct. 1582 gap */
if (julian > 577737L)
{
julian += 10L;
}
yy = (int)(julian / 365L);
days = (julian % 365L);
/* account for the leap years */
if (yy < 1700)
{
days -= (yy / 4);
}
else
{
days -= (yy / 4);
days += (yy / 100);
days -= (yy / 400);
days -= 12;
}
/* if we did a backwards overrun, adjust properly */
while (days <= 0)
{
if (is_leap_year(yy))
{
yy -= 1;
days += 366;
}
else
{
yy -= 1;
days += 365;
}
}
dd = (int) days;
yy++;
/* store year, and days in year */
if (pyy != NULL)
{
*pyy = yy;
}
if (pddiny != NULL)
{
*pddiny = dd;
}
/* now calculate the month number and decrease the day number
accordingly */
for (i = 1; i <= 12; i++)
{
mm = i;
if (dd <= s_days_in_month[is_leap_year(yy)][i-1])
break;
else
dd -= s_days_in_month[is_leap_year(yy)][i-1];
}
if (pdd != NULL)
{
*pdd = dd;
}
if (pmm != NULL)
{
*pmm = mm;
}
}
long julian_today(void)
{
time_t t;
struct tm *tm;
time(&t);
tm=localtime(&t);
return get_julian_date(tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
}
#ifdef TEST
void test(int dd, int mm, int yy)
{
int rdd, rmm, ryy, rdiny;
long l;
l = get_julian_date(dd, mm, yy);
decode_julian_date(l, &rdd, &rmm, &ryy, &rdiny);
printf ("%2d.%2d.%4d %8ld %2d.%2d.%4d. (%3d)\n",
dd,mm,yy,l,rdd,rmm,ryy,rdiny);
}
int main(void)
{
test (31, 12, 1899);
test (1, 1, 1900);
test (28, 2, 1900);
test (1, 3, 1900);
test (31, 12, 1999);
test (1, 1, 2000);
test (28, 2, 2000);
test (1, 3, 2000);
test (31, 12, 2099);
test (1, 1, 2100);
test (28, 2, 2100);
test (1, 3, 2100);
test (22, 6, 1976); /* tobi's birthday <g> */
test (11, 10, 1999);
test (1, 1, 1);
test (4, 10, 1582);
test (15, 10, 1582);
return 0;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1