@@ -455,7 +455,8 @@ struct MenuView: View {
455455 }
456456
457457 /// z.ai peak hours: 14:00–18:00 CST (UTC+8), i.e. 06:00–10:00 UTC.
458− /// Limits are most likely to bind during this window.
458+ /// Limits are most likely to bind during this window. Displayed in the
459+ /// user's local timezone so they know when to expect slowdowns.
459460 private var zaiPeakHours: some View {
460461 let inPeak = ViewModel.zaiInPeakHours
461462
@@ -464,12 +465,31 @@ struct MenuView: View {
464465 .fill(inPeak ? Color.orange : Color.secondary.opacity(0.4))
465466 .frame(width: 6, height: 6)
466467
467− Text(inPeak ? "Peak hours now" : "Peak 14:00–18:00 CST")
468+ Text(inPeak ? "Peak hours now" : "Peak \(Self.zaiPeakHoursLocal)")
468469 .font(Self.footnoteFont)
469470 .foregroundColor(inPeak ? .orange : .secondary)
470471 }
471472 }
472473
474+ /// z.ai peak hours converted to the user's local timezone, e.g. "09:00–13:00".
475+ private static var zaiPeakHoursLocal: String {
476+ let formatter = DateFormatter()
477+ formatter.timeZone = TimeZone.current
478+ formatter.dateFormat = "HH:mm"
479+
480+ var utc = DateComponents()
481+ utc.timeZone = TimeZone(identifier: "UTC")
482+ utc.hour = 6
483+ var calendar = Calendar(identifier: .gregorian)
484+ calendar.timeZone = TimeZone(identifier: "UTC")!
485+ let start = calendar.date(from: utc)!
486+
487+ utc.hour = 10
488+ let end = calendar.date(from: utc)!
489+
490+ return "\(formatter.string(from: start))–\(formatter.string(from: end))"
491+ }
492+
473493 /// Formats the time until a z.ai window resets, e.g. "3h 20m".
474494 private static func zaiResetsIn(from date: Date) -> String {
475495 let interval = date.timeIntervalSince(Date())