WWDC Quick Look đź’“ By SwiftGGTeam
Bring context to today's weather

Bring context to today's weather

Watch original video

Highlight

WeatherKit adds Changes and Historical Comparisons queries, helping your weather app evolve from “displaying numbers” to “interpreting weather changes.”


Core Content

Open a weather app and you usually see temperature, humidity, and wind speed. Users have to draw their own conclusions: Is today colder than yesterday? Will it suddenly cool down tomorrow? An experience that makes users compare on their own is really a failure of data presentation—the app has the data but does not interpret it for the user.

This year’s WeatherKit updates address that pain point directly. The new Changes query returns upcoming temperature and precipitation changes, including the time window when the change occurs and the direction (rising/falling/steady). The Historical Comparisons query compares current weather against more than 50 years of historical averages, with results sorted by deviation significance. Apple’s own Weather app already uses both queries: Changes highlights “sharp temperature drop tomorrow” on the home screen, and Historical Comparisons shows “today’s high is 3°C above the historical average.”

Beyond these two new queries, forecast data itself is getting finer. Current conditions and hourly forecasts now include cloud cover by altitude, hourly forecasts add hourly precipitation amounts, daily forecasts can be split into day/night parts, and high/low humidity is returned. Apple Weather has been using this data all along; third-party developers can now access it too. The REST API also adds FlatBuffers binary format support, reducing payload size by up to 25% and parsing time by up to 90% compared to compressed JSON.

Detailed Content

Hourly Precipitation

On the Swift side, fetching hourly precipitation only requires specifying an .hourly query and accessing the precipitationAmount property (02:40):

let hourlyPrecipitation = try await WeatherService()
    .weather(for: .newYork, including: .hourly)
    .map(\.precipitationAmount)

Key points:

  • WeatherService().weather(for:including:) is WeatherKit’s main query entry point; the including parameter specifies the dataset
  • .hourly requests an hourly forecast and returns an array of HourlyForecast
  • .map(\.precipitationAmount) uses a key path to extract hourly precipitation directly, skipping other fields

Equivalent REST call (03:25):

https://weatherkit.apple.com/api/v2/weather/en-US/40.710/-74.006?dataSets=forecastHourly&relativeHourlyStart=0&relativeHourlyEnd=1&hourlyRelativeTo=now&timezone=America/New_York

Key points:

  • dataSets=forecastHourly specifies an hourly forecast request
  • relativeHourlyStart and relativeHourlyEnd specify the range using relative time; Apple Weather Service calculates start and end times based on the timezone you pass in
  • When no range is specified, 24 hours are returned by default; up to 240 hours can be requested

Changes Query

Fetch upcoming weather changes (06:05):

let changes = try await WeatherService()
   .weather(for: .newYork, including: .changes)

let lowTemperatureChanges = changes?
   .filter(\.date.isTomorrow)
   .map(\.lowTemperature)

if let lowTemperatureChanges, lowTemperatureChanges.contains(.decrease) {
   // Lower temperatures expected tomorrow
}

Key points:

  • .changes is the new query type and returns a WeatherChanges object
  • Each change includes startDate, endDate, and a change type (such as increase, decrease, steady)
  • The example filters low-temperature changes occurring tomorrow; if .decrease is included, notify the user

On the REST side, only dataSets=weatherChanges is needed (06:43). Each returned change object includes startDate, endDate, and type (such as highTemperatureIncrease). Results are returned even when there is no significant change, with type set to steady.

Historical Comparisons Query

Compare today’s weather against historical averages (08:17):

let mostSignificant = try await WeatherService()
    .weather(for: .newYork, including: .historicalComparisons)?
    .first

switch mostSignificant {
case .highTemperature(let trend), .lowTemperature(let trend):
    // Display temperature trend
    break
case .some, .none:
    break
}

Key points:

  • .historicalComparisons returns a comparison list sorted by deviation significance
  • .first takes the most significant deviation
  • Each comparison includes currentValue (current value), baselineValue (historical baseline), deviationType (deviation level: withinNormalRange/higher/muchHigher/lower/muchLower), and baselineType (statistical method, currently mean)

Statistics API: Historical Averages and Daily Summary

The new Statistics API provides two queries. Historical Averages returns long-term averages since 1970 (monthly example, 11:11):

let averagePrecipitation = try await WeatherService()
    .monthlyStatistics(
        for: .newYork,
        startMonth: 1,
        endMonth: 12,
        including: .precipitation
    )

let averagePrecipitationAmountsPerMonth = Dictionary(
    grouping: averagePrecipitation,
    by: \.month
)

Key points:

  • monthlyStatistics fetches historical averages by month; month numbers are 1–12
  • Results grouped by month are used by Apple Weather to show monthly precipitation averages

Daily Summary returns a weather summary for any past day (back to August 1, 2021) (12:52):

let pastThirtyDaysSummary = try await WeatherService()
    .dailySummary(
       for: .newYork,
       forDaysIn: DateInterval(start: .thirtyDaysAgo, end: .now),
       including: .precipitation
    )
    .first

if let pastThirtyDaysSummary {
    // We have a daily weather summary for each day in the past 30 days
}

Key points:

  • dailySummary accepts a date interval and returns a summary for each day in that range
  • Summaries include high/low temperature, precipitation, and snowfall
  • Apple Weather uses this to show accumulated precipitation over the past 30 days

FlatBuffers Binary Format

The REST API adds FlatBuffers support (14:16). Compared to compressed JSON, payload size is reduced by up to 25% and parsing time by up to 90%. The Swift API benefits from this optimization automatically; on the REST side, specify FlatBuffers in the Accept request header to activate it.

Core Takeaways

  • What to build: Add an “Upcoming Changes” card to the weather home screen. Call the Changes query, filter temperature and precipitation changes within the next 24–48 hours, and display entries containing .increase or .decrease with prominent styling. Why it’s worth doing: When users open a weather app, what they care about most is “how tomorrow differs from today”—this card answers that directly. How to start: The .changes query return values include startDate and type; the frontend only needs simple filtering and rendering.

  • What to build: Add a “compared to historical average” label for today’s weather. Call the Historical Comparisons query, take entries where deviationType is not withinNormalRange, and display copy such as “today’s high is 3°C above the historical average.” Why it’s worth doing: 28°C alone gives no context; knowing “the average for this month is 22°C” does. How to start: Each object returned by .historicalComparisons has currentValue and baselineValue; subtract to generate the copy.

  • What to build: Show monthly precipitation averages for travel destinations on a trip planning page. Call the Statistics API’s monthlyStatistics, request full-year precipitation data, and present it with a bar chart or calendar heatmap. Why it’s worth doing: Users planning trips need to know rainy and dry seasons—pure forecast data cannot provide that. How to start: One call to monthlyStatistics(for:startMonth:endMonth:including:), group by month, and feed directly to your chart component.

  • What to build: Adopt FlatBuffers in REST API integration to reduce transfer and parsing overhead. If your weather app backend frequently calls the WeatherKit REST API for large amounts of historical data, add FlatBuffers to the Accept header. Why it’s worth doing: In high-volume scenarios (such as 30-day daily summaries), 25% smaller payloads and 90% faster parsing directly improve user experience. How to start: Specify FlatBuffers format in REST request headers; no changes needed on the Swift API side.

Comments

GitHub Issues · utterances