我已经在这个问题上咀嚼了一段时间。我认为我正在努力努力,不断绕圈跑来跑去。
问题
我需要在夜间计算月光的时间,即月亮在白天之外的时间。众所周知,在给定的日期中,UTC的日出/日落和月球/月球时间。最简单的(催眠)场景是以下内容:
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
结构之间的月光和日光小时之间的相移是一场噩梦。因此,我希望有人对这个问题有重新考虑。任何帮助将不胜感激。
编辑
这是我根据@Ilmari Karonen
的建议提出的解决方案。这将在给定日历日期(使用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;
当您有复杂的问题时,将其分解为更简单的步骤通常很有用:
步骤1:,如有必要,将太阳/月亮/设置时间转换为可以使用算术的适当的DateTime值。第二以来,自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:计算月光时期的长度(s)。
这只是简单的DateTime减法。请注意,如果在给定的夜晚完全不可见月球,则减法可能会产生负值,在这种情况下,您应将结果夹为零。
如果您要对特定日历日期进行计算,则应对上一个和第二天晚上重复此操作,然后将(非负)结果添加在一起。
您可以将其转换为自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
如果您只想计算月光的量,例如如果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个日期执行此操作,从那里您可以执行您在帖子开头提到的计算。