为什么NSDateFormatter返回这4个时区的nil日期?

时间:2022-08-31 08:45:54

Try running this in iOS6 (haven't tested pre iOS6):

尝试在iOS6中运行这个(还没有测试过iOS6):

NSDateFormatter *julianDayDateFormatter = nil;
julianDayDateFormatter = [[NSDateFormatter alloc] init];
[julianDayDateFormatter setDateFormat:@"g"];

for (NSString *timeZone in [NSTimeZone knownTimeZoneNames]) {
    julianDayDateFormatter.timeZone = [NSTimeZone timeZoneWithName: timeZone];
    NSDate *date = [julianDayDateFormatter dateFromString:[NSString stringWithFormat:@"%d", 2475213]];
    if (date == nil)
        NSLog(@"timeZone = %@", timeZone);
}

and you get the following output:

得到如下输出:

America/Bahia
America/Campo_Grande
America/Cuiaba
America/Sao_Paulo

Can anyone explain why these four time zones behave like this with NSDateFormatter set to julian day numbers? All other time zones makes NSDateFormatter return actual NSDates.

有谁能解释为什么这四个时区的NSDateFormatter被设置为朱利安日号?所有其他时区都使NSDateFormatter返回实际的nsdate。

2 个解决方案

#1


61  

I have a suspicion. Only a suspicion, but a pretty strong one.

我有一个怀疑。只是一种怀疑,但却是相当强烈的怀疑。

That value represents October 19th 2064. The Brazilian time zones observe daylight saving time starting at local midnight - that's when their clocks go forward, so midnight itself doesn't exist. October 19th is one of those transitions.

这个值代表了2064年10月19日。巴西时区从当地午夜开始观察夏令时——这是他们的时钟前进的时候,所以午夜本身并不存在。10月19日就是这样的转变之一。

Here's some sample code using Noda Time, my .NET date/time API. It checks whether the start of the day in every time zone it knows about is actually midnight:

这里有一些使用野田时间的示例代码,我的。net日期/时间API。它会检查每个时区的开始时间是否为午夜:

using System;
using NodaTime;

class Test
{
    static void Main()
    {
        var localDate = new LocalDate(2064, 10, 19);
        var provider = DateTimeZoneProviders.Tzdb;
        foreach (var id in provider.Ids)
        {
            var zone = provider[id];
            var startOfDay = zone.AtStartOfDay(localDate).LocalDateTime.TimeOfDay;
            if (startOfDay != LocalTime.Midnight)
            {
                Console.WriteLine(id);
            }
        }
    }
}

That produces a very similar list:

这就产生了一个非常相似的列表:

America/Bahia
America/Campo_Grande
America/Cuiaba
America/Sao_Paulo
Brazil/East

I suspect Brazil/East may be an alias for America/Sao_Paolo, which is why it's not on your list.

我怀疑巴西/东部可能是美国/圣保罗的别名,这就是为什么它不在你的名单上。

Anyway, to get back to your Julian day issue - I suspect the formatter always wants to return an NSDate * which is at the local midnight. That doesn't exist for October 19th 2064 in those time zones... hence it returns nil. Personally I'd suggest it should return the 1am value instead, but hey...

无论如何,回到您的朱利安日问题——我怀疑格式化程序总是想返回一个NSDate *,它在本地午夜。这在2064年10月19日的时区是不存在的……因此它返回零。我个人认为它应该返回上午1点的值,但是嘿…

#2


16  

Credits to Jon Skeet for putting me on the right track. However, I just want to clarify his answer in an iOS context.

感谢乔恩·斯凯,让我走上了正确的道路。然而,我只是想在iOS环境下澄清他的答案。

When you ask NSDateFormatter to convert a julian day number into an NSDate, you can only specify whole numbers (usually you can specify a decimal part for the hours/minutes/secs of the day) in the string to be parsed. Because Apple demarcates julian days at midnight (as opposed to noon in astronomy, read more here: http://www.unicode.org/reports/tr35/#Date_Field_Symbol_Table) and some midnights simply doesn't exists (thanks for pointing that out @JonSkeet) NSDateFormatter identifies that that particular point in time doesn't exist in that time zone and returns nil.

当您要求NSDateFormatter将朱利安日号转换为NSDate时,您只能在要解析的字符串中指定整个数字(通常可以指定一天中的小时/分钟/秒的小数部分)。因为苹果在午夜划分儒略日(与天文学的正午相反,请在这里阅读更多:http://www.unicode.org/reports/tr35/#Date_Field_Symbol_Table),一些午夜根本不存在(感谢您指出@JonSkeet), NSDateFormatter指出,在那个时区不存在特定的时间点,并返回nil。

For the record, iOS5 does not behave like this and I agree with Jon Skeet, that NSDateFormatter should return an NSDate adjusted for DST instead of nil, as that particular julian day in fact exists! I filed a bug with Apple.

为了记录,iOS5不是这样的,我同意Jon Skeet的观点,NSDateFormatter应该返回一个调整为DST而不是nil的NSDate,因为那个特定的julian day确实存在!我向苹果公司提出了一个问题。

#1


61  

I have a suspicion. Only a suspicion, but a pretty strong one.

我有一个怀疑。只是一种怀疑,但却是相当强烈的怀疑。

That value represents October 19th 2064. The Brazilian time zones observe daylight saving time starting at local midnight - that's when their clocks go forward, so midnight itself doesn't exist. October 19th is one of those transitions.

这个值代表了2064年10月19日。巴西时区从当地午夜开始观察夏令时——这是他们的时钟前进的时候,所以午夜本身并不存在。10月19日就是这样的转变之一。

Here's some sample code using Noda Time, my .NET date/time API. It checks whether the start of the day in every time zone it knows about is actually midnight:

这里有一些使用野田时间的示例代码,我的。net日期/时间API。它会检查每个时区的开始时间是否为午夜:

using System;
using NodaTime;

class Test
{
    static void Main()
    {
        var localDate = new LocalDate(2064, 10, 19);
        var provider = DateTimeZoneProviders.Tzdb;
        foreach (var id in provider.Ids)
        {
            var zone = provider[id];
            var startOfDay = zone.AtStartOfDay(localDate).LocalDateTime.TimeOfDay;
            if (startOfDay != LocalTime.Midnight)
            {
                Console.WriteLine(id);
            }
        }
    }
}

That produces a very similar list:

这就产生了一个非常相似的列表:

America/Bahia
America/Campo_Grande
America/Cuiaba
America/Sao_Paulo
Brazil/East

I suspect Brazil/East may be an alias for America/Sao_Paolo, which is why it's not on your list.

我怀疑巴西/东部可能是美国/圣保罗的别名,这就是为什么它不在你的名单上。

Anyway, to get back to your Julian day issue - I suspect the formatter always wants to return an NSDate * which is at the local midnight. That doesn't exist for October 19th 2064 in those time zones... hence it returns nil. Personally I'd suggest it should return the 1am value instead, but hey...

无论如何,回到您的朱利安日问题——我怀疑格式化程序总是想返回一个NSDate *,它在本地午夜。这在2064年10月19日的时区是不存在的……因此它返回零。我个人认为它应该返回上午1点的值,但是嘿…

#2


16  

Credits to Jon Skeet for putting me on the right track. However, I just want to clarify his answer in an iOS context.

感谢乔恩·斯凯,让我走上了正确的道路。然而,我只是想在iOS环境下澄清他的答案。

When you ask NSDateFormatter to convert a julian day number into an NSDate, you can only specify whole numbers (usually you can specify a decimal part for the hours/minutes/secs of the day) in the string to be parsed. Because Apple demarcates julian days at midnight (as opposed to noon in astronomy, read more here: http://www.unicode.org/reports/tr35/#Date_Field_Symbol_Table) and some midnights simply doesn't exists (thanks for pointing that out @JonSkeet) NSDateFormatter identifies that that particular point in time doesn't exist in that time zone and returns nil.

当您要求NSDateFormatter将朱利安日号转换为NSDate时,您只能在要解析的字符串中指定整个数字(通常可以指定一天中的小时/分钟/秒的小数部分)。因为苹果在午夜划分儒略日(与天文学的正午相反,请在这里阅读更多:http://www.unicode.org/reports/tr35/#Date_Field_Symbol_Table),一些午夜根本不存在(感谢您指出@JonSkeet), NSDateFormatter指出,在那个时区不存在特定的时间点,并返回nil。

For the record, iOS5 does not behave like this and I agree with Jon Skeet, that NSDateFormatter should return an NSDate adjusted for DST instead of nil, as that particular julian day in fact exists! I filed a bug with Apple.

为了记录,iOS5不是这样的,我同意Jon Skeet的观点,NSDateFormatter应该返回一个调整为DST而不是nil的NSDate,因为那个特定的julian day确实存在!我向苹果公司提出了一个问题。