ceeK / Solar

A Swift micro library for generating Sunrise and Sunset times.
MIT License
566 stars 82 forks source link

isDaytime and isNightTime return incorrect values for polar day #59

Open ddekanski opened 2 years ago

ddekanski commented 2 years ago

For places where there's a polar day in the given time/date (see the example), isDaytime returns false and isNightTime returns true for all times of day (just opposite to reality).

Code:

private func isSunUp(dateTime: Date, coords: LatLon) -> Bool {
    let solar = Solar(for: dateTime, coordinate: CLLocationCoordinate2D(latitude: coords.lat, longitude: coords.lon))
    return solar!.isDaytime
}

Params: dateTime: 2022-06-03 06:00:00 +0000 coords: lat: 67.94753132376813, lon: 13.131613209843637

daneden commented 4 months ago

I know this is an old bug, but I’ve been using Solar extensively for my project Solstice and polar days/nights are so tricky! I’ve figured out a workaround that involves checking whether the coordinates are within a polar circle:

import CoreLocation
import Solar

extension CLLocationCoordinate2D {
  var insideArcticCircle: Bool { latitude > 66.34 }
  var insideAntarcticCircle: Bool { latitude < -66.34 }
  var insidePolarCircle: Bool { insideArcticCircle || insideAntarcticCircle }
}

extension Solar {
  var isSunUp: Bool {
    if sunrise != nil && sunset != nil {
      return isDaytime
    }

    guard coordinate.insidePolarCircle else { return isDaytime }

    let month = Calendar.current.component(.month, from: date)

    switch month {
      case 1...3, 10…12:
        return coordinate.insideAntarcticCircle
      default:
        return coordinate.insideArcticCircle
    } 
  }
}

This works by:

  1. Returning isDaytime if there is a sunrise/sunset (which is how isDaytime works under the hood anyway)
  2. Checking whether the coordinates lie within a polar circle, and returning isDaytime if they don't
  3. Returning a boolean based on: a. Which polar circle the coordinates are in b. Whether the date lies within the northern hemisphere’s winter months