В PHP проверьте, есть ли время между заходом и восходом солнца

#php #time

#php #время

Вопрос:

Я рассмотрел несколько вопросов и ответов здесь, на SO, но, похоже, я не могу в этом разобраться. По сути, я пытаюсь проверить, наступила ли ночь в определенном месте (широта / lng) в определенное время.

До сих пор мне удавалось получить время восхода и захода солнца в определенном месте, а затем я пытаюсь сравнить его с текущим временем. У меня немного ситуация с Золушкой, когда все работает нормально, пока не пробьет полночь.

Я создаю свои переменные для сравнения следующим образом:

 
    $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);
  

Я делаю простой оператор IF следующим образом:

     if ($currenttime>$sunsettime) {
       $nightminutes  ;
    }
  

Это выводит следующее:

 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
  

Когда я меняю логику на:

 if ($currenttime>$sunsettime amp;amp; $currenttime<$sunrisetime) {
    $nightminutes  ;
}
  

Он выводит:

 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
  

Как я могу решить эту проблему?

ОБНОВЛЕНИЕ, устанавливающее время захода солнца на один день вперед в соответствии с ответом RO, все еще имеет эту проблему:

 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
  

Когда оно пересекает полночь, время захода солнца МЕНЬШЕ текущего времени, поэтому оно показывает false. Есть идеи?

ОБНОВЛЕНИЕ 2 Это базовый код, который я использую (выдержки):

 <?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 amp;amp; $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');
    }
?>
  

Ответ №1:

Вы рассчитали время восхода солнца до захода солнца.

Смотрите Этот пример для иллюстрации:

 <?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') . "nn";
echo "Sunrise at:n" . $sunriseTime->format('Y-m-d H:i') . "nn";

echo "Some time in the afternoon (NOT in between sunset/sunrise):n" . $randomAfternoonTime->format('Y-m-d H:i') . "nn";
echo "At night (in between sunset/sunrise):n" . $randomNightTime->format('Y-m-d H:i') . "nn";

// Shows bool(false): 13:25 is not in between sunset/sunrise.
var_dump($randomAfternoonTime->getTimestamp() > $sunsetTime->getTimestamp() amp;amp; $randomAfternoonTime->getTimestamp() < $sunriseTime->getTimestamp());

// Shows bool(true): 02:23 is in between sunset/sunrise.
var_dump($randomNightTime->getTimestamp() > $sunsetTime->getTimestamp() amp;amp; $randomNightTime->getTimestamp() < $sunriseTime->getTimestamp());
  

Смотрите этот 3v4l для живой демонстрации: https://3v4l.org/lLUfL

Обновить

Я взял на себя смелость провести рефакторинг вашего кода, как показано ниже. Я намеренно оставил то, что я считаю вашей логической ошибкой. Мой код выводит следующее:

Текущее время: 2020-09-22 23:58:00 Местоположение: 50.1776906598, -51.077228098126 Начало захода солнца: 2020-09-22 23:18:17 Начало восхода солнца: 2020-09-23 11:16:49 Ночью или днем? : ночь

Текущее время: 2020-09-22 23:59:00 Местоположение: 50.202093865458, -50.984342445684 Начало захода солнца: 2020-09-22 23:17:55 Начало восхода солнца: 2020-09-23 11:16:27 Ночь или день? : ночь

Текущее время: 2020-09-23 00:00:00 Местоположение: 50.226422634856, -50.891362177619 Начало захода солнца: 2020-09-23 23:15:20 Начало восхода солнца: 2020-09-24 11:17:36 Ночью или днем? : день

Текущее время: 2020-09-23 00:01:00 Местоположение: 50.25067682914, -50.798287405434 Начало захода солнца: 2020-09-23 23:14:57 Начало восхода солнца: 2020-09-24 11:17:14 Ночью или днем? : день

И 2020-09-23 00:00:00, и 2020-09-23 00: 01:00 демонстрируют проблему, когда сравнение должно производиться не по метке времени UNIX, а только по времени. Поскольку и 00: 01:00, и 00:00:00 находятся в пределах периода захода / восхода солнца («ночь»), но вы сравниваете полные даты и время. Вы близки. Дайте мне знать, если вам понадобится дополнительная помощь.

Переработанный код (с намеренно оставленной в нем ошибкой):

 <?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 amp;amp; $referenceDateTime < $sunriseDateTime)?'night':'day';
    
    echo "Current Time: {$referenceDateTime->format('Y-m-d H:i:s')}nLocation: $lat, $longnSunset Start: {$sunsetDateTime->format('Y-m-d H:i:s')}nSunrise Start: {$sunriseDateTime->format('Y-m-d H:i:s')}nNight or day? : $daySegmentnn";
    
    $referenceDateTime->add(new DateInterval('PT1M'));
}
  

ОБНОВЛЕНИЕ 2

Хотел разобраться в этом сам, поэтому пошел и написал следующее, что поможет вам думать в правильном направлении:

 <?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 amp;amp; $referenceTime <= $sunriseTime)?'night':'day';

echo "Reference time: " . sprintf('d:d', $referenceHour, $referenceMinute) . ", sunset time: " . sprintf('d:d', $sunsetHour, $sunsetMinute) . ", sunrise time: " . sprintf('d:d', $sunriseHour, $sunriseMinute) . ", night/day: $daySegmentn";
  

Комментарии:

1. А, понятно! Так должен ли я затем добавить один день к текущему времени и рассчитать восход солнца на следующий день?

2. ДА. Вы можете использовать add метод для DateTime объекта, который принимает DateInterval объект. Его конструктор принимает строку в определенном формате . Вы, скорее всего, хотите P1D . Пожалуйста, подумайте о том, чтобы отметить мой ответ как принятый, если он был полезен :).

3. Идеальный. Не могу поверить, как я это пропустил, большое спасибо, Ro, действительно ценю это.

4. Просто попробовал, и та же проблема возникает после полуночи, поскольку время восхода солнца больше текущего времени.

5. Я намеренно сделал свое добавление немного многословным, чтобы вы могли видеть шаги. Они должны быть достаточно самокомментирующимися. Вы можете подключить эту логику к своему коду, и все должно быть готово. Если это сработает, то, пожалуйста, подумайте о том, чтобы отметить мой ответ как принятый 🙂