static let Calendar variable with autoupdatingCurrent time zone uses wrong time zone

Originator:aleksander.grzyb
Number:rdar://32516552 Date Originated:
Status:Closed Resolved:17.01.2018
Product: Product Version:
Classification: Reproducible:
 
Area:
Calendar

Summary:
In my application I have a static `gregorian` property in `SharedCalendar` class that is defined like this:

    static let gregorian: Calendar = {
        var calendar = Foundation.Calendar(identifier: .gregorian)
        calendar.timeZone = TimeZone.autoupdatingCurrent
        return calendar
    }()

When I want to access a day of some date in specific time zone I am calling:

    SharedCalendar.gregorian.dateComponents([ .day ], from: someDate).day!

Let's say `someDate` is `Date(timeIntervalSinceReferenceDate: 512658000.0)` which is `2017-03-31 13:00:00 +0000`.

When I start the app in Vancouver time zone the `SharedCalendar.gregorian.timeZone` property has value `America/Vancouver (autoupdatingCurrent)` and the result of `SharedCalendar.gregorian.dateComponents([ .day ], from: someDate).day!` is `31` **which is correct**.

When I put the application to background and switch the time zone to Sydney and run the app again the `SharedCalendar.gregorian.timeZone` property has value `Australia/Sydney (autoupdatingCurrent)` (which is correct), but the result of `SharedCalendar.gregorian.dateComponents([ .day ], from: someDate).day!` is `31` **which is wrong (should be `1`)**.

When I change the definition of `gregorian` property to be a `var`:

    var gregorian: Calendar {
        var calendar = Foundation.Calendar(identifier: .gregorian)
        calendar.timeZone = TimeZone.autoupdatingCurrent
        return calendar
    }

Everything works properly, which is for `America/Vancouver (autoupdatingCurrent)` I get `31`, and for `Australia/Sydney (autoupdatingCurrent)` I get `1`.

Right now I don't quite understand how `TimeZone.autoupdatingCurrent` is working. When device's time zone changes the `SharedCalendar.gregorian.timeZone` reflects the device's time zone, but it looks like `SharedCalendar.gregorian` is somehow using the old time zone. I don't know if it's a bug or my lack of knowledge how `static let` variables are working.

Steps to Reproduce:
1. Run the "CalendarTest" app in Vancouver time zone.
2. Tap "Update Date" on main screen (you should see "31").
3. Change time zone of the device to Sydney (should be one day later when changed, so for example 12pm in Vancouver 5am in Sydney).
4. Tap "Update Date" on main screen.

Expected Results:
The screen should display "1".

Observed Results:
The screen displays "31".

Version:
iOS 10.3.2 (14F89)

Notes:


Configuration:

Comments

This is a follow-up regarding regarding Bug ID# 32516552.

Engineering has provided the following information regarding this issue:

The reason that your static let calendar’s time zone doesn’t update is that you need to issue a call to NSTimeZone.resetSystemTimeZone() to sync up with the system time zone. See the documentation for NSTimeZone.resetSystemTimeZone() for more info: https://developer.apple.com/documentation/foundation/nstimezone/1387189-resetsystemtimezone?language=objc

The reason your var calendar works is because every call to the calendar property actually creates a new computed calendar, which happens to be set to a new time zone representing the current system time zone.

By aleksander.grzyb at Jan. 17, 2018, 7:58 a.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!