I’m making an attempt to make use of weatherKit to get the dawn and sundown in order that I can change the WeatherConditionIcons relying upon if the time is earlier than or after dawn and sundown. Initially I used to be simply getting day time icons however not I’m solely receiving night time time icons. I used a debugging line to get the dawn and sundown time to print. Nonetheless, the dawn and sundown time are printing that they’re occurring 4 hours after the precise dawn and sundown. Right here is the code I’ve proper now:
@MainActor
class WeatherData: ObservableObject {
static let shared = WeatherData()
let service = WeatherService.shared
@Revealed var currentWeather: CurrentWeather?
@Revealed var hourlyForecast: [HourWeather] = []
@Revealed var dailyForecast: [DayWeather] = []
@Revealed var cityName: String = ""
@Revealed var sunEvents: SunEvents?
func updateWeather(for location: CLLocation) {
Job {
do {
let currentForecast = attempt await service.climate(for: location, together with: .present)
await MainActor.run {
self.currentWeather = currentForecast
}
let dailyForecast = attempt await service.climate(for: location, together with: .each day)
await MainActor.run {
self.dailyForecast = dailyForecast.forecast
if let firstDayWeather = dailyForecast.forecast.first {
self.sunEvents = firstDayWeather.solar
}
}
} catch {
print("Didn't fetch climate information: (error)")
}
}
}
}
struct HourlyForecastView: View {
@ObservedObject var weatherData: WeatherData
var physique: some View {
VStack {
if let startDate = weatherData.hourlyForecast.first?.date, let endDate = weatherData.hourlyForecast.final?.date {
HStack {
Textual content("(formatDate(startDate)) to (formatDate(endDate))")
.font(.caption)
}
.padding([.leading, .trailing])
}
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 20) {
ForEach(weatherData.hourlyForecast, id: .date) { hourWeather in
VStack(spacing: 5) {
Textual content(hourWeatherFormatter.string(from: hourWeather.date))
.font(.caption)
Picture(systemName: weatherData.getWeatherConditionIcon(for: hourWeather.situation, at: hourWeather.date))
.foregroundColor(.blue)
Textual content("(hourWeather.precipitationChance * 100, specifier: "%.0f%%")")
.font(.caption)
.foregroundColor(.blue)
Textual content("(hourWeather.temperature.worth, specifier: "%.1f°")")
.font(.caption)
}
.body(width: 40, top: 105)
}
}
.background(RoundedRectangle(cornerRadius: 7).fill(Coloration.grey.opacity(0.2)))
}
}
}
personal var hourWeatherFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "ha"
formatter.amSymbol = "AM"
formatter.pmSymbol = "PM"
return formatter
}
personal func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter.string(from: date)
}
}
extension WeatherData {
func getWeatherConditionIcon(for situation: WeatherCondition, at time: Date) -> String {
guard let sunEvents = dailyForecast.first?.solar else {
print("No SunEvents information accessible, defaulting to daytime icons.")
return getDefaultIcon(for: situation, isDaytime: true)
}
print("Dawn: (String(describing: sunEvents.dawn)), Sundown: (String(describing: sunEvents.sundown)), Present Time: (time)")
let isDaytime: Bool
if let dawn = sunEvents.dawn, let sundown = sunEvents.sundown {
isDaytime = time >= dawn && time <= sundown
} else {
isDaytime = true
}
return getDefaultIcon(for: situation, isDaytime: isDaytime)
}
personal func getDefaultIcon(for situation: WeatherCondition, isDaytime: Bool) -> String {
change situation {
case .clear:
return isDaytime ? "solar.max.fill" : "moon.stars.fill"
case .cloudy:
return "cloud.fill"
case .drizzle, .rain:
return isDaytime ? "cloud.drizzle.fill" : "cloud.drizzle.fill.bolt"
case .snow:
return "snow"
case .sleet:
return "cloud.sleet.fill"
case .hail:
return "cloud.hail.fill"
case .thunderstorms, .scatteredThunderstorms, .strongStorms:
return "cloud.bolt.rain.fill"
case .foggy:
return "cloud.fog.fill"
case .partlyCloudy:
return isDaytime ? "cloud.solar.fill" : "cloud.moon.fill"
case .mostlyCloudy:
return "cloud.fill"
case .mostlyClear:
return isDaytime ? "solar.max.fill" : "moon.stars.fill"
case .windy, .breezy:
return "wind"
case .smoky:
return "smoke.fill"
case .haze:
return isDaytime ? "solar.haze.fill" : "moon.haze.fill"
case .blowingDust:
return "solar.mud.fill"
case .heavyRain:
return "cloud.heavyrain.fill"
case .sunShowers:
return isDaytime ? "solar.rain.fill" : "moon.rain.fill"
case .isolatedThunderstorms:
return "cloud.bolt.rain.fill"
case .tropicalStorm, .hurricane:
return "hurricane"
case .blizzard, .blowingSnow, .heavySnow:
return "snowflake"
case .frigid:
return "thermometer.snowflake"
case .sizzling:
return "thermostat.solar"
case .wintryMix:
return "cloud.snow.fill"
default:
return "questionmark.circle.fill"
}
}
}