You are here

function _weather_calculate_sunrise_sunset in Weather 6.5

Same name and namespace in other branches
  1. 5.6 weather_parser.inc \_weather_calculate_sunrise_sunset()
  2. 7 weather_parser.inc \_weather_calculate_sunrise_sunset()

Calculate the times of sunrise and sunset

The times are GMT, so it's possible for the sunrise being at 16:48 while the sun sets at 7:06.

Parameters

array Parsed METAR data, will be altered:

1 call to _weather_calculate_sunrise_sunset()
weather_parse_metar in ./weather_parser.inc
Parses a raw METAR data string

File

./weather_parser.inc, line 482

Code

function _weather_calculate_sunrise_sunset(&$metar) {
  $info = weather_get_latitude_longitude($metar['icao']);

  // Use gmdate() so times are appropriate for gmmktime() used to
  // create new sunrise/sunset times below.
  $day_of_year = gmdate('z', $metar['reported_on']);
  $year = gmdate('Y', $metar['reported_on']);
  $month = gmdate('m', $metar['reported_on']);
  $day = gmdate('d', $metar['reported_on']);

  // setup pi constants: 0.5*pi, 1.0*pi, 1.5*pi, 2.0*pi
  $pi_05 = 1.570796;
  $pi_10 = 3.141593;
  $pi_15 = 4.712389;
  $pi_20 = 6.283185;

  // convert latitude and longitude degree into radian
  // x rad = y° * pi / 180 = 0.017453 * y°
  $latitude = 0.017453 * $info['latitude'];
  $longitude = 0.017453 * $info['longitude'];

  // we want always GMT time, so set to 0. Otherwise,
  // the timezone can be calculated as follows:
  // $timezone = 0.261799 * offset;
  $timezone = 0;

  // the sunrise/sunset altitude in radian (-0.833°)
  $altitude = -0.014539;
  $sunrise = 0;
  $sunset = 0;
  foreach (array(
    'sunrise' => $pi_05,
    'sunset' => $pi_15,
  ) as $type => $factor) {
    $a = $day_of_year + ($factor - $longitude) / $pi_20;

    // solar mean anomaly
    $sma = $a * 0.017202 - 0.0574039;

    // solar true longitude
    $stl = $sma + 0.0334405 * sin($sma);
    $stl += 4.93289 + 0.000349066 * sin(2 * $sma);

    // normalize the longitude to be between >= 0 and < 2.0*pi
    while ($stl < 0) {
      $stl += $pi_20;
    }
    while ($stl >= $pi_20) {
      $stl -= $pi_20;
    }
    if ($stl / $pi_05 - intval($stl / $pi_05) == 0) {
      $stl += 4.84814E-6;
    }

    // solar right ascension
    $sra = sin($stl) / cos($stl);
    $sra = atan2(0.9174600000000001 * $sra, 1);

    // adjust quadrant
    if ($stl > $pi_15) {
      $sra += $pi_20;
    }
    else {
      if ($stl > $pi_05) {
        $sra += $pi_10;
      }
    }

    // solar declination
    $sd = 0.39782 * sin($stl);
    $sd = $sd / sqrt(1 - $sd * $sd);
    $sd = atan2($sd, 1);
    $diurnal_arc = ($altitude - sin($sd) * sin($latitude)) / (cos($sd) * cos($latitude));

    // is there a sunrise or sunset at all?
    if ($diurnal_arc >= 1) {

      // no sunrise
      $no_sunrise = TRUE;
      break;
    }
    if ($diurnal_arc <= -1) {

      // no sunset
      $no_sunset = TRUE;
      break;
    }
    $diurnal_arc = $diurnal_arc / sqrt(1 - $diurnal_arc * $diurnal_arc);
    $diurnal_arc = $pi_05 - atan2($diurnal_arc, 1);
    if ($type == 'sunrise') {
      $diurnal_arc = $pi_20 - $diurnal_arc;
    }

    // calculate the time
    $localtime = $diurnal_arc + $sra - 0.0172028 * $a - 1.73364;

    // wall clock time
    $wallclock = $localtime - $longitude + $timezone;

    // normalize wallclock to be between >= 0 and < 2.0*pi
    while ($wallclock < 0) {
      $wallclock += $pi_20;
    }
    while ($wallclock >= $pi_20) {
      $wallclock -= $pi_20;
    }
    $wallclock = $wallclock * 3.81972;
    $hour = intval($wallclock);
    $minute = round(($wallclock - $hour) * 60, 0);
    if ($type == 'sunrise') {
      $sunrise = gmmktime($hour, $minute, 0, $month, $day, $year);
    }
    else {
      $sunset = gmmktime($hour, $minute, 0, $month, $day, $year);
    }
  }

  // handle special cases like no sunrise / sunset at all
  if (isset($no_sunset)) {
    $condition = 'day';
  }
  else {
    if (isset($no_sunrise)) {
      $condition = 'night';
    }
    else {

      // correctly handle northern and southern hemisphere
      if ($sunrise <= $sunset) {

        // this should be on the northern hemisphere
        if ($metar['reported_on'] >= $sunrise and $metar['reported_on'] < $sunset) {
          $condition = 'day';
        }
        else {
          $condition = 'night';
        }
      }
      else {

        // this should be on the southern hemisphere
        if ($metar['reported_on'] >= $sunrise or $metar['reported_on'] <= $sunset) {
          $condition = 'day';
        }
        else {
          $condition = 'night';
        }
      }
    }
  }
  $metar['daytime']['sunrise_on'] = $sunrise;
  $metar['daytime']['sunset_on'] = $sunset;
  if (isset($no_sunrise)) {
    $metar['daytime']['no_sunrise'] = TRUE;
  }
  else {
    $metar['daytime']['no_sunrise'] = FALSE;
  }
  if (isset($no_sunset)) {
    $metar['daytime']['no_sunset'] = TRUE;
  }
  else {
    $metar['daytime']['no_sunset'] = FALSE;
  }
  $metar['daytime']['condition'] = $condition;
}