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开发者_如何学Go 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.
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.
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.
Thanks for the question and I agree with your selection of @Pekka's as the correct one, but I had a similar problem with a different cause (which you touched on in your question) so I thought I would share.
I found that when using the same script that you have above, but with a set of different lat/long and time zone, it had the appearance of the sunrise / sunset and twilight values being inverted. This was as a result of the default timezone that was set in my php.ini file being incorrect. This can be found in the [Date]
section of the ini file and can be corrected (if required) by entering the correct timezone.
Most people (including yourself) will probably notice that the timezone will be off straight away because there is an obvious difference, but in my defense I was thrown off by the default timezone being 'UTC' and the one I was looking for being 'Pacific/Auckland' which is exactly opposite (timezone wise).
精彩评论