I would like to help these of you who helped me find bugs and faults
in my online solar calendar.
I am especially grateful to Gianni Ferrari, Antonio Siccardi, David
Bell, John Hall and Jack Aubert.
A lot of thanks!
I am working on solving the bugs you reported to me and I have to say
that I think I have solved
almost all of them just by doing the following, which can serve as an
advice:
-------------------------------------------------------------
DO *NOT* use the JavaScript Date() class except when
absolutely neccessary. It is much better to work with angles
and translate the results into hh:mm:ss format at the end.
-------------------------------------------------------------
When I did this all the problems got solved. I am not saying that the
Date() class has got flaws (I leave
this for the gurus), just that it is much safer to work with angles.
I am not completely sure my script always calculates well the Julian
Date (and consequently, the DifferenceOfDates),
and maybe some bugs could stay there but (I cross my fingers) the rest
of them apparently have been solved.
As regards to the vocabulary, I have accepted all your suggestions, but
still I am not sure about Noon...
Is it correct to say 'True Solar Noon'? or just 'True Noon'? I wouldn't
like to use cumbersome expressions
like 'Solar Transit' or so.
And about the superfluous decimal figures (nice but useless) I have
received as many opinions against
them than in favour, so I don't know what to do.
Thanks in advance for your help and, please, keep sending suggestions.
Anselmo
<x-html><!x-stuff-for-pete base="" src="" id="0"><HTML>
<SCRIPT LANGUAGE="JavaScript">
var rad2deg = 180/Math.PI;
var deg2rad = Math.PI/180;
var Latitud = 41.63;
var Longitud = 4.73;
var Tseg = 1000;
var Tmin = 60*1000;
var Thor = 60*60*1000;
var Tdia = 24*60*60*1000;
var miReloj = null;
var VentanaCambiar;
function normaliza(ang) {
var numrevs = ang/360;
return(360*(numrevs - Math.floor(numrevs)));
}
function redondea(num, ndec) {
var mult=1;
for(cnt=1; cnt<=ndec; cnt++) mult *= 10;
return Math.round(num*mult) / mult;
}
function HourToString(objDate) {
var horas = objDate.getHours().toString();
var mins = objDate.getMinutes().toString();
var segs = objDate.getSeconds().toString();
if (horas.length == 1) horas = "0" + horas;
if (mins.length == 1) mins = "0" + mins;
if (segs.length == 1) segs = "0" + segs;
return(" " + horas + ":" + mins + ":" + segs + " ");
}
function DegToHMS(ang) {
ang = normaliza(ang);
var horas = (Math.floor(ang/15)).toString();
var mins = (Math.floor(4*(ang%15))).toString();
var segs = (Math.round((ang*240)%60)).toString();
if (horas.length == 1) horas = "0" + horas;
if (mins.length == 1) mins = "0" + mins;
if (segs.length == 1) segs = "0" + segs;
return(" " + horas + ":" + mins + ":" + segs + " ");
}
function Parar() {
clearTimeout(miReloj);
}
function actualizar(cerrar) {
// Esta función pasa los valores del formulario de abajo a la ventana
principal
window.document.forms[0].lat.value =
VentanaCambiar.document.forms[0].NuevaLatitud.value;
window.document.forms[0].lon.value =
VentanaCambiar.document.forms[0].NuevaLongitud.value;
if(cerrar==true) VentanaCambiar.close();
}
function Cambia() {
VentanaCambiar = window.open("", "Cambio", "widht=400, height=120")
var contenido =
'<HTML> <HEAD> <TITLE> CambiarCoordenadas </TITLE> </HEAD>' +
'<BODY BGCOLOR="wheat"> <FORM>' +
' Nueva Latitud (N): <input name="NuevaLatitud"> <br>' +
' Nueva Longitud (W): <input name="NuevaLongitud"> <br>' +
'<input type="button" value="Aplicar"
onClick="javascript:opener.actualizar(false);">' +
'<input type="button" value="Aceptar"
onClick="javascript:opener.actualizar(true);">' +
'</FORM> <BODY>' +
'<HTML>';
VentanaCambiar.document.open();
VentanaCambiar.document.write(contenido);
VentanaCambiar.document.close();
}
// ======================= FUNCION PRINCIPAL ==========================
function darHora() {
Latitud = document.forms[0].lat.value;
Longitud = document.forms[0].lon.value;
var ahora = new Date();
var huso = ahora.getTimezoneOffset(); // en minutos (de tiempo)
var ahoraUT = new Date(ahora - Tdia + huso*Tmin);
var FechaRef = new Date(2000,0,1,12-huso/60,0); // 1 de enero de 2000 a
las 12:00 UT
var DifFechas = (ahoraUT - FechaRef)/Tdia + 1.0;
var FechaJD = ahora.valueOf()/Tdia + 2440587.5; // ALT: 2451545.0 +
DifFechas.valueOf() + 3/24;
var Hahora = ahora.getHours()*15 + ahora.getMinutes()/4 +
ahora.getSeconds()/240;
var Hhuso = huso/4; // en grados
// ================= algoritmo de Savoie 53 ====================
LM = 280.46+0.9856474*DifFechas;
LM = normaliza(LM);
M = deg2rad*(357.528+0.9856003*DifFechas);
LAMBDA = LM + 1.915*Math.sin(M) + 0.02*Math.sin(2*M);
var Decl = rad2deg*Math.asin(Math.sin(deg2rad*LAMBDA)*0.3977724943);
var AscRec = rad2deg*Math.atan2(Math.sin(deg2rad*LAMBDA) ,
Math.cos(deg2rad*LAMBDA)*1.089937164);
AscRec = normaliza(AscRec);
var HEoT = LM - AscRec; // medida en grados
var EoT = 4*(LM - AscRec)*60; // medida en segundos (de tiempo)
var HCorreccionTotal = Hhuso + HEoT - Longitud;
var HAngHorSol = Hahora + HCorreccionTotal;
// Se calcula el ángulo horario del sol, y con él todo lo demás
var HHoraCivil = HAngHorSol - 180;
with(Math) {
var Elev = rad2deg*asin( sin(deg2rad*Decl)*sin(deg2rad*Latitud) +
cos(deg2rad*Decl)*cos(deg2rad*Latitud)*cos(deg2rad*HHoraCivil) ) ;
var Acim = rad2deg*atan2( sin(deg2rad*HHoraCivil) ,
sin(deg2rad*Latitud)*cos(deg2rad*HHoraCivil) -
cos(deg2rad*Latitud)*tan(deg2rad*Decl) )
};
var AngSidereo = normaliza(HHoraCivil + AscRec);
var ArcoSemiDiurno =
rad2deg*Math.acos(-Math.tan(deg2rad*Latitud)*Math.tan(deg2rad*Decl));
var Hita = HHoraCivil - ArcoSemiDiurno;
var Hbab = HHoraCivil + ArcoSemiDiurno;
var Hmed = Hahora - HHoraCivil; //ALT : 180º - correccióntotal
var Hort = Hahora - Hbab; //ALT: Hmed - ASD
var Hocc = Hahora - Hita; //ALT: Hmed + ASD
document.forms[0].reloj.value = DegToHMS(Hahora);
document.forms[0].relojUTC.value = DegToHMS(Hahora + Hhuso);
document.forms[0].fechajuliana.value = redondea(FechaJD,5);
// document.forms[0].fecha.value = DegToHMS(-HCorreccionTotal);
//DifFechas; //FechaRef; // ahora.toLocaleString(); // cambialo
document.forms[0].EcuaTiem.value = redondea(EoT,2);
document.forms[0].Declinacion.value = redondea(Decl,3);
document.forms[0].Longitud.value = redondea(LAMBDA,3);
// document.forms[0].AscRec.value = DegToHMS(AscRec);
document.forms[0].relojS.value = DegToHMS(HAngHorSol);
document.forms[0].Elev.value = redondea(Elev,5);
document.forms[0].Acimut.value = redondea(Acim,5);
document.forms[0].HS.value = DegToHMS(AngSidereo);
document.forms[0].Ita.value = DegToHMS(Hita);
document.forms[0].Bab.value = DegToHMS(Hbab);
// document.forms[0].Duracion.value = DegToHMS(2*ArcoSemiDiurno);
document.forms[0].Mediodia.value = DegToHMS(Hmed);
document.forms[0].Orto.value = DegToHMS(Hort);
document.forms[0].Ocaso.value = DegToHMS(Hocc);
// document.forms[0].lat.value = Latitud; ???
// document.forms[0].lon.value = Longitud; ???
// document.forms[0].AS.value = redondea(AngSidereo,5);
miReloj = setTimeout("darHora()", 500);
}
// FALTAS:
// - Orto y ocaso
// - Hora del mediodía
// - Horas temporarias y demás
// - Modificar coordenadas más fácilmente (en la misma hoja)
// - Ajustar los formatos numéricos
// * Corregir Fecha Juliana
// * Organizarlo mejor (vg. clase HORA)
// * Comentarios
</SCRIPT>
<STYLE TYPE="text/css">
BODY {
BACKGROUND-C0LOR: lightblue;
FONT-SIZE: 12pt;
FONT-FAMILY: Georgia, Palatino, Times;
}
INPUT, TEXTAREA {
BACKGROUND-COLOR: transparent;
BORDER-STYLE: none;
BORDER-WIDHT: 2pt;
BORDER-COLOR: tan;
FONT-SIZE: 14pt;
FONT-FAMILY: Georgia, Palatino, Times; /* prueba monospace; */
TEXT-ALIGN: right;
}
</STYLE>
<HEAD> <TITLE> Yet another online solar calendar </TITLE> <HEAD>
<BODY BGCOLOR="wheat" onload="darHora();" >
<!-- BASEFONT FACE="Georgia, Palatino" SIZE="+3" -->
<FORM>
<CENTER>
<TABLE NOBORDER WIDTH=75%>
<TR><TD COLSPAN= 2 BGCOLOR=indianred ALIGN="center"><FONT SIZE=+4
COLOR=WHEAT> UBI SOL IBI CLARITAS </FONT>
<TR> <TD ALIGN="left" STYLE="font-size:10pt;"> LOCATION AT:
Latitude (N): <INPUT STYLE="font-size:10pt;" TYPE="text" SIZE="6"
NAME="lat" value=41.63>
Longitude (W): <INPUT STYLE="font-size:10pt;" TYPE="text" SIZE="6"
NAME="lon" value=4.73>
<TD ALIGN="right" STYLE="font-size:10pt;">| <A
HREF="javascript:Cambia();">Change Coords</A> |
</TABLE>
</CENTER>
<TABLE NOBORDER WIDTH=75% ALIGN="center">
<TR>
<TD ALIGN="right" WIDTH=45%>
<INPUT TYPE="text" SIZE="10" NAME="reloj">
<TD> Legal Time
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="10" NAME="relojUTC">
<TD> UTC Time
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="15" MAXLENGTH="15" NAME="fechajuliana">
<TD> Julian Date
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="5" NAME="EcuaTiem">
<TD> Equation of Time [sec]
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="5" NAME="Declinacion">
<TD>   Declination [deg]
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="5" NAME="Longitud">
<TD> Ecliptic Longitude [deg]
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="8" NAME="Elev">
<TD> Altitude [deg]
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="8" NAME="Acimut">
<TD> Azimuth SWNE [deg]
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="10" NAME="relojS">
<TD> Solar Local Time
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="10" NAME="Ita">
<TD> Hours from Sunset (italian)
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="10" NAME="Bab">
<TD> Hours from Sunrise (babilonian)
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="10" NAME="HS">
<TD> Sidereal Local Time
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="10" NAME="Orto">
<TD> Sunrise Time
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="10" NAME="Mediodia">
<TD> Solar Noon Time
<TR>
<TD ALIGN="right">
<INPUT TYPE="text" SIZE="10" NAME="Ocaso">
<TD> Sunset Time
</TABLE>
<P ALIGN="center">
<INPUT TYPE="button" VALUE="Stop"
onClick="javascript:Parar();">
<INPUT TYPE="button" VALUE="Continue"
onClick="javascript:darHora();">
<INPUT TYPE="button" VALUE="Change Coords"
onClick="javascript:Cambia();">
</P>
</FORM>
</BODY>
</HTML>