Radu Dan
iOS calendars — current vs autoupdatingCurrent

iOS calendars — current vs autoupdatingCurrent

Motivation

With SwiftUI continuing to evolve since its debut at WWDC19, it’s clear how much it’s shaping the future of iOS development. But today, let's shift gears and focus on a core topic: calendars.

If you're curious about how to handle dates and times effectively in Swift, let's dive into the Calendar API and explore its practical uses.

This article will help you understand the differences between calendar.current and calendar.autoupdatingCurrent and when to use them.

Setting up

When working with calendars in iOS, we have two primary methods to access the user's calendar settings: .current and .autoupdatingCurrent.

According to Apple's documentation, these methods serve different purposes. The .current method provides a snapshot of calendar settings at the time of access, remaining static even if the user modifies their settings later. In contrast, .autoupdatingCurrent creates a dynamic reference that automatically reflects any changes the user makes to their preferred calendar settings.

Let's explore these differences with a practical example. You can either create a new project by selecting Single View App (File > New > Project > Single View App) or download my complete example from GitHub.

For this tutorial, I've chosen to implement the example using SwiftUI, Apple's modern declarative framework for building user interfaces. If you're new to SwiftUI, don't worry - the concepts we'll cover are straightforward and the code is easy to follow.

⚠️ Important: This tutorial requires a physical iOS device to test the calendar and time zone changes. The iOS Simulator cannot properly demonstrate these features as it doesn't fully replicate the device's system settings behavior.

Here's how your view should look:

Calendar Example

The code for this view is as follows:

struct ContentView: View {
    // State variable that will update the UI when changed
    @State private var outputText: String = "Tap a button to display calendar information"
    
    // Initialize two different calendar instances
    private let currentCalendar = Calendar.current
    private let autoupdatingCalendar = Calendar.autoupdatingCurrent

    // ... other code ...
}

The UI is built using a VStack (vertical stack) with three main components:

  • A text display area
  • "Current Calendar" button
  • "Autoupdating Calendar" button

The code for this view is as follows:

var body: some View {
    VStack(spacing: 20) {
        // Output text display
        Text(outputText)
            .padding()
            .multilineTextAlignment(.center)
            .frame(maxWidth: .infinity)
        
        // Two buttons with different styling
        Button(action: {
            displayCalendarInfo(from: currentCalendar)
        }) {
            Text("Show Current Calendar")
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(10)
        }
        // ... similar button for autoupdating calendar
        }
    }

The displayCalendarInfo function does the heavy lifting:

private func displayCalendarInfo(from calendar: Calendar) {
    // Get current date components
    let comps = calendar.dateComponents(
        [.year, .month, .day, .hour, .minute, .second],
        from: Date()
    )
    
    // Format time with leading zeros for single digits
    let time: (hour: Int, minute: Int) = (comps.hour ?? 0, comps.minute ?? 0)
    let hours = time.hour < 10 ? "0\(time.hour)" : "\(time.hour)"
    let minutes = time.minute < 10 ? "0\(time.minute)" : "\(time.minute)"
    
    // Build the output string
    var output = "Calendar: \(calendar.identifier)\n"
    output += "Time Zone: \(calendar.timeZone.identifier)\n"
    output += "\(hours):\(minutes)"
    
    // Update the UI
    outputText = output
}

Run the app and see what you get. Be sure to use a real device for this.

Understanding calendars

At first glance, you might assume that the key distinction between .current and .autoupdatingCurrent lies in how they handle time setting changes - with .autoupdatingCurrent reflecting updates while .current remains static. Let's test this assumption and see what actually happens.

Start by opening the app and tapping either button. You should see an output label displaying something like: Calendar: gregorian Time Zone: Europe/London 09:28. To experiment with the calendar settings, navigate to your device's settings menu: Settings > General > Date & Time. Once there, locate and disable the Set Automatically switch.

⚠️ Note: If you find that the Set Automatically option is disabled (grayed out), you'll need to turn off Screen Time first. Go to Settings > Screen Time > Turn Off Screen Time to enable manual date and time adjustments.

Date and Time Settings

Change the time to an hour or two earlier or later. For example, my current time was 09:28, and I updated it to 10:28.

Date and Time Settings

Go back to the app and press the buttons again. Surprised? Both buttons update the label to reflect the new time!
Why does .current also update? Shouldn't only .autoupdatingCurrent respond to the time change?

Setting time zone

Let's experiment further by changing the time zone. Navigate back to your device settings and tap on Time Zone. In the search field, type Bucharest and select it from the results.

Now, return to the app and let's carefully observe how each calendar type handles this change.

First, tap the Calendar autoupdatingCurrent button. You'll notice that the label immediately updates to reflect the new time zone:
Calendar: gregorian Time Zone: Europe/Bucharest 11:29.

Next, tap the Calendar current button. Here's where it gets interesting - the label still shows the original time zone:
Calendar: gregorian Time Zone: Europe/London 09:29.

This experiment beautifully demonstrates the key difference between these two approaches: .autoupdatingCurrent dynamically adapts to any changes made to the date and time settings in real-time, while .current maintains its initial configuration throughout the app's lifecycle. It's worth noting that this behavior isn't unique to calendars - the same principle applies to other Foundation objects like Locale and TimeZone, making it a consistent pattern across iOS development.

Conclusion

Working with dates and times can be tricky, so understanding the differences between .current and .autoupdatingCurrent is crucial when designing your APIs.

Here's when to use each approach:

Use .autoupdatingCurrent when you need to:

  • Always display the current date and time based on the user's latest settings
  • Reflect changes in time zone, region, or locale settings in real-time
  • Build apps that need to stay synchronized with system-wide preferences

Use .current when you:

  • Need a snapshot of the current calendar settings
  • Want to maintain consistent calendar behavior throughout a specific operation
  • Don't need to track user-initiated system changes

By choosing the right calendar type for your specific use case, you can build more reliable and user-friendly date-handling features in your iOS applications.

Further readings

There’s an interesting Wikipedia page on time formatting bugs: Time Formatting and Storage Bugs.
One of the most famous examples is the Y2K problem: Y2K Problem (or check out this video: Y2K Video).

References