Thank you. It's very kind of you to offer. I don't mind doing the
conversion. I just wondered if a method already existed that I could
use. I was just trying to avoid re-inventing the wheel.
I agree that it's better to rely on something that already exists if you can find it. If not then here's the code which I haven't used since the early 1990s. Note that I once tested it with every date since 4713 B.C. (see comments) and it worked fine. The conversion to C# should be minimal. Good luck.
////////////////////////////////////////////////////////////////////////////
// Name : jdn.c
//
// Description:
// Routines for processing dates in the format JDN (Julian Day Number).
// Based on formulae originally posted by Tom Van Flandern / Washington,
// DC / (e-mail address removed) in the UseNet newsgroup sci.astro.
// Reposted 14 May 1991 in FidoNet C Echo conference by Paul Schlyter
// (Stockholm). Minor corrections, added JDN to julian, and recast into
// C by Raymond Gardner Englewood, Colorado.
//
// These routines convert Gregorian and Julian calendar dates to and
// from Julian Day Numbers. Julian Day Numbers (JDN) are used by
// astronomers as a date/time measure independent of calendars and
// convenient for computing the elapsed time between dates. The JDN
// for any date/time is the number of days (including fractional days)
// elapsed since noon, Jan 1, 4713 BC. Julian Day Numbers were originated
// by Joseph Scaliger in 1582 and named after his father Julius, not
// after Julius Caesar. They are not related to the Julian calendar.
// For dates from Jan 1, 4713 BC thru Feb 12, 32766 AD, "YMDToJDN()"
// will give the JDN for noon on that date. "JDNToYMD()" will compute
// the year, month, and day from the JDN. Years BC are given (and
// returned) as negative numbers. Note that there is no year 0 BC; the
// day before Jan 1, 1 AD is Dec 31, 1 BC. Also note that 1 BC, 5 BC,
// etc. are leap years.
//
// Pope Gregory XIII decreed that the Julian calendar would end on
// Oct 4, 1582 AD and that the next day would be Oct 15, 1582 in the
// Gregorian Calendar. The only other change is that centesimal years
// (years ending in 00) would no longer be leap years unless divisible
// by 400. Britain and its possessions and colonies continued to use
// the Julian calendar up until Sep 2, 1752, when the next day became
// Sep 14, 1752 in the Gregorian Calendar. These routines can be
// compiled to use either convention. By default, the British convention
// will be used. Simply #define PAPAL to use Pope Gregory's convention.
//
// Each routine takes, as its last argument, a flag to indicate whether
// to use the Julian or Gregorian calendar convention. If this flag is
// negative, the routines decide based on the date itself, using the
// changeover date described in the preceding paragraph. If the flag is
// zero, Gregorian conventions will be used, and if the flag is
// positive, Julian conventions will be used. Consult each function
// in the module for details.
//
// Development Environment:
// MSC V6.00, DOS 3.3
//
// Target Environment:
// Any (ANSI compatible)
//
// Change Control:
// Date Ver Who Ref Description
// Mar 17, 92 01.00.00 LS N/A Creation
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////
#ifdef PAPAL // Pope Gregory XIII's decree ...
#define LASTJULDATE 15821004L // Last day to use Julian calendar
#define LASTJULJDN 2299160L // JDN equivalent of above
#else // British-American usage ...
#define LASTJULDATE 17520902L // last day to use Julian calendar
#define LASTJULJDN 2361221L // JDN equivalent of above
#endif
////////////////////////////////////////////////////////////////////////////
// typedefs
////////////////////////////////////////////////////////////////////////////
typedef long JDN; // Julian Day Number
////////////////////////////////////////////////////////////////////////////
// Name:
// YMDToJDN
//
// Description:
// As described in the module header, converts a date in the range
// Jan 1, 4713 BC to Feb 12, 32766 to its Julian Day Number (JDN).
// This function is the converse of "JDNToYMD()" defined elsewhere in
// the module. Note that no error checking is conducted by the function
// to ensure that the given date is valid.
//
// Input:
// iYear - Year in the range -4713 to 32766. Note that year 0 is
// invalid as described in the module header.
// iMonth - Month in the range 1 to 12
// iDay - Day of the month
// iJulian - As described in the module header, set to 1 if the Julian
// calendar is to be used, 0 if the Gregorian calendar is to
// be used, or -1 if the function decides this based on the
// date itself (again, see the module header for details).
// Note that most of the time, you will likely pass -1. Thus,
// the date you pass is assumed to be a Gregorian date if
// it falls past the Julian==>Gregorian changeover date
// described in the module header. Otherwise, if it falls on
// or before this changeover date, the date is assumed to be a
// Julian date.
//
// Output:
// None
//
// Return:
// The Julian Day Number for the given date.
//
// Comments:
// Note that the date you pass must be valid or erroneous results may
// occur. Thus, besides being a valid date (i.e., the year is not zero,
// the month is in the range 1-12, the day is in the range 1-31 and
// valid for the given month, etc.), care must be taken for those dates
// that fall inbetween the Julian==>Gregorian changeover dates described
// in the module header. Thus, for instance, since Britain and its
// possessions and colonies continued to use the Julian calendar up until
// Sep 2, 1752, where the next day became Sep 14, 1752, it makes little
// sense to pass a date inbetween this range (non-inclusive) if this date
// is intended to be a Gregorian date. It is a valid date however if
// the date is considered to be a Julian date (assumes no changeover
// to the Gregorian calendar for that date). The value returned by the
// function therefore varies according to the "iJulian" flag, returning
// the correct JDN regardless of the date (for its date type, either
// Julian or Gregorian).
//
////////////////////////////////////////////////////////////////////////////
extern JDN YMDToJDN(int iYear, int iMonth, int iDay, int iJulian)
{
long lJDN;
if (iJulian < 0) // Set Julian flag if auto set
iJulian = (((iYear * 100L) + iMonth) * 100 + iDay <= LASTJULDATE);
if (iYear < 0) // Adjust BC year
iYear++;
if (iJulian)
{
lJDN = 367L * iYear - 7 * (iYear + 5001L + (iMonth - 9) / 7) / 4
+ 275 * iMonth / 9 + iDay + 1729777L;
}
else
{
lJDN = (long)(iDay - 32076)
+ 1461L * (iYear + 4800L + (iMonth - 14) / 12) / 4
+ 367 * (iMonth - 2 - (iMonth - 14) / 12 * 12) / 12
- 3 * ((iYear + 4900L + (iMonth - 14) / 12) / 100) / 4
+ 1; // correction by rdg
}
return lJDN;
}
////////////////////////////////////////////////////////////////////////////
// Name:
// JDNToYMD
//
// Description:
// As described in the module header, converts a Julian Day Number (JDN)
// in the range Jan 1, 4713 BC to Feb 12, 32766 to its equivalent year,
// month and day. This function is the converse of "YMDToJDN()" defined
// elsewhere in the module. Note that no error checking is conducted by
// the function to ensure that the given JDN is valid..
//
// Input:
// lJDN - Julian Day Number in the range Jan 1, 4713 BC to
// Feb 12, 32766.
// iJulian - As described in the module header, set to 1 if the Julian
// calendar is to be used, 0 if the Gregorian calendar is to
// be used, or -1 if the function decides this based on the
// date itself (again, see the module header for details).
// Note that most of the time, you will likely pass -1. Thus,
// the date you pass is assumed to be a Gregorian date if
// it falls past the Julian==>Gregorian changeover date
// described in the module header. Otherwise, if it falls on
// or before this changeover date, the date is assumed to be a
// Julian date.
//
// Output:
// piYear - Ignored if NULL. Otherwise, receives the year equivalent of
// the given JDN in the range -4713 to 32766. Note that year 0
// is invalid so this is NEVER returned.
// piMonth - Ignored if NULL. Otherwise, receives the month equivalent
// of the given JDN in the range 1 to 12.
// piDay - Ignored if NULL. Otherwise, receives the day of the month
// equivalent of the given JDN in the range 1 to 31
// (appropriate for the given month).
//
// Return:
// None
//
// Comments:
//
////////////////////////////////////////////////////////////////////////////
extern void JDNToYMD(JDN lJDN, int *piYear, int *piMonth, int *piDay, int iJulian)
{
long x, z, m, d, y;
long lDaysPer400Years = 146097L;
long lFudgedDaysPer4000Years = 1460970L + 31;
if (iJulian < 0) // Set Julian flag if auto set
{
iJulian = (lJDN <= LASTJULJDN);
}
x = lJDN + 68569L;
if (iJulian)
{
x += 38;
lDaysPer400Years = 146100L;
lFudgedDaysPer4000Years = 1461000L + 1;
}
z = 4 * x / lDaysPer400Years;
x = x - (lDaysPer400Years * z + 3) / 4;
y = 4000 * (x + 1) / lFudgedDaysPer4000Years;
x = x - 1461 * y / 4 + 31;
m = 80 * x / 2447;
d = x - 2447 * m / 80;
x = m / 11;
m = m + 2 - 12 * x;
y = 100 * (z - 49) + y + x;
if (piYear)
{
*piYear = (int)y;
if (*piYear <= 0) // Adjust BC years */
{
(*piYear)--;
}
}
if (piMonth)
{
*piMonth = (int)m;
}
if (piDay)
{
*piDay = (int)d;
}
}