5

Note: this is a exercise for my curiosity and there are existing functions / code that solve this problem (see comments too)

An algorithm for calculation of sunrise and sunset times can be found here and implementations at 1 in Tcl and 2 in javascript.

I am trying to convert the algorithm to PHP, but it's slightly over my head and takes too much time. This is my result so far:

<?php
$sunrise = sunriseSunsetTimeTest(9, 4, 2015, 46.929512, 7.565272);
$sunset = sunriseSunsetTimeTest(9, 4, 20, 46.929512, 7.565272, 'sunset');

echo $sunrise . '/' . $sunset;
/* output is: 12.314714533758/12.612340511889 (?) */

function sunriseSunsetTimeTest($day, $month, $year, $latitude, $longitude,
                                    $which='sunrise', $localTimeOffset=1, $zenith=96){
    /*
     * Output:
     * sunrise or sunset time depending on parameter $which
     *
     * Input:
     * (int) day
     * (int) month
     * (int) year
     * (float) latitude_degree
     * (float) longitude_degree
     * (string) which -> "sunrise" or "sunset (resp. not 'sunrise')"
     * (int) localTimeOffset (0 for GMT, 1 for CET, etc.)
     * (float) zenith_degree
     *      offical = 90 degrees 50'
     *      civil = 96 degrees
     *      nautical = 102 degrees
     *      astronomical = 108 degrees
     */
    $dayOfYear = dayOfYear($day, $month, $year);
    // convert the longitude to hour value and calculate an approximate time
    $lngHour = $longitude / 15;
    $approximateTime = ($which=='sunrise')
        ? $dayOfYear + ((6 - $lngHour) / 24)
        : $dayOfYear + ((18 - $lngHour) / 24);
    // calculate the Sun's mean anomaly
    $sunMeanAnomaly = (0.9856 * $approximateTime) - 3.289;
    // calculate the Sun's true longitude
    $sunTrueLongitude = $sunMeanAnomaly + (1.916 * sin($sunMeanAnomaly)) + (0.020 * sin(2 * $sunMeanAnomaly)) + 282.634;
    while ($sunTrueLongitude>360)
        $sunTrueLongitude -= 360;
    while ($sunTrueLongitude<0)
        $sunTrueLongitude += 360;
    // calculate the Sun's right ascension
    $sunRightAscension = rad2deg(atan(0.91764 * tan(deg2rad($sunTrueLongitude))));
    while ($sunRightAscension>360)
        $sunRightAscension -= 360;
    while ($sunRightAscension<0)
        $sunRightAscension += 360;
    // right ascension value needs to be in the same quadrant as true longitude
    $sunTrueLongitudeQuadrant  = (floor($sunTrueLongitude/90)) * 90;
    $sunRightAscensionQuadrant = (floor($sunRightAscension/90)) * 90;
    $sunRightAscension = $sunRightAscension + ($sunTrueLongitudeQuadrant - $sunRightAscensionQuadrant);
    // right ascension value needs to be converted into hours
    $sunRightAscension = $sunRightAscension / 15;
    // calculate the Sun's declination
    $sunSinDec = 0.39782 * sin(deg2rad($sunTrueLongitude));
    $sunCosDec = cos(asin($sunSinDec));
    // calculate the Sun's local hour angle
    $cosH = (cos(deg2rad($zenith)) - ($sunSinDec * sin(deg2rad($latitude)))) / ($sunCosDec * cos(deg2rad($latitude)));
    // finish calculating H and convert into hours
    if ($which=='sunrise'){
        if ($cosH > 1) //sun never rises on this location (on the specified date)
            return false;
        $H = 360 - acos($cosH);
    }
    else{
        if ($cosH < -1) // sun never sets on this location (on the specified date)
            return false;
        $H = acos($cosH);
    }
    $H = $H / 15;
    // calculate local mean time of rising/setting
    $T = $H + $sunRightAscension - (0.06571 * $approximateTime) - 6.622;
    // adjust back to UTC
    $UT = $T - $lngHour;
    while ($UT>24)
        $UT -= 24;
    while ($UT<0)
        $UT += 24;
    // convert UT value to local time zone of latitude/longitude
    $localT = $UT + $localTimeOffset;
    return $localT;
}

function dayOfYear($day,$month,$year){
    $N1 = floor(275 * $month / 9);
    $N2 = floor(($month + 9) / 12);
    $N3 = (1 + floor(($year - 4 * floor($year / 4) + 2) / 3));
    return $N1 - ($N2 * $N3) + $day - 30;
}

...the Input of date 09-04-2015, latitude 46.929512, longitude 7.565272 results in the outputs 12.314714533758 for sunrise and 12.612340511889 for sunset.

I would like to understand what is wrong in the code, maybe somebody can help. Thanks!

marcell
  • 1,498
  • 1
  • 10
  • 22
mch
  • 1,259
  • 15
  • 23
  • 3
    Why not simply use the built-in [date_sunrise()](http://php.net/manual/en/function.date-sunrise.php) and [date_sunset()](http://php.net/manual/en/function.date-sunset.php) functions? – Mark Baker Apr 09 '15 at 10:23
  • It's a exercise for me... want to improve my math knowledge. – mch Apr 09 '15 at 10:25
  • Try to point out the part of the code that produce described output (sample usage example). Then add expected output to your question. That way you will probably get an answer faster because it would be easier for readers to understand what you trying to achieve without reading the whole code. – Whirlwind Apr 09 '15 at 10:32
  • 2
    Quick hint: convert everything to radians at the beginning; it will make your life a lot easier. I think one (not necessarily the only one) of your problems is `360 - acos($cosH);` which seems to mix degrees and radians (I don't know PHP very well, so feel free to ignore me if I'm broadcasting my ignorance) – k_g Apr 10 '15 at 22:28
  • This was my first try, converted lat, lng and zenith to radians at the beginning of the script with deg2rad(). Without success unfortunately. – mch Apr 11 '15 at 07:15
  • Did you find the solution since then? – marcell Dec 17 '17 at 10:57

0 Answers0