Central American NSTimeZone instances returning CST rather than permanently CDT

I had some support tickets about dates not showing properly for customers based in the America/Merida timezone.

Essentially America/Merida permanently changed to -0500 (CDT) on October 31, 2021, and it appears that the NSTimeZone does not respect this change, and reports times as -0600 (CST).

Creating a little test tool with the following code:

+(void) run {
    NSArray<NSString *> * args = [[NSProcessInfo processInfo] arguments];
    if ([args count] > 1) {
        NSString *timezone = args[1];
        NSLog(@"custom TZ: %@", timezone);
        
        NSTimeZone * tz = [NSTimeZone timeZoneWithName:timezone];
        [NSTimeZone setDefaultTimeZone:tz];
    }
    
    NSDate * now = [NSDate date];
    
    NSLog(@"Testing Dates:  (local timezone  : %@)", [NSTimeZone localTimeZone]);
    NSLog(@"                (default timezone: %@)", [NSTimeZone defaultTimeZone]);
    NSLog(@"                (is DST          : %@)", [[NSTimeZone defaultTimeZone] isDaylightSavingTimeForDate:now] ? @"YES" : @"NO");
    NSLog(@"                (current cal-tz  : %@)", [[NSCalendar currentCalendar] timeZone]);
    NSLog(@"                (current locale  : %@)", [[NSLocale currentLocale] localeIdentifier]);
    NSLog(@"Now:            %@", now);
}

And running with the America/Merida timezone passed in, I'm getting the following output:

custom TZ: America/Merida
Testing Dates:  (local timezone  : Local Time Zone (America/New_York (EDT) offset -14400 (Daylight)))
                (default timezone: America/Merida (CST) offset -21600)
                (is DST          : NO)
                (current cal-tz  : America/Merida (CST) offset -21600)
                (current locale  : en_US)
Now:            Tue May 14 15:06:14 2024

Running the same code on Linux via the GNUStep implementation of Objective-C, I get the correct output with America/Merida showing up as CDT (ie (is DST : YES)).


Are there any good ways to work around this?

Answered by DTS Engineer in 787758022

Consider this:

import Foundation

func main() {
    var c = Calendar(identifier: .gregorian)
    c.timeZone = .gmt
    let jan2022 = c.date(from: .init(year: 2022, month: 1, day: 1))!
    let jun2022 = c.date(from: .init(year: 2022, month: 6, day: 1))!
    let jan2023 = c.date(from: .init(year: 2023, month: 1, day: 1))!
    let jun2023 = c.date(from: .init(year: 2023, month: 6, day: 1))!
    
    let tz = TimeZone(identifier: "America/Merida")!
    for d in [jan2022, jun2022, jan2023, jun2023] {
        print(tz.isDaylightSavingTime(for: d), tz.daylightSavingTimeOffset(for: d), tz.secondsFromGMT(for: d) / 60 / 60)
    }
}

main()

On macOS 14.4.1 it prints:

false 0.0 -6
true 3600.0 -5
false 0.0 -6
false 0.0 -6

That definitely matches your assertion that this time zone is ‘stuck’ on standard time rather than daylight savings time.

However, I’m confused by this assertion:

Essentially America/Merida permanently changed to -0500 (CDT) on October 31, 2021

The Wikipedia summary of Mexican time zones suggests that America/Merida is effectively deprecated in favour of America/Mexico_City. And if I plug America/Mexico_City into the above code, it prints the same results.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

This is the world standard

Central Daylight Time (CDT) is a North American time zone that is used from the second Sunday in March to the first Sunday in November during Daylight Saving Time (DST). Central Standard Time (CST) is used during the remainder of the year.

System developers will eventually adapt since a sudden change will result in repercussions in various financial markets and platforms.

File a bug with Apple via the feedback app.

Accepted Answer

Consider this:

import Foundation

func main() {
    var c = Calendar(identifier: .gregorian)
    c.timeZone = .gmt
    let jan2022 = c.date(from: .init(year: 2022, month: 1, day: 1))!
    let jun2022 = c.date(from: .init(year: 2022, month: 6, day: 1))!
    let jan2023 = c.date(from: .init(year: 2023, month: 1, day: 1))!
    let jun2023 = c.date(from: .init(year: 2023, month: 6, day: 1))!
    
    let tz = TimeZone(identifier: "America/Merida")!
    for d in [jan2022, jun2022, jan2023, jun2023] {
        print(tz.isDaylightSavingTime(for: d), tz.daylightSavingTimeOffset(for: d), tz.secondsFromGMT(for: d) / 60 / 60)
    }
}

main()

On macOS 14.4.1 it prints:

false 0.0 -6
true 3600.0 -5
false 0.0 -6
false 0.0 -6

That definitely matches your assertion that this time zone is ‘stuck’ on standard time rather than daylight savings time.

However, I’m confused by this assertion:

Essentially America/Merida permanently changed to -0500 (CDT) on October 31, 2021

The Wikipedia summary of Mexican time zones suggests that America/Merida is effectively deprecated in favour of America/Mexico_City. And if I plug America/Mexico_City into the above code, it prints the same results.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Oof, serves me right for not doing my own research. That was the time change info I was relayed by one of the support staff that I trust to get their details correct. :facepalm:

But as far as I can tell from that wiki page, you are correct, being stuck on CST is the correct behavior.

Central American NSTimeZone instances returning CST rather than permanently CDT
 
 
Q