2014-02-06 2 views
2

Я долгое время искал эту проблему. Я думаю, что я слишком стараюсь и бегаю по кругу.Алгоритм расчета ночных часов лунного света

Проблеме

мне нужно вычислить часы лунных в ночное время, т.е. количества времени Луны над горизонтом вне часов дневного света. Известны времена восхода/захода солнца и лунного восхода/луны в UTC на заданную дату. Самый простой сценарий (hypthetical) заключается в следующем:

sunrise: 06:45 
sunset: 18:20 
moonrise: 02:30 
moonset: 19:50 

алгоритма для расчета лунных часов будет:

if(moonrise<sunset && sunrise<moonset) { 
    moonlighthours = (sunrise-moonrise)-(moonset-sunset); 
} 

Столь же легко:

sunrise: 06:45 
sunset: 18:20 
moonrise: 10:30 
moonset: 19:50 

if(moonrise>sunset && sunrise<moonset) { 
    moonlighthours = (moonset-sunset); 
} 

Но, как мы имеем дело с UTC он может стать довольно сложным в зависимости от часового пояса, поскольку восход/установка и время восхода/захода могут быть растянуты на три разные даты:

sunrise: 2014-02-05 23:30 
sunset: 2014-02-06 12:20 
moonrise: 2014-02-06 11:00 
moonset: 2014-03-07 00:50 

Так рассчитать лунные часы для 2014-02-06 Я хотел бы попробовать что-то свернутое, как это:

if(sunrise<midnight) { sunrise = midnight; } 
if(sunset>midnight+24) { sunset = midnight+24; } 
if(moonrise<midnight) { moonrise = midnight; } 
if(moonset>midnight+24) { moonset = midnight+24 } 

if(moonrise<sunset && sunrise<moonset) { 
    moonlighthours = (sunrise-moonrise)-(moonset-sunset); 
} else if (moonrise>sunset && sunrise<moonset) { 
    moonlighthours = (moonset-sunset); 
} else if (moonrise<sunset && sunrise>moonset) { 
    moonlighthours = (sunrise-moonrise); 
} else { 
    moonlighthours=0; 
} 

Попытку охватить все возможные сценарии в результате фазового сдвига между лунными и дневными часами использование структур if... else - кошмар. Поэтому я надеюсь, что есть кто-то со свежим решением проблемы. Любая помощь будет принята с благодарностью.

EDIT

Вот решение, которое я придумал на основе предложений @Ilmari Karonen «s. Это Расчитайте лунными часов в течение заданного календарной даты (с использованием синтаксиса PHP):

$mid00 = midnight;   // unixtimestamp , e.g. 1391558400 (2014-02-05 00:00:00) 
$mid24 = midnight+86399;  // 1399075199 (2014-02-05 23:59:59) 

$mr  = moonrise; 
$ms  = moonset; 
$sr  = sunrise; 
$ss  = sunset; 

$mr = $mr < $mid00 ? $mid00 : $mr; 
$ms = $ms > $mid24 ? $mid24 : $ms; 
$sr = $sr < $mid00 ? $mid00 : $sr; 
$ss = $ss > $mid24 ? $Mid24 : $ss; 

$ml_morn = 0; // moonlight hours during morning night 
$ml_even = 0; // moonlight hours during evening night 

if($ms > $mr) {          // moon set later than moon rise 
    $ml_morn = $mr < $sr ? $sr-$mr : 0;    // moon rises before sunrise? 
    $ml_even = $ms > $ss ? $ms-$ss : 0;    // moon sets after sunset? 
} else {            // moon set before moon rise 
    $ml_even = $mr > $ss ? $mid24-$mr : $mid24 - $ss; // moon rises before sunset? 
    $ml_morn = $ms < $sr ? $ms-$mid00 : $sr - $mid00; // moon sets before sunrise? 
} 

moonlight_hours = $ml_morn = $ml_even; 
+3

Лунный свет? – bonCodigo

+0

??? -Я этого не понимаю. – Tomm

+0

До сегодняшнего дня я знал только летнее время ... думал, что Солнце всегда было важным, по сравнению с редко встречающимися кругами Луны, когда-то 28 дней ..;) – bonCodigo

ответ

1

Если у вас есть сложная проблема, это часто бывает полезно разбить его на более простые шаги:

Шаг 1: При необходимости преобразования ВС/Moonrise/установленное время в соответствующих значений даты и времени, что вы можете сделать арифметику. Во-вторых, начиная с эпохи Unix (или минут с начала тысячелетия или чего-то еще), но если ваш язык имеет подходящий класс или тип datetime, я бы рекомендовал его использовать.

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

Шаг 2: Найдите начальное и конечное время периода (ов) лунного света.

Если вы хотите, чтобы лунный свет часов в течение одного ночи, то вы можете рассчитать начало и конец лунного периода, как:

start = max(moonrise, sunset) 
end = min(sunrise, moonset) 

Если вам действительно нужны лунный свет часов в течение одного календарных дня , это немного сложнее, так как могут быть два отдельных периода лунного света. Вы можете вычислить их соответствующие начальные и конечные разы:

start1 = max(moonrise1, sunset1, midnight) 
end1 = min(sunrise1, moonset1) 
start2 = max(moonrise2, sunset2) 
end1 = min(sunrise2, moonset2, midnight + 24 hours) 

где имена переменных, заканчивающиеся в 1 обозначают соответствующие времена для ночи перед тем данного дня, и имена переменных, заканчивающиеся в 2 обозначают соответствующие времена на ночь после данного дня.

Шаг 3: Рассчитайте длину (и) периодов (периодов) лунного света.

Это просто вычитание даты и времени. Обратите внимание, что вычитание может дать отрицательное значение, если луна вообще не видна в заданную ночь, и в этом случае вы должны зажать результат до нуля.

Если вы делаете расчеты для определенной даты календаря, вы должны повторить это как для предыдущей, так и для следующей ночи, а затем добавить вместе (неотрицательные) результаты.

+0

Это еще сложнее, чем второй фрагмент кода под Шагом 2. Потому что ваше решение предполагает, что за каждый день у нас синхронная луна и солнце поднимаются. Но на самом деле, если вы посмотрите даты календаря (часовой пояс UTC!) у вас могут быть случаи, когда в хронологическом порядке у вас есть что-то вроде «луна»> восход солнца> закат> восход луны »или даже« закат> восход луны> восход солнца> луны ». Но ваше предложение поставило меня на правильный путь (я отредактирую сообщение, чтобы показать алгоритм, который я придумал). Спасибо за ваши усилия, очень ценим! – Tomm

0

Если вы только хотите вычислить сумму лунного света, то вы можете преобразовать всю дату одним целым числом, представляющим количество минут после определенной даты, например если D является объектом дата и D.year, D.month, D.day, D.hour, D.minute представляет собой структуру даты (это просто псевдо-код), и предположим, что 01-01-2010 00:00 время 0, то счетчик минут должен быть рассчитан как

total_minutes = ((D.year - 2010) * 60*60*24*365) + (D.month * 60*60*24) + (D.day * 60*60) + (D.hour * 60) + D.minutes;

Сделайте это для всех 4 дат, которые вы упомянули, и оттуда вы можете выполнить вычисления, как вы упомянули в начале своего сообщения.

0

Вы можете конвертировать его в считанные секунды с 1970 года и вычитать результаты.

tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + 
(tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - 
((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400 
Смежные вопросы