Commit 4bfa1114 by Demid Merzlyakov

Today parsing: fix moon-related information parsing.

parent 5ddfebfc
...@@ -37,8 +37,11 @@ struct WdtDailySummary: Codable { ...@@ -37,8 +37,11 @@ struct WdtDailySummary: Codable {
case precipitationProbability = "pop" case precipitationProbability = "pop"
case sunriseUtc = "solunar_sunrise_utc" case sunriseUtc = "solunar_sunrise_utc"
case sunsetUtc = "solunar_sunset_utc" case sunsetUtc = "solunar_sunset_utc"
case sunState = "solunar_sun_state"
case moonriseUtc = "solunar_moonrise_utc" case moonriseUtc = "solunar_moonrise_utc"
case moonsetUtc = "solunar_moonset_utc" case moonsetUtc = "solunar_moonset_utc"
case moonState = "solunar_moon_state"
case moonPhase = "moon_phase"
} }
private static let log = Logger(componentName: "WdtDailySummary") private static let log = Logger(componentName: "WdtDailySummary")
......
...@@ -32,39 +32,73 @@ struct WdtLocation: Codable { ...@@ -32,39 +32,73 @@ struct WdtLocation: Codable {
case hourlySummaries = "hourly_summaries" case hourlySummaries = "hourly_summaries"
} }
public func toAppModel(timeZone: TimeZone, updatedAt: Date) throws -> Location { private func enhance(today original: CurrentWeather, from daily: [DailyWeather], using timeZone: TimeZone) -> CurrentWeather {
var coordinates: CLLocationCoordinate2D? = nil var today = original
if let lat = CLLocationDegrees(lat ?? ""), let lon = CLLocationDegrees(lon ?? "") { var calendar = Calendar(identifier: .gregorian)
coordinates = CLLocationCoordinate2D(latitude: lat, longitude: lon) calendar.timeZone = timeZone
guard let startOfToday = calendar.date(bySettingHour: 0, minute: 0, second: 0, of: today.date) else {
return today
} }
var today = surfaceObservation.toAppModel(timeZone: timeZone, updatedAt: updatedAt) guard let indexOfToday = daily.firstIndex(where: { fabs($0.date.timeIntervalSince(startOfToday)) < 60 }) else {
let dailyWeather = try dailySummaries?.toAppModel(timeZone: timeZone, updatedAt: updatedAt) ?? [DailyWeather]() // although timestamps are exact, TimeInterval is Double, and I don't trust Double == comparisons... The 60 magic constant is taken as a kind of a domain-sensitive date comparison epsilon, 1 minute.
let hourlyWeather = try hourlySummaries?.toAppModel(timeZone: timeZone, updatedAt: updatedAt) ?? [HourlyWeather]() return today
if let todayInDaily = dailyWeather.first {
today?.minTemp = todayInDaily.minTemp
today?.maxTemp = todayInDaily.maxTemp
today?.precipitationProbability = todayInDaily.precipitationProbability
today?.sunState = todayInDaily.sunState ?? .normal
} }
let todayInDaily = daily[indexOfToday]
today.minTemp = todayInDaily.minTemp
today.maxTemp = todayInDaily.maxTemp
today.precipitationProbability = todayInDaily.precipitationProbability
today.sunState = todayInDaily.sunState ?? .normal
today.approximateMoonset = todayInDaily.moonset
let currentDate = Date() let currentDate = Date()
if let moonDay = dailyWeather.first(where: {
let absTimeFromToday = fabs(currentDate.timeIntervalSince($0.date)) // In CurrentWeather (which is what `today` is) we're only interested in moonrise / moonset pair that hasn't passed yet.
guard absTimeFromToday < TimeInterval(24 * 3600) else { // 24 hours else // Moonrise / moonset are available in daily in the WDT API.
// 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.
let dayWithNextMoonsetFilter: (DailyWeather) -> Bool = {
// not too efficient, but acceptable
guard let moonset = $0.moonset else {
return false return false
} }
guard let moonset = $0.moonset else { guard moonset > currentDate else {
return false return false
} }
return moonset > currentDate let dateWithin24Hours = fabs($0.date.timeIntervalSince(currentDate)) < TimeInterval(24 * 3600)
}) { guard dateWithin24Hours else {
#warning("Not implemented!") return false
//TODO: This logic is not correct, got to fix. }
today?.moonState = moonDay.moonState ?? .normal return true
today?.moonPhase = moonDay.moonPhase }
today?.moonrise = moonDay.moonrise
today?.moonset = moonDay.moonset if let indexOfDayWithNextMoonset = daily.firstIndex(where: dayWithNextMoonsetFilter) {
let moonsetDayInDaily = daily[indexOfDayWithNextMoonset]
var moonriseDayInDaily: DailyWeather? = nil
if indexOfDayWithNextMoonset > 0 {
moonriseDayInDaily = daily[indexOfDayWithNextMoonset - 1]
}
today.moonset = moonsetDayInDaily.moonset
today.moonPhase = moonsetDayInDaily.moonPhase
today.moonState = moonsetDayInDaily.moonState
today.moonrise = moonriseDayInDaily?.moonrise
}
return today
}
public func toAppModel(timeZone: TimeZone, updatedAt: Date) throws -> Location {
var coordinates: CLLocationCoordinate2D? = nil
if let lat = CLLocationDegrees(lat ?? ""), let lon = CLLocationDegrees(lon ?? "") {
coordinates = CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
let dailyWeather = try dailySummaries?.toAppModel(timeZone: timeZone, updatedAt: updatedAt) ?? [DailyWeather]()
let hourlyWeather = try hourlySummaries?.toAppModel(timeZone: timeZone, updatedAt: updatedAt) ?? [HourlyWeather]()
var todayOpt = surfaceObservation.toAppModel(timeZone: timeZone, updatedAt: updatedAt)
if let today = todayOpt {
todayOpt = enhance(today: today, from: dailyWeather, using: timeZone)
} }
return Location(deviceLocation: false, return Location(deviceLocation: false,
...@@ -79,7 +113,7 @@ struct WdtLocation: Codable { ...@@ -79,7 +113,7 @@ struct WdtLocation: Codable {
zip: zipcode, zip: zipcode,
fipsCode: nil, fipsCode: nil,
timeZone: timeZone, timeZone: timeZone,
today: today, today: todayOpt,
daily: dailyWeather, daily: dailyWeather,
hourly: hourlyWeather) hourly: hourlyWeather)
} }
......
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