Updating Time Text Label Each Minute in Widgetkit

Updating time text label each minute in WidgetKit

A possible solution is to use the time date style:

/// A style displaying only the time component for a date.
/// Text(event.startDate, style: .time)
/// Example output:
/// 11:23PM
public static let time: Text.DateStyle

  1. You need a simple Entry with a Date property:
struct SimpleEntry: TimelineEntry {
let date: Date

  1. Create an Entry every minute until the next midnight:
struct SimpleProvider: TimelineProvider {

func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
var entries = [SimpleEntry]()
let currentDate = Date()
let midnight = Calendar.current.startOfDay(for: currentDate)
let nextMidnight = Calendar.current.date(byAdding: .day, value: 1, to: midnight)!

for offset in 0 ..< 60 * 24 {
let entryDate = Calendar.current.date(byAdding: .minute, value: offset, to: midnight)!
entries.append(SimpleEntry(date: entryDate))

let timeline = Timeline(entries: entries, policy: .after(nextMidnight))

  1. Display the date using the time style:
struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry

var body: some View {
Text(entry.date, style: .time)

If you want to customise the date format you can use your own DateFormatter:

struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry

static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "HH:mm"
return formatter

var body: some View {
Text("\(entry.date, formatter: Self.dateFormatter)")

Here is a GitHub repository with different Widget examples including the Clock Widget.

SwiftUI and WidgetKit - Automatically updating components

According to Apple's documentation, the only self-updating SwiftUI view is Text, configured to display a relative date or time. See Displaying Dynamic Dates in Widgets for details.

The options are:

Text(futureDate, style: .relative)
Text(futureDate, style: .offset)
Text(futureDate, style: .timer)
Text(aprilFirstDate, style: .date)
Text("Date: \(aprilFirstDate, style: .date)")
Text(startDate ... endDate)
Text("The meeting will take place: \(startDate ... endDate)")

Can't refresh WidgetView every minute

I also tried refreshing every second with only refresing the date to
show current time, but its stops refreshing after couple of seconds.

You only have a limited number of refreshes available to your Widget. If you call WidgetCenter.shared.reloadAllTimelines() every second, your Widget is likely to run out of available updates very quickly.

Also, you shouldn't call reloadAllTimelines() in getTimeline():

WidgetCenter.shared.reloadAllTimelines() // remove this

Then I tried this code below from @pawello2222 but widgets are not
loading correctly with it

I assume you're referring to this answer: Updating time text label each minute in WidgetKit

Note that in your code guard let may not pass through:

for offset in 0 ..< 60 * 24 {
guard let widget = try? JSONDecoder().decode([myWidgets].self, from: widgetData) // you need `else { ... return }` here
let entryDate = Calendar.current.date(byAdding: .minute, value: offset, to: midnight)!
entries.append(widgetEntry(date: entryDate, widget: widget[0]))

See: When to use guard let rather than if let

WidgetKit @StateObject not updating View

Widgets are static, the view you provide on getTimeline is what will be displayed as is and won't be updated, so the call to fetchSchedule on onAppear won't even be executed. Once you execute the completion handler in getTimeline, no more code is executed.

To display data on your widgets you need to fetch your data in getTimeline, create a view that displays the data from the start, and return that entry in your completion handler.

In your last example I would suggest that you create your entry in the completion handler of model.fetchSchedule and pass the schedule object to your view.

Related Topics

Leave a reply