title: Algorithm to calculate nightly hours of moonlight
body: <p>I have been chewing on this problem for quite a while. I think I'm trying too hard and keep running around in circles. </p>
  
  <p><strong>The Problem</strong></p>
  
  <p>I need to calculate the hours of moonlight at night, i.e. the amount of time the moon is over the horizon outside the daylight hours. What is known are the sunrise/sunset and moonrise/moonset times in UTC for a given date. The easiest (hypthetical) scenario is the following:</p>
  
  <pre><code>sunrise:  06:45
  sunset:   18:20
  moonrise: 02:30
  moonset:  19:50
  </code></pre>
  
  <p>The algorithm to calculate moonlight hours would be:</p>
  
  <pre><code>if(moonrise&lt;sunset &amp;&amp; sunrise&lt;moonset) {
     moonlighthours = (sunrise-moonrise)-(moonset-sunset);
  }
  </code></pre>
  
  <p>Equally easy:</p>
  
  <pre><code>sunrise:  06:45
  sunset:   18:20
  moonrise: 10:30
  moonset:  19:50
  
  if(moonrise&gt;sunset &amp;&amp; sunrise&lt;moonset) {
     moonlighthours = (moonset-sunset);
  }
  </code></pre>
  
  <p>But as we're dealing with UTC it can get quite complicated depending on the time zone as sunrise/set and moonrise/set times might be stretched across three different dates:</p>
  
  <pre><code>sunrise:  2014-02-05 23:30 
  sunset:   2014-02-06 12:20
  moonrise: 2014-02-06 11:00
  moonset:  2014-03-07 00:50
  </code></pre>
  
  <p>So to calculate the moonlight hours for 2014-02-06 I would try something convoluted like this:</p>
  
  <pre><code>if(sunrise&lt;midnight)    { sunrise  = midnight;    }
  if(sunset&gt;midnight+24)  { sunset   = midnight+24; }
  if(moonrise&lt;midnight)   { moonrise = midnight;    }
  if(moonset&gt;midnight+24) { moonset  = midnight+24  }
  
  if(moonrise&lt;sunset &amp;&amp; sunrise&lt;moonset) {
     moonlighthours = (sunrise-moonrise)-(moonset-sunset);
  } else if (moonrise&gt;sunset &amp;&amp; sunrise&lt;moonset) {
     moonlighthours = (moonset-sunset);
  } else if (moonrise&lt;sunset &amp;&amp; sunrise&gt;moonset) {
     moonlighthours = (sunrise-moonrise);
  } else {
     moonlighthours=0;
  } 
  </code></pre>
  
  <p>Trying to cover all possible scenarios as a result of the phase shift between moonlight and daylight hours using <code>if... else</code> structures is a nightmare. So I am hoping that there is someone with a fresh take on the problem. Any help would be greatly appreciated.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>Here is the solution I have come up with based on <code>@Ilmari Karonen</code>'s suggestions. This will caclulate the moonlight hours during a given calendar date (using PHP syntax):</p>
  
  <pre><code>$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 &lt; $mid00 ? $mid00 : $mr;
  $ms = $ms &gt; $mid24 ? $mid24 : $ms;
  $sr = $sr &lt; $mid00 ? $mid00 : $sr;
  $ss = $ss &gt; $mid24 ? $Mid24 : $ss;
  
  $ml_morn = 0;   // moonlight hours during morning night
  $ml_even = 0;   // moonlight hours during evening night
  
  if($ms &gt; $mr) {                                      // moon set later than moon rise 
     $ml_morn = $mr &lt; $sr ? $sr-$mr : 0;               // moon rises before sunrise?
     $ml_even = $ms &gt; $ss ? $ms-$ss : 0;               // moon sets after sunset?
  } else {                                             // moon set before moon rise
    $ml_even = $mr &gt; $ss ? $mid24-$mr : $mid24 - $ss;  // moon rises before sunset?
    $ml_morn = $ms &lt; $sr ? $ms-$mid00 : $sr - $mid00;  // moon sets before sunrise? 
  }
  
  moonlight_hours = $ml_morn = $ml_even;
  </code></pre>