After a quick search I found this simple but really useful algorithm which I simply translated to UnityScript (Javascript):
static function CalculateSunRiseSunSet(date: System.DateTime, lat: float, lng: float, offset: float) { // calc the day of the year var N1: float = Mathf.Floor(275.0 * date.Month /9.0); var N2: float = Mathf.Floor((date.Month +9.0)/12.0); var N3: float = 1 + Mathf.Floor((date.Year - 4 * Mathf.Floor(date.Year / 4) + 2) / 3); var N = N1 - (N2 * N3) + date.Day - 30; // convert the longitude to hour value and calculate an approximate time var lngHour: float = lng / 15.0; var tRise = N + ((6 - lngHour) / 24.0); var tSet = N + ((18 - lngHour) / 24.0); // calculate the Sun's mean anomaly var MRise = (0.9856 * tRise) - 3.289; var MSet = (0.9856 * tSet) - 3.289; // calculate the Sun's true longitude var LRise = MRise + (1.916 * Mathf.Sin(Mathf.PI/180.0 *MRise)) + (0.020 * Mathf.Sin(Mathf.PI/180.0 *2 * MRise)) + 282.634; var LSet = MSet + (1.916 * Mathf.Sin(Mathf.PI/180.0 *MSet)) + (0.020 * Mathf.Sin(Mathf.PI/180.0 *2 * MSet)) + 282.634; if(LRise < 0) { LRise += 360; } if(LSet < 0) { LSet += 360; } if(LRise >= 360) { LRise -= 360; } if(LSet >= 360) { LSet -= 360; } // calculate the Sun's right ascension var RARise = (180.0/Mathf.PI) * Mathf.Atan(0.91764 * Mathf.Tan(Mathf.PI/180.0 *LRise)); var RASet = (180.0/Mathf.PI) * Mathf.Atan(0.91764 * Mathf.Tan(Mathf.PI/180.0 *LSet)); if(RARise < 0) { RARise += 360; } if(RASet < 0) { RASet += 360; } if(RARise >= 360) { RARise -= 360; } if(RASet >= 360) { RASet -= 360; } // right ascension value needs to be in the same quadrant as L var LquadrantRise = (Mathf.Floor( LRise/90.0)) * 90; var RAquadrantRise = (Mathf.Floor(RARise/90.0)) * 90; RARise = RARise + (LquadrantRise - RAquadrantRise); var LquadrantSet = (Mathf.Floor( LSet/90.0)) * 90; var RAquadrantSet = (Mathf.Floor(RASet/90.0)) * 90; RASet = RASet + (LquadrantSet - RAquadrantSet); //right ascension value needs to be converted into hours RARise = RARise / 15.0; RASet = RASet / 15.0; //calculate the Sun's declination var sinDecRise = 0.39782 * Mathf.Sin(Mathf.PI/180.0 *LRise); var cosDecRise = Mathf.Cos(Mathf.PI/180.0 *(180.0/Mathf.PI) *Mathf.Asin(sinDecRise)); var sinDecSet = 0.39782 * Mathf.Sin(Mathf.PI/180.0 *LSet); var cosDecSet = Mathf.Cos(Mathf.PI/180.0 *(180.0/Mathf.PI) *Mathf.Asin(sinDecSet)); //calculate the Sun's local hour angle var cosHRise = (Mathf.Cos(Mathf.PI/180.0 *90.5) - (sinDecRise * Mathf.Sin(Mathf.PI/180.0 *lat))) / (cosDecRise * Mathf.Cos(Mathf.PI/180.0 *lat)); var cosHSet = (Mathf.Cos(Mathf.PI/180.0 *90.5) - (sinDecSet * Mathf.Sin(Mathf.PI/180.0 *lat))) / (cosDecSet * Mathf.Cos(Mathf.PI/180.0 *lat)); if (cosHRise > 1) return; if (cosHSet < -1) return; // finish calculating H and convert into hours var HRise =(360 - ( (180.0/Mathf.PI) *Mathf.Acos(cosHRise))); var HSet = (180.0/Mathf.PI) *Mathf.Acos(cosHSet); HRise = HRise / 15.0; HSet = HSet / 15.0; //calculate local mean time of rising/setting var TRise = HRise + RARise - (0.06571 * tRise) - 6.622; var TSet = HSet + RASet - (0.06571 * tSet) - 6.622; // adjust back to UTC var UTRise = TRise - lngHour; var UTSet = TSet - lngHour; if(UTRise < 0) { UTRise += 24; } else if(UTRise >= 24) { UTRise -= 24; } if(UTSet < 0) { UTSet += 24; } else if(UTSet >= 24) { UTSet -= 24; } // convert UT value to local time zone of latitude/longitude var RiseTime: float = UTRise + offset; var SetTime: float = UTSet + offset; if(RiseTime < 0) { RiseTime += 24; } else if(RiseTime >= 24) { RiseTime -= 24; } if(SetTime < 0) { SetTime += 24; } else if(SetTime >= 24) { SetTime -= 24; } // now you can use the RiseTime & SetTime as you wish }
if(LRise > 360)
ReplyDelete{
LRise -= 360;
Not accurate code. The more correct is as follows:
if(LRise >= 360.)
{
LRise -= 360.;
The same thing is with 24.
Thanks! In my haste I didn't notice
DeleteThank you!
ReplyDeletethank you!!
ReplyDeleteHow do you know what the offset should be? It seems that I have a UTC time but the local time is incorrect
ReplyDelete