Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP date_sun_info wrong times

Tags:

php

time

I'm trying to use PHP's date_sun_info function to get information about the time of certain positions of the sun throughout the day:

At the moment I'm using code similar to that in the documentation.

$sun_info = date_sun_info(strtotime('today'), 40.42, 74.0);
foreach ($sun_info as $key => $val) {
    echo "$key: " . date("H:i:s", $val) . "<br>";
}

Output is:

sunrise: 20:50:20
sunset: 07:45:03
transit: 02:17:41
civil_twilight_begin: 20:22:45
civil_twilight_end: 08:12:38
nautical_twilight_begin: 19:51:01
nautical_twilight_end: 08:44:22
astronomical_twilight_begin: 19:19:28
astronomical_twilight_end: 09:15:55

Which is obviously wrong.

I'm unsure why this happens. Any help would be much appreciated.

I had thought that it is something to do with timezones? If so how should I correct for this? The timezone for the server is set to America/New_York which would be 5 hours behind GMT but even taking that into account the times cannot be right, unless I'm calculating this wrong.

like image 614
JoeR Avatar asked Dec 05 '25 23:12

JoeR


2 Answers

I think you mixed up the numbers. 40.42, 74.0 translates to a point in the mountains of Kyrgysztan. You probably meant 40.42, -74 for (approximately) New York?

As to why this happens, it seems like the function is indeed time zone sensitive, something that is not properly documented:

  • Kyrgyzstan is GMT+6
  • New York is GMT-5

that amounts to a difference of 11 hours.

Sunrise time at that point is 7:50 local time, 20:50 New York time.

like image 142
Pekka Avatar answered Dec 08 '25 12:12

Pekka


As @Pekka commented, this function is timezone-sensitive, and it can drive you crazy for a while until you find out.

In fact this function should have an extra parameter to pass the timezone, just like date_sunrise/date_sunset. Anyway, as a solution to be sure that all calculations are right, you must always do this ($timezone is the tz of the target location, where the lat/long points):

    // push tz
    $tz = date_default_timezone_get();
    date_default_timezone_set($timezone);
    $dsi = date_sun_info($timestamp, $latitude, $longitude);
    // pop tz
    date_default_timezone_set($tz);

The results are standard UTC based timestamps, and you must apply the $timezone to the results to get the proper (local) date and time:

    $dsi_tz = new DateTimeZone($timezone);
    $sunrise = new DateTime("@" . $dsi['civil_twilight_begin']);
    $sunrise->setTimezone($dsi_tz);
    echo $sunrise->format('Y-m-d H:i:s e');
    $sunset = new DateTime("@" . $dsi['civil_twilight_end']);
    $sunset->setTimezone($dsi_tz);
    echo $sunset->format('Y-m-d H:i:s e');

The rule of thumb to deal with timestamps and timezones is: ALL timestamps must be always read, stored and processed as UTC based, and timezones must be used only at the end of the chain, for representation. Messing with biased timestamps to make them local or adding offsets is a recipe for quite a bunch of headaches.

like image 37
Sobakus Avatar answered Dec 08 '25 11:12

Sobakus