Reputation: 521
I've gone over multiple questions and answers here on SO, but I can't seem to figure it out. I am essentially trying to check if it is night at a certain location (lat/lng) at a certain time.
So far, I managed to get the sunrise and sunset times at the particular location and then I am trying to compare it with the current time. I have a bit of a Cinderella situation where it works fine until midnight strikes.
I am creating my variables for comparison like this:
$currenttime = DateTime::createFromFormat('Y-m-d H:i', $templooptime);
$sunsettime = DateTime::createFromFormat('Y-m-d H:i', $sunsetfinal);
$sunrisetime = DateTime::createFromFormat('Y-m-d H:i', $sunrisefinal);
I am doing a simple IF statement like this:
if ($currenttime>$sunsettime) {
$nightminutes++;
}
This outputs the following:
Current Time:2020-09-22 23:58:00| Location: 50.1776906598,-51.077228098126 | Sunset Start: 2020-09-22 18:48:00 |Sunrise Start: 2020-09-22 06:45:00 | Night:287
Current Time:2020-09-22 23:59:00| Location: 50.202093865458,-50.984342445684 | Sunset Start: 2020-09-22 18:47:00 |Sunrise Start: 2020-09-22 06:44:00 | Night:288
Current Time:2020-09-23 00:00:00| Location: 50.226422634856,-50.891362177619 | Sunset Start: 2020-09-23 18:45:00 |Sunrise Start: 2020-09-23 06:46:00 | Night:0
Current Time:2020-09-23 00:01:00| Location: 50.25067682914,-50.798287405434 | Sunset Start: 2020-09-23 18:44:00 |Sunrise Start: 2020-09-23 06:45:00 | Night:0
When I change the logic to:
if ($currenttime>$sunsettime && $currenttime<$sunrisetime) {
$nightminutes++;
}
It outputs:
Current Time:2020-09-22 23:58:00| Location: 50.1776906598,-51.077228098126 | Sunset Start: 2020-09-22 18:48:00 |Sunrise Start: 2020-09-22 06:45:00 | Night:0
Current Time:2020-09-22 23:59:00| Location: 50.202093865458,-50.984342445684 | Sunset Start: 2020-09-22 18:47:00 |Sunrise Start: 2020-09-22 06:44:00 | Night:0
Current Time:2020-09-23 00:00:00| Location: 50.226422634856,-50.891362177619 | Sunset Start: 2020-09-23 18:45:00 |Sunrise Start: 2020-09-23 06:46:00 | Night:0
Current Time:2020-09-23 00:01:00| Location: 50.25067682914,-50.798287405434 | Sunset Start: 2020-09-23 18:44:00 |Sunrise Start: 2020-09-23 06:45:00 | Night:0
How can I solve this problem?
UPDATE Setting sunset time to one day ahead as per RO's answer, still has this issue:
Current Time:2020-09-22 23:59:00 | Location: 50.202093865458,-50.984342445684 | Sunset Start: 2020-09-22 18:47:00 | Sunrise Start: 2020-09-23 06:46:00 | Night:288
Current Time:2020-09-23 00:00:00 | Location: 50.226422634856,-50.891362177619 | Sunset Start: 2020-09-23 18:45:00 | Sunrise Start: 2020-09-24 06:47:00 | Night:0
When it crosses midnight, then the sunset time is LESS than current time so it shows false. Any ideas?
UPDATE 2 This is the basic code I am using (excerpts):
<?php
$fulltimestampdateforloop = new DateTime('2020-09-22 23:58:00');
$coords=["50.1776906598,-51.077228098126","50.202093865458,-50.984342445684","50.226422634856,-50.891362177619","50.25067682914,-50.798287405434"];
$nightmin=0;
$offset2=2;
foreach ($coords as $value) {
$latlng = explode(",", $value);
$lat = $latlng[0];
$lng = $latlng[1];
$str_timestamp = $fulltimestampdateforloop->format('Y-m-d');
$str_flighttime =$fulltimestampdateforloop->getTimestamp();
$sunsetTime_a = (clone $fulltimestampdateforloop);
$sunriseTime_a = (clone $fulltimestampdateforloop)->add(new DateInterval('P1D'));
$sunsetStr = date_sunset($sunsetTime_a->getTimestamp(), SUNFUNCS_RET_STRING, $lat, $lng, 90,$offset2);
$sunriseStr = date_sunrise($sunriseTime_a->getTimestamp(), SUNFUNCS_RET_STRING, $lat, $lng, 90,$offset2);
$ssettime = explode(":", $sunsetStr);
$sunsetStr_h = $ssettime[0];
$sunsetStr_m = $ssettime[1];
$srisetime = explode(":", $sunriseStr);
$sunriseStr_h = $srisetime[0];
$sunriseStr_m = $srisetime[1];
$sunsetTime_e = (clone $fulltimestampdateforloop)->setTime($sunsetStr_h,$sunsetStr_m);
$sunriseTime_e = (clone $fulltimestampdateforloop)->add(new DateInterval('P1D'))->setTime($sunriseStr_h,$sunriseStr_m);
if ($fulltimestampdateforloop > $sunsetTime_e && $fulltimestampdateforloop < $sunriseTime_e) {
$nightmin="Night";
} else{
$nightmin="Day";
}
echo 'Current Time:'.$fulltimestampdateforloop->format('Y-m-d H:i:s').' | Location: '.$lat.','.$lng.' | Sunset Start: '.$sunsetTime_e->format('Y-m-d H:i:s').' | Sunrise Start: '.$sunriseTime_e->format('Y-m-d H:i:s').' | Night or Day? : '.$nightmin."<br>";
$fulltimestampdateforloop->modify('+1 minutes');
}
?>
Upvotes: 0
Views: 546
Reputation: 2714
You've calculated your sunrise time to be before the sunset.
See this example for an illustration:
<?php
$today = new DateTime;
$randomAfternoonTime = (clone $today)->setTime(13, 25);
$randomNightTime = (clone $today)->add(new DateInterval('P1D'))->setTime(2, 23);
// Times relevant to Amsterdam on 2020-09-23.
// Sunset happens this evening.
$sunsetTime = (clone $today)->setTime(19, 36);
// Sunrise happens tomorrow, so add one day.
$sunriseTime = (clone $today)->add(new DateInterval('P1D'))->setTime(7, 30);
echo "Sunset at:\n" . $sunsetTime->format('Y-m-d H:i') . "\n\n";
echo "Sunrise at:\n" . $sunriseTime->format('Y-m-d H:i') . "\n\n";
echo "Some time in the afternoon (NOT in between sunset/sunrise):\n" . $randomAfternoonTime->format('Y-m-d H:i') . "\n\n";
echo "At night (in between sunset/sunrise):\n" . $randomNightTime->format('Y-m-d H:i') . "\n\n";
// Shows bool(false): 13:25 is not in between sunset/sunrise.
var_dump($randomAfternoonTime->getTimestamp() > $sunsetTime->getTimestamp() && $randomAfternoonTime->getTimestamp() < $sunriseTime->getTimestamp());
// Shows bool(true): 02:23 is in between sunset/sunrise.
var_dump($randomNightTime->getTimestamp() > $sunsetTime->getTimestamp() && $randomNightTime->getTimestamp() < $sunriseTime->getTimestamp());
See this 3v4l for a live demo: https://3v4l.org/lLUfL
UPDATE
I've taken the liberty of refactoring your code as shown below. I've purposely left in what I think is your logic bug. My code outputs the following:
Current Time: 2020-09-22 23:58:00 Location: 50.1776906598, -51.077228098126 Sunset Start: 2020-09-22 23:18:17 Sunrise Start: 2020-09-23 11:16:49 Night or day? : night
Current Time: 2020-09-22 23:59:00 Location: 50.202093865458, -50.984342445684 Sunset Start: 2020-09-22 23:17:55 Sunrise Start: 2020-09-23 11:16:27 Night or day? : night
Current Time: 2020-09-23 00:00:00 Location: 50.226422634856, -50.891362177619 Sunset Start: 2020-09-23 23:15:20 Sunrise Start: 2020-09-24 11:17:36 Night or day? : day
Current Time: 2020-09-23 00:01:00 Location: 50.25067682914, -50.798287405434 Sunset Start: 2020-09-23 23:14:57 Sunrise Start: 2020-09-24 11:17:14 Night or day? : day
Both 2020-09-23 00:00:00 and 2020-09-23 00:01:00 demonstrate the problem, where the comparison shouldn't be made on a UNIX timestamp, but on the time alone. Because both 00:01:00 and 00:00:00 are within the sunset/sunrise period ('night'), yet you're comparing full DateTimes. You're close. Let me know if you need any additional help.
Refactored code (with bug purposely left in it):
<?php
$referenceDateTime = new DateTime('2020-09-22 23:58:00');
$coordinates =
[
[ 50.1776906598, -51.077228098126 ],
[ 50.202093865458, -50.984342445684 ],
[ 50.226422634856, -50.891362177619 ],
[ 50.25067682914, -50.798287405434 ]
];
foreach ($coordinates as $coordinate)
{
[ $lat, $long ] = $coordinate;
$sunsetDateTime = (clone $referenceDateTime)->setTimestamp(date_sunset($referenceDateTime->getTimestamp(), SUNFUNCS_RET_TIMESTAMP, $lat, $long, 90, 2));
$sunriseDateTime = (clone $referenceDateTime)->setTimestamp(date_sunrise((clone $referenceDateTime)->add(new DateInterval('P1D'))->getTimestamp(), SUNFUNCS_RET_TIMESTAMP, $lat, $long, 90, 2));
$daySegment = ($referenceDateTime > $sunsetDateTime && $referenceDateTime < $sunriseDateTime)?'night':'day';
echo "Current Time: {$referenceDateTime->format('Y-m-d H:i:s')}\nLocation: $lat, $long\nSunset Start: {$sunsetDateTime->format('Y-m-d H:i:s')}\nSunrise Start: {$sunriseDateTime->format('Y-m-d H:i:s')}\nNight or day? : $daySegment\n\n";
$referenceDateTime->add(new DateInterval('PT1M'));
}
UPDATE 2
Wanted to figure it out myself, so went along and wrote up the following that will help you think along the right lines:
<?php
$referenceHour = 22;
$referenceMinute = 31;
$sunsetHour = 23;
$sunsetMinute = 50;
$sunriseHour = 7;
$sunriseMinute = 30;
$referenceHour -= ($referenceHour < 12)?-12:12;
$sunsetHour -= ($sunsetHour < 12)?-12:12;
$sunriseHour -= ($sunriseHour < 12)?-12:12;
$referenceTime = ($referenceHour * 60) + $referenceMinute;
$sunsetTime = ($sunsetHour * 60) + $sunsetMinute;
$sunriseTime = ($sunriseHour * 60) + $sunriseMinute;
$daySegment = ($referenceTime >= $sunsetTime && $referenceTime <= $sunriseTime)?'night':'day';
echo "Reference time: " . sprintf('%02d:%02d', $referenceHour, $referenceMinute) . ", sunset time: " . sprintf('%02d:%02d', $sunsetHour, $sunsetMinute) . ", sunrise time: " . sprintf('%02d:%02d', $sunriseHour, $sunriseMinute) . ", night/day: $daySegment\n";
Upvotes: 2