Commit 91b67642 by Demid Merzlyakov

Fix moonrise / moonset.

parent fccd6f5e
...@@ -32,8 +32,8 @@ public struct CurrentWeather: Equatable, Hashable { ...@@ -32,8 +32,8 @@ public struct CurrentWeather: Equatable, Hashable {
public var sunState: CelestialState? = .normal public var sunState: CelestialState? = .normal
public var moonrise: Date? public var moonrise: Date?
public var moonset: Date? public var moonset: Date?
/// An approximate moonset value that can be used to draw animation when usual moonset is not available. Do not show this value to the user as actual time. /// An approximate moonrise value that can be used to draw animation when usual moonrise is not available. Do not show this value to the user as actual time.
public var approximateMoonset: Date? public var approximateMoonrise: Date?
public var moonState: CelestialState? = .normal public var moonState: CelestialState? = .normal
public var moonPhase: MoonPhase? = .unknown public var moonPhase: MoonPhase? = .unknown
} }
...@@ -70,6 +70,7 @@ extension CurrentWeather: UpdatableModelObjectInTime { ...@@ -70,6 +70,7 @@ extension CurrentWeather: UpdatableModelObjectInTime {
result.moonset = incrementalChanges.moonset ?? result.moonset result.moonset = incrementalChanges.moonset ?? result.moonset
result.moonState = incrementalChanges.moonState ?? result.moonState result.moonState = incrementalChanges.moonState ?? result.moonState
result.moonPhase = incrementalChanges.moonPhase ?? result.moonPhase result.moonPhase = incrementalChanges.moonPhase ?? result.moonPhase
result.approximateMoonrise = incrementalChanges.approximateMoonrise ?? result.approximateMoonrise
return result return result
} }
......
...@@ -27,9 +27,9 @@ public struct DailyWeather: Equatable, Hashable { ...@@ -27,9 +27,9 @@ public struct DailyWeather: Equatable, Hashable {
public var sunset: Date? public var sunset: Date?
public var sunState: CelestialState? = .normal public var sunState: CelestialState? = .normal
/// Note: this is when the moon rises in the evening. So, moonset < moonrise. It's different in CurrentWeather. /// Note: moonrise can be before moonset or after it, or a day before or after. I love WDT...
public var moonrise: Date? public var moonrise: Date?
/// Note: this is when the moon sets in the morning. So, moonset < moonrise. It's different in CurrentWeather. /// Note: moonset can be before moonrise or after it, or a day before or after. I love WDT...
public var moonset: Date? public var moonset: Date?
public var moonState: CelestialState? = .normal public var moonState: CelestialState? = .normal
public var moonPhase: MoonPhase? = .unknown public var moonPhase: MoonPhase? = .unknown
......
...@@ -47,43 +47,66 @@ struct WdtLocation: Codable { ...@@ -47,43 +47,66 @@ struct WdtLocation: Codable {
today.minTemp = todayInDaily.minTemp today.minTemp = todayInDaily.minTemp
today.maxTemp = todayInDaily.maxTemp today.maxTemp = todayInDaily.maxTemp
today.precipitationProbability = todayInDaily.precipitationProbability today.precipitationProbability = todayInDaily.precipitationProbability
today.sunState = todayInDaily.sunState ?? .normal today.sunState = todayInDaily.sunState
today.approximateMoonset = todayInDaily.moonset today.approximateMoonrise = todayInDaily.moonrise?.addingTimeInterval(-24 * 3600) // -24 hours
let currentDate = Date()
// In CurrentWeather (which is what `today` is) we're only interested in moonrise / moonset pair that hasn't passed yet. // In CurrentWeather (which is what `today` is) we're only interested in moonrise / moonset pair that hasn't passed yet.
// Moonrise / moonset are available in daily in the WDT API. // Moonrise / moonset are available in daily in the WDT API.
// And in DailyWeather moonset happens in the morning, before the moonrise in the evening. // And in DailyWeather moonset happens in the morning, before the moonrise in the evening.
// So, we need to find the first moonset in daily that hasn't passed (and that isn't too far from the current date). The day before it (if we have it) will contain the corresponding moonrise. // So, we need to find the first moonset in daily that hasn't passed (and that isn't too far from the current date). The day before it (if we have it) will contain the corresponding moonrise.
let dayWithNextMoonsetFilter: (DailyWeather) -> Bool = { enum MoonType: CustomDebugStringConvertible {
// not too efficient, but acceptable case rise
guard let moonset = $0.moonset else { case set
return false
var debugDescription: String {
return self == .rise ? "rise" : "set"
} }
guard moonset > currentDate else {
return false
} }
let dateWithin24Hours = fabs($0.date.timeIntervalSince(currentDate)) < TimeInterval(24 * 3600)
guard dateWithin24Hours else { struct MoonEvent {
return false var type: MoonType
let date: Date
let phase: MoonPhase?
let state: CelestialState?
init?(type: MoonType, phase: MoonPhase?, state: CelestialState?, date: Date?) {
guard let date = date else { return nil }
self.type = type
self.date = date
self.phase = phase
self.state = state
} }
return true
} }
if let indexOfDayWithNextMoonset = daily.firstIndex(where: dayWithNextMoonsetFilter) { let allMoonrises: [MoonEvent] = daily.compactMap { MoonEvent(type: .rise, phase: $0.moonPhase, state: $0.moonState, date: $0.moonrise) }
let moonsetDayInDaily = daily[indexOfDayWithNextMoonset] let allMoonsets: [MoonEvent] = daily.compactMap { MoonEvent(type: .set, phase: $0.moonPhase, state: $0.moonState, date: $0.moonset) }
var moonriseDayInDaily: DailyWeather? = nil
if indexOfDayWithNextMoonset > 0 { let currentDate = Date()
moonriseDayInDaily = daily[indexOfDayWithNextMoonset - 1] let allMoonEvents: [MoonEvent] = (allMoonrises + allMoonsets)
.filter({ fabs($0.date.timeIntervalSince(currentDate)) < TimeInterval(24 * 3600) }) // +-24 hours from current date
.sorted(by: { $1.date > $0.date })
let nextMoonsetFilter: (MoonEvent) -> Bool = {
$0.type == .set && $0.date > currentDate
}
if let indexOfNextMoonset = allMoonEvents.firstIndex(where: nextMoonsetFilter) {
let nextMoonset = allMoonEvents[indexOfNextMoonset]
today.moonset = nextMoonset.date
today.moonPhase = nextMoonset.phase
today.moonState = nextMoonset.state
if indexOfNextMoonset > 0 && allMoonEvents[indexOfNextMoonset - 1].type == .rise {
today.moonrise = allMoonEvents[indexOfNextMoonset - 1].date
} }
today.moonset = moonsetDayInDaily.moonset
today.moonPhase = moonsetDayInDaily.moonPhase
today.moonState = moonsetDayInDaily.moonState
today.moonrise = moonriseDayInDaily?.moonrise
} }
//TODO: finish debugging, doesn't work properly.
return today return today
} }
......
...@@ -131,23 +131,31 @@ class MoonPhaseCell: UITableViewCell { ...@@ -131,23 +131,31 @@ class MoonPhaseCell: UITableViewCell {
//Public //Public
public func configure(with location:Location) { public func configure(with location:Location) {
MoonPhaseCell.dateFormatter.timeZone = location.today?.timeZone let today = location.today // for convenience
MoonPhaseCell.nowDateFormatter.timeZone = location.today?.timeZone MoonPhaseCell.dateFormatter.timeZone = today?.timeZone
moonTypeLabel.text = location.today?.moonPhase?.localized MoonPhaseCell.nowDateFormatter.timeZone = today?.timeZone
moonTypeLabel.text = today?.moonPhase?.localized
guard guard
let moonrise = location.today?.moonrise, let moonrise = today?.moonrise ?? today?.approximateMoonrise,
let moonset = location.today?.moonset let moonset = today?.moonset
else { else {
return return
} }
if today?.moonrise != nil {
// it's not approximate moonrise
moonriseTimeLabel.text = MoonPhaseCell.dateFormatter.string(from: moonrise) moonriseTimeLabel.text = MoonPhaseCell.dateFormatter.string(from: moonrise)
}
else {
moonriseTimeLabel.text = ""
}
moonsetTimeLabel.text = MoonPhaseCell.dateFormatter.string(from: moonset) moonsetTimeLabel.text = MoonPhaseCell.dateFormatter.string(from: moonset)
let moonTimePeriod = moonset.timeIntervalSince1970 - moonrise.timeIntervalSince1970
let moonTimePeriod = moonset.timeIntervalSince(moonrise)
let nowString = MoonPhaseCell.nowDateFormatter.string(from: Date()) let nowString = MoonPhaseCell.nowDateFormatter.string(from: Date())
let nowDate = MoonPhaseCell.nowDateFormatter.date(from: nowString) ?? Date() let nowDate = MoonPhaseCell.nowDateFormatter.date(from: nowString) ?? Date()
self.moonProgress = CGFloat((nowDate.timeIntervalSince1970 - moonrise.timeIntervalSince1970) / moonTimePeriod) self.moonProgress = CGFloat(nowDate.timeIntervalSince(moonrise) / moonTimePeriod)
} }
public func updateMoonPosition() { public func updateMoonPosition() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment