So…
Here is a happy little bi-directional Julian Day Number / Calendar Date Converter
written in Javascript.
By editing this bit of code (for example) :
//round to nearest second
var jd0 = (intgr + frac)*100000;
var jd = Math.floor(jd0);
if( jd0 - jd > 0.5 ) ++jd;
return jd/100000;
the Julian Day Number epoch (or output) can either be manipulated, or cause a digital aneurysm, depending on whether the editor is an actual coder, or not.
Also – managing to edit the algorithm to successfully convert in one direction
does not mean a successful conversion in the opposite direction.
How then can the algorithm be edited to output an integer day number + fractional day
from a new epoch – JD 2049857.25 (for example)
15 March 900 CE at 18:00:00 UTC in the Julian Calendar,
and output correctly in both directions? (based on this example epoch)
Thanks in advance!
<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript">
<!-------
//-------
// convert calendar to Julian date
//-------
function cal_to_jd( era, y, m, d, h, mn, s )
{
var jy, ja, jm; //scratch
if( y == 0 ) {
alert("There is no year 0 in the Julian system!");
return "invalid";
}
if( y == 1582 && m == 10 && d > 4 && d < 15 ) {
alert("The dates 5 through 14 October, 1582, do not exist in the Gregorian system!");
return "invalid";
}
// if( y < 0 ) ++y;
if( era == "BCE" ) y = -y + 1;
if( m > 2 ) {
jy = y;
jm = m + 1;
} else {
jy = y - 1;
jm = m + 13;
}
var intgr = Math.floor( Math.floor(365.25*jy) + Math.floor(30.6001*jm) + d + 1720995 );
//check for switch to Gregorian calendar
var gregcal = 15 + 31*( 10 + 12*1582 );
if( d + 31*(m + 12*y) >= gregcal ) {
ja = Math.floor(0.01*jy);
intgr += 2 - ja + Math.floor(0.25*ja);
}
//correct for half-day offset
var dayfrac = h/24.0 - 0.5;
if( dayfrac < 0.0 ) {
dayfrac += 1.0;
--intgr;
}
//now set the fraction of a day
var frac = dayfrac + (mn + s/60.0)/60.0/24.0;
//round to nearest second
var jd0 = (intgr + frac)*100000;
var jd = Math.floor(jd0);
if( jd0 - jd > 0.5 ) ++jd;
return jd/100000;
}
//-------
// convert Julian date to calendar date
//-------
function jd_to_cal( jd, form )
{
var j1, j2, j3, j4, j5; //scratch
//
// get the date from the Julian day number
//
var intgr = Math.floor(jd);
var frac = jd - intgr;
var gregjd = 2299161;
if( intgr >= gregjd ) { //Gregorian calendar correction
var tmp = Math.floor( ( (intgr - 1867216) - 0.25 ) / 36524.25 );
j1 = intgr + 1 + tmp - Math.floor(0.25*tmp);
} else
j1 = intgr;
//correction for half day offset
var dayfrac = frac + 0.5;
if( dayfrac >= 1.0 ) {
dayfrac -= 1.0;
++j1;
}
j2 = j1 + 1524;
j3 = Math.floor( 6680.0 + ( (j2 - 2439870) - 122.1 )/365.25 );
j4 = Math.floor(j3*365.25);
j5 = Math.floor( (j2 - j4)/30.6001 );
var d = Math.floor(j2 - j4 - Math.floor(j5*30.6001));
var m = Math.floor(j5 - 1);
if( m > 12 ) m -= 12;
var y = Math.floor(j3 - 4715);
if( m > 2 ) --y;
if( y <= 0 ) --y;
//
// get time of day from day fraction
//
var hr = Math.floor(dayfrac * 24.0);
var mn = Math.floor((dayfrac*24.0 - hr)*60.0);
f = ((dayfrac*24.0 - hr)*60.0 - mn)*60.0;
var sc = Math.floor(f);
f -= sc;
if( f > 0.5 ) ++sc;
if( y < 0 ) {
y = -y;
form.era[1].checked = true;
} else
form.era[0].checked = true;
form.year.value = y;
form.month[m-1].selected = true;
form.day[d-1].selected = d;
form.hour.value = hr;
form.minute.value = mn;
form.second.value = sc;
}
//-------
// calculate Julian date from calendar date or calendar date from Julian date
//-------
function JDcalc( form ) {
var era;
for( k=0; k < form.era.length; ++k ) {
if( form.era[k].checked ) {
era = form.era[k].value;
break;
}
}
var calctype;
for( k=0; k < form.calctype.length; ++k ) {
if( form.calctype[k].checked ) {
calctype = form.calctype[k].value;
break;
}
}
if( calctype == "JD" ) {
var m;
for( var k=0; k < form.month.length; ++k ) { //Netscape 4.7 is stoopid
if( form.month[k].selected ) {
m = k+1;
break;
}
}
var d;
for( var k=1; k <= form.day.length; ++k ) { //Netscape 4.7 is stoopid
if( form.day[k-1].selected ) {
d = k;
break;
}
}
var y = parseFloat(form.year.value);
// var m = parseFloat(form.month.value);
// var d = parseFloat(form.day.value);
var h = parseFloat(form.hour.value);
var mn = parseFloat(form.minute.value);
var s = parseFloat(form.second.value);
if( y < 0 ) {
y = -y;
era = "BCE";
form.year.value = y;
form.era[1].checked = true;
}
form.JDedit.value = cal_to_jd(era,y,m,d,h,mn,s);
} else {
jd_to_cal(form.JDedit.value,form);
}
//weekday
var weekday = new Array("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday");
var t = parseFloat(form.JDedit.value) + 0.5;
var wd = Math.floor( (t/7 - Math.floor(t/7))*7 + 0.000000000317 ); //add 0.01 sec for truncation error correction
form.wkday.value = weekday[wd];
}
var month = new Array("January","February","March","April","May","June","July",
"August","September","October","November","December");
var numdays = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
function ModifiedDate() {
updated = new Date(document.lastModified);
Month = month[updated.getMonth()];
Day = updated.getDate();
Year = updated.getYear();
Hour = updated.getHours();
Min = updated.getMinutes();
if( Year < 2000 ) Year += 1900;
if( Year < 2000 ) Year += 100; //Netscape 3 and IE 4.7 return 0 instead of 100 for 2000
if( Hour < 10 ) Hour = "0" + Hour;
if( Min < 10 ) Min = "0" + Min;
document.write("Last modified " + Month + " " + Day + ", " + Year + " at " + Hour + ":" + Min);
}
function set_form_fields(form) {
//grab the current USNO clock time
var today = new Date();
var year = today.getYear();
if( year < 2000 ) year += 1900;
if( year < 2000 ) year += 100; //Netscape 3 and IE 4.7 return 0 instead of 100 for 2000
var month = today.getMonth();
var day = today.getDate();
var hour = today.getHours();
var mins = today.getMinutes();
var secs = today.getSeconds();
//convert to UT
var TZ = today.getTimezoneOffset()/60;
hour += TZ;
if( hour >= 24 ) {
hour -= 24;
++day;
if( day > numdays[month-1] ) {
day = 1;
++month;
if( month > 11 ) {
month -= 12;
++year;
}
}
}
//set the form fields
form.year.value = year;
for( k=0; k < form.month.length; ++k ) { //Netscape 4.7 is stoopid
if( k == month ) {
form.month[k].selected = true;
break;
}
}
form.day.value = day;
for( k=1; k <= form.day.length; ++k ) { //Netscape 4.7 is stoopid
if( k == day ) {
form.day[k-1].selected = true;
break;
}
}
form.hour.value = hour;
form.minute.value = mins;
form.second.value = secs;
doJD(form);
}
function dodate(form) {
for( k=0; k < form.calctype.length; ++k ) {
if( form.calctype[k].value == "date" ) {
form.calctype[k].checked = true;
break;
}
}
}
function doJD(form) {
for( k=0; k < form.calctype.length; ++k ) {
if( form.calctype[k].value == "JD" ) {
form.calctype[k].checked = true;
break;
}
}
}
//------>
</script>