My application engages the following:
- Generates and properly displays a selected location with MapKit.
- Generates SwiftUI WeatherKit information for a selected MapKit location.
- Generates correct Timezone WeatherKit [DayWeather] Sunrise and Sunset times within my timezone using the [ForEach] function.
- Generates incorrect Timezone WeatherKit [DayWeather] using the ForEach function, while retrieving Sunrise and Sunset times outside of my timezone.
I modified my MapKit application to locate and retrieve weather information at specified locations. The application correctly illustrates all the weather information views I want to display without issue for a MapKit selected location. One view exception presents itself specific to the [ForEach] function inside a WeatherKit view, which retrieves Sunrise and Sunset information. The retrieved Sunrise and Sunset times for a selected timezone location outside of my identified timezone are not correct. My application does not generate nor apply an incorrect timezone identifier, such as [Europe/Paris] anywhere within the application, but the following view code segment surely hiccups.
The selected timezone location view presents the Sunrise and Sunset time information as an equivalent time within my timezone, displayed in the images below.
The issue happens to be within the view's following ForEach function code:
Text(day.sun.sunrise?.formatted(.dateTime.hour().minute()) ?? "?")
For the moment, I am struggling to discover how to correct the above code to properly display the [Sunrise] and [Sunset] times within a [ForEach] function. I do not know whether this issue happens to be inherent to WeatherKit's ForEach function, but most likely I am not properly applying the code to reflect the selected location's timezone format within the [Text]. I have not found a solution to apply within the [ForEach] function to correct this issue, as the application iterates through the supplied WeatherKit DayWeather information.
I know I can retrieve the correct current TimeZone time for a selected location with the following code:
func main() {
let d = Date()
// Show the [VARIABLE f] as [HOUR / MINUTE] such as [12:23PM]
var f = Date.FormatStyle.dateTime.hour().minute()
print("The [LOCAL TIME ZONE TIME with MAIN] :: \(d.formatted(f))")
f.timeZone = TimeZone(identifier: "Europe/Paris")!
print("The [SELECTED TIME ZONE TIME with MAIN] :: \(d.formatted(f))\n")
}
// Call the function
main()
The above code does not solve my application's issue, because the code simply returns the selected location's current timezone time relative to my current timezone time. So, if my timezone time happens to be 1:40 PM, then the above code generates a timezone time for a selected location, such as Paris to be 9:40 PM. I know a [View] does not respond to the incremental function code, such as stated above.
As a side note :: My application displays the WeatherKit information through a Container and Hosting Controller, where the application's SwiftUI ContentView calls ::
if let dailyForecast {
TestForecastView(dailyForecast: dailyForecast, timezone: timezone)
}
If you have a moment, I appreciate your possible corrective suggestions, which would be very welcome ... :]
Best regards,
jim_k
My TestForecastView Code with the attached generated views follow:
import Foundation
import SwiftUI
import CoreLocation
import WeatherKit
struct TestForecastView: View {
let dailyForecast: Forecast<DayWeather>
let timezone: TimeZone
var body: some View {
Spacer()
.frame(height: 10)
Text("Sunrise Sunset")
.font(.system(size: 24, weight: .bold))
.foregroundStyle(.white)
Text("Ten Day Forecast")
.font(.system(size: 11, weight: .medium))
.foregroundStyle(.white)
Spacer()
.frame(height: 4)
VStack {
ForEach(dailyForecast, id: \.date) { day in
LabeledContent {
HStack(spacing: 20) {
RoundedRectangle(cornerRadius: 10)
.fill(Color.orange.opacity(0.5))
.frame(width: 120, height: 5)
.padding(.leading, 2)
.padding(.trailing, 0)
VStack {
Image(systemName: "sunrise")
.font(.system(size: 24.0, weight: .bold))
.foregroundColor(.yellow)
Text(day.sun.sunrise?.formatted(.dateTime.hour().minute()) ?? "?")
.font(.system(size: 10.0))
}
.frame(width: 50, height: 20)
VStack {
Image(systemName: "sunset")
.font(.system(size: 24.0, weight: .bold))
.foregroundColor(.yellow)
Text(day.sun.sunset?.formatted(.dateTime.hour().minute()) ?? "?")
.font(.system(size: 10.0))
}
.frame(width: 50, height: 20)
Spacer()
.frame(width: 2)
}
} label: {
Text(day.date.localDate(for: timezone))
.frame(width: 80, alignment: .leading)
.padding(.leading, 30)
.padding(.trailing, 0)
}
.frame(width: 380, height: 52)
.background(RoundedRectangle(cornerRadius: 4).fill(LinearGradient(gradient: Gradient(colors: [Color(.systemBlue), Color(.black)]), startPoint: .topLeading, endPoint: .bottomTrailing)).stroke(.black, lineWidth: 6).multilineTextAlignment(.center))
.shadow(color: Color.white.opacity(0.1), radius: 4, x: -2, y: -2)
.shadow(color: Color.white.opacity(0.1), radius: 4, x: 2, y: 2)
}
}
.padding(.top, 20)
.padding(.bottom, 20)
.padding(.leading, 20)
.padding(.trailing, 20)
.contentMargins(.all, 4, for: .scrollContent)
.background(RoundedRectangle(cornerRadius: 10).fill(Color.black.opacity(0.0)).stroke(.gray, lineWidth: 4))
} // End of [var body: some View]
} // End of [struct TestForecastView: View]
My resultant code views ::
Calgary
Paris
Hi Jim,
To get the time in the local time zone, you must set the time zone you want on the Date.FormatStyle
you pass to formatted
.
Quinn has a nice example of that here: https://forums.developer.apple.com/forums/thread/700213.
If you want to do this inline, assuming your timezone
variable is the time zone of the location you are displaying, you can make a helper function like this:
var dateFormat -> Date.FormatStyle {
let formatStyle = Date.FormatStyle.dateTime.hour().minute()
formatStyle.timeZone = self.timezone
return formatStyle
}
Then replace lines like this:
Text(day.sun.sunrise?.formatted(.dateTime.hour().minute()) ?? "?")
With something like this:
Text(day.sun.sunrise?.formatted(dateFormat) ?? "?")
Hope that helps!