Radu Dan
iOS calendars — current vs autoupdatingCurrent

iOS calendars — current vs autoupdatingCurrent

Motivation

Everybody is talking about #wwdc19 and how SwiftUI is drawing the future and I am here writing a snippet about calendars.

Well, if you want to be a time traveller and see if SwiftUI will be a changer on how the UI will be created for iOS apps, let's first open up a Calendar.

This article helps you understand what are the differences between calendar.current and calendar.autoupdatingCurrent and when to apply them.

Setting up

There are two ways of retrieving user's calendar: .current and .autoupdatingCurrent.

If you open Apple's documentation, is saying that .current is not tracking changes that user makes to their settings.
On the other hand, .autoupdatingCurrent tracks changes to the user's preferred calendar.

Let's test that. Start with creating a simple single view app (File > New > Project > Single View App) or you can use mine from here.

Open Main.storyboard and add two buttons and one label. Name the buttons "Calendar current" and "Calendar autoupdatingCurrent". Connect the IBActions from the buttons with ViewController and add an IBOutlet for the UILabel.

Create a new function in ViewController to handle the output.

Your view controller should look something like this:

          
          class ViewController: UIViewController {

              @IBOutlet weak var outputLabel: UILabel!

              private let currentCalendar = Calendar.current
              private var autoupdatingCalendar = Calendar.autoupdatingCurrent

              @IBAction func onTouchCalendarCurrent(_ sender: Any) {
                  displayCalendarInfo(from: currentCalendar)
              }

              @IBAction func onTouchCalendarAutoupdatingCurrent(_ sender: Any) {
                  displayCalendarInfo(from: autoupdatingCalendar)
              }

              private func displayCalendarInfo(from calendar: Calendar) {
                  let comps = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: Date())

                  // minor output formatting
                  let time: (hour: Int, minute: Int) = (comps.hour!, comps.minute!)
                  let hours = time.hour < 10 ? "0\(time.hour)" : "\(time.hour)"
                  let minutes = time.minute < 10 ? "0\(time.minute)" : "\(time.minute)"

                  var output = "Calendar: \(calendar.identifier)\nTime Zone: \(calendar.timeZone.identifier)\n"
                  output.append(contentsOf: "\(hours):\(minutes)")

                  outputLabel.text = output
              }

          }

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

Understanding calendars

You might think the main difference is that if you are going to change the time from your device settings, this will be reflected when accessing the .autoupdatingCurrent calendar and not for .current.
Let's try it out.

Open the app and hit one of those buttons. The output label will have the text something like: Calendar: gregorian Time Zone: Europe/London 09:28. Go to your device settings, General > Date & Time. Toggle of the Set Automatically switch.

Date and Time Settings

Update the time 1-2 hours before or after your current time. For example, current time for me was 09:28 and I updated it to 10:28.

Date and Time Settings

Go back to the app. Tap on the buttons again. Surprised? Both actions update the label to the new time!
Shouldn't just the .autoupdatingCurrent update its time? Why is this happening as well for the .current?

Setting time zone

Let's play around with the time zones. Go again to the device settings and tap on Time Zone. Search for Bucharest.

Return to the application.

Tap on the Calendar autoupdatingCurrent button. Observe that the label changed its text to:
Calendar: gregorian Time Zone: Europe/Bucharest 11:29
Now tap on the Calendar current button. Label has now the following text:
Calendar: gregorian Time Zone: Europe/London 09:29

So .autoupdatingCurrent calendar is following every update you do / system does to the date & time parameters.
This also applies if you change, for example, the Calendar from your device settings (Settings > General > Language & Region > Calendar).

Same pattern applies to other Foundation objects, such as Locale and TimeZone.

Conclusion

Working with dates has been always problematic and you need to consider this in your development side.
Having a clear understanding of what are the differences between iOS .current vs .autoupdatingCurrent is important when designing your APIs.

If you want to always display to the user the current date / time in based on their settings / region, time zone, calendar use .autoupdatingCurrent.
If you just want to access user's calendar and do not track changes that he does through settings later on, just use .current.

Further readings

There is a special Wikipedia page for time formatting bugs: https://en.wikipedia.org/wiki/Time_formatting_and_storage_bugs.
Most well known case is y2k: https://en.wikipedia.org/wiki/Year_2000_problem (or a more casual video: https://www.youtube.com/watch?v=h-StyszRCzc).

References