如何确定特定日期是否是夏令时?

6

我正在处理一个糟糕编程的第三方API,它强制我在Objective C中处理一些日期/时间数据。

与其返回UTC绝对UNIX时间戳相比,它返回格式化字符串,没有时区信息。(实际上,在与其中一个开发人员交谈后,他们实际上将日期/时间存储在数据库中,作为没有时区信息的字符串,而不是作为时间戳!)服务器位于美国中部某处,所以当前处于CDT状态,因此理论上我可以只需将“CDT”添加到格式化日期并使用NSDateFormatter(yyyy-MM-dd HH:mm:ss zzz)构建NSDate即可。但是,根据所涉及日期来自的年份不同,它可能在CST或CDT中。

如何确定在特定日期是否实行夏令时,以便我可以附加正确的时区并计算正确的UTC日期?

2个回答

8
我认为并没有一种正确的方法来解决这个问题。有一些 API 可以用于此,例如:[NSTimeZone isDaylightSavingTimeForDate:][NSTimeZone daylightSavingTimeOffsetForDate:]
但是,在从 CDT 到 CST 的转换中,一个小时将被重复,因此无法确定它是 CDT 还是 CST。除了那个小时假设为 CST 并检查夏令时是否有效应该可以工作。我的建议是把编写此 API 的人点燃着火。

正确-- 最好的选择是更改API。不幸的是我没有这个能力。有没有一种方法可以从NSDate获取NSTimeZone?这样我就可以使用isDaylightSavingsTimeForDate:方法。 - Jason
2
@Jason 要非常小心。NSDate与NSTimeZone没有任何关系(Unix时间戳有时区吗?没有,原因是相同的)。 时区适用于日期格式化程序,而不是日期本身。 所以,如我上面所述,只需假定CST(使用该缩写创建时区),在格式化程序上设置该时区,并使用格式化程序创建一个NSDate对象。 它会运行,除了重复的一个小时。 如果夏令时正在生效,则相应地调整NSDate。 - borrrden
我同意在夏令时回退转换期间重复一小时的说法。如果没有来自 API 的其他信息,您只能猜测其中之一,而且可能是错误的。 - Matt Johnson-Pint
我也想找到那个人。 - Carlos

0

我认为我有一个解决方案:

    NSString *originalDateString = <ORIGINAL DATE FROM API>;

    NSDateFormatter *dateStringFormatter = [[NSDateFormatter alloc] init];
    dateStringFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss zzz";

    NSString *tempDateString = [originalDateString stringByAppendingFormat:@" CST"];

    // create a temporary NSDate object
    NSDate *tempDate = [dateStringFormatter dateFromString:tempDateString];

    // get the time zone for this NSDate (it may be incorrect but it is an NSTimeZone object)
    NSDateComponents *components = [[NSCalendar currentCalendar]
                                    components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSTimeZoneCalendarUnit
                                    fromDate:tempDate];
    NSTimeZone *tempTimeZone = [components timeZone];

    // Find out if the time zone of the temporary date
    // (in CST or CDT depending on the local time zone of the iOS device)
    // **would** use daylight savings time for the date in question, and
    // select the proper time zone
    NSString *timeZone;
    if ([tempTimeZone isDaylightSavingTimeForDate:tempDate]) {
        timeZone = @"CDT";
    } else {
        timeZone = @"CST";
    }

    NSString *finalDateString = [originalDateString stringByAppendingFormat:@" %@", timeZone];

1
注意时区缩写。我不确定iOS如何处理,但有许多相同缩写的时区。您可以在此处查看列表:http://www.timeanddate.com/library/abbreviations/timezones/。例如,CST可能意味着“中国标准时间”... - Matt Johnson-Pint
2
我想知道你是否可以直接传递时区ID America/Chicago?如果是这样,你可能不需要自己检查isDaylightSavingsTimeForDate。它可能会在内部执行。(我只是猜测 - 我不是iOS/ObjectiveC开发人员) - Matt Johnson-Pint
@MattJohnson 对于这个API来说,这是没有意义的,因为"America/Chicago"将取决于日期,而时区则不会。此外,对于这个API来说更快的方法是,不需要再创建另一个格式化程序,只需在您在tempDate中创建的日期上添加daylightSavingTimeOffsetForDate:即可。如果夏令时没有生效,它将为零。 - borrrden
很不幸,iOS无法从日期格式化程序自动确定夏令时。如果我在应该是CDT的时候输入CST,那么时间就会差一个小时。 - Jason
1
@Jason 他的意思是直接传递“America/Chicago”而不是“CST”,让系统确定实际的时区 :). 此外,您可以考虑通过名称构建时区,而不是缩写,以避免他上面提到的问题。 - borrrden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接