NSDateFormatter,我是做错了什么,还是这个bug?

时间:2022-09-20 18:35:47

I'm trying to print out the date in a certain format:

我试着以某种格式打印出日期:

NSDate *today = [[NSDate alloc] init];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
NSString *dateStr = [dateFormatter stringFromDate:today];

If the iPhone is set to 24 hour time, this works fine, if on the other hand the user has set it to 24 hour time, then back to AM/PM (it works fine until you toggle this setting) then it appends the AM/PM on the end even though I didn't ask for it:

如果iPhone设置为24小时的时间,这个工作很好,另一方面,如果用户已经设置为24小时的时间,然后回到AM / PM(这没问题,直到你切换设置)那么它附加的AM / PM即使我没有问:

20080927030337 PM

Am I doing something wrong or is this a bug with firmware 2.1?

我做错了什么,还是固件2.1有问题?

Edit 1: Made description clearer

编辑1:使描述更清晰

Edit 2 workaround: It turns out this is a bug, to fix it I set the AM and PM characters to "":

编辑2个变通:原来这是一个bug,为了修复它,我将AM和PM字符设置为“”:

[dateFormatter setAMSymbol:@""];
[dateFormatter setPMSymbol:@""];

8 个解决方案

#1


12  

Using the code you posted on both the simulator and a phone with the 2.1 firmware and 24-hour time set to off, I never had an AM/PM appended to dateStr when I do:

使用你在模拟器上发布的代码和一部装有2.1固件、24小时关机的手机,我从来没有在dateStr中添加过AM/PM,当我这样做的时候:

NSLog(@"%@", dateStr);

Are you doing anything else with dateStr that you didn't post here? How are you checking the value?

你还在使用dateStr做什么吗?如何检查值?

Follow up

跟进

Try turning the am/pm setting on then off. I didn't have the problem either, until I did that. I am printing it out the same way you are.

试着把am/pm打开然后关掉。我也没有问题,直到我这样做。我用和你们一样的方式打印出来。

Okay, I see it when I do this also. It's gotta be a bug. I recommend you file a bug report and just check for and filter out the unwanted characters in the meantime.

我也看到了。一定是有问题。我建议您提交一个bug报告,同时检查并过滤掉不需要的字符。

#2


28  

The reason for this behaviour is Locale, set the correct Locale, Set the local of your NSDateFormatter to en_US_POSIX will fix this. It works for both 24-hour and 12 hour format.

这种行为的原因是Locale,设置正确的Locale,将NSDateFormatter的local设置为en_US_POSIX将修复这一点。它适用于24小时和12小时的格式。

On iPhone OS, the user can override the default AM/PM versus 24-hour time setting (via Settings > General > Date & Time > 24-Hour Time), which causes NSDateFormatter to rewrite the format string you set. From apple doc

在iPhone OS上,用户可以覆盖默认的AM/PM和24小时时间设置(通过设置>常规>日期和时间> 24小时时间),这会导致NSDateFormatter重写您设置的格式字符串

Try this,

试试这个,

NSDate *today = [[NSDate alloc] init];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
[dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
NSString *dateStr = [dateFormatter stringFromDate:today];

#3


14  

Here's the explanation of the iPhone SDK bug (also still there in 3.1 beta SDK)

下面是对iPhone SDK漏洞的解释(在3.1 beta SDK中也有)

First, a little background on the iPhone user interface. When iPhone users change their region format between, say, “United States” and “France”, the users’ “24-Hour Time” setting is automatically switched to the mode that is most prevalent in that region. In France, that would set 24-Hour Time to “ON”, and in the U.S., that would set it to “OFF”. The users can then manually override that setting and that’s where trouble starts.

首先,介绍一下iPhone用户界面的一些背景知识。当iPhone用户改变他们的区域格式时,比如“美国”和“法国”,用户的“24小时”设置会自动切换到该地区最流行的模式。在法国,这将把24小时的时间设定为“打开”,在美国则是这样,这将把它设置为“OFF”。然后用户可以手动覆盖该设置,这就是问题开始的地方。

The problem comes from NSDateFormatter somehow “getting stuck” in the 12 or 24-hour time mode that the user has manually selected. So if a French user manually selects 12-hour mode, and the application requested NSDateFormatter to output time with the 24-hour format “HHmm”, it would actually receive time in a 12-hour format, e.g. “01:00 PM”, as if the application had instead requested “hhmm aa”. The reverse would happen if a US user manually selected 24-hour mode: outputting time with the 12-hour format “hhmm aa” would actually get you time in the 24-hour format instead, e.g. “17:00″.

问题来自于NSDateFormatter,它以某种方式在用户手动选择的12或24小时时间模式中“卡住”。因此,如果一个法国用户手动选择12小时模式,应用程序请求NSDateFormatter以24小时格式“HHmm”输出时间,那么它实际上会以12小时格式接收时间,例如“01:00 PM”,就好像应用程序请求的是“HHmm aa”。如果美国用户手动选择24小时模式,则会出现相反的情况:用12小时格式的“hhmm aa”输出时间,实际上会得到24小时格式的时间,例如“17:00”。

More details and a possible workaround can be found on this blog.

更多的细节和可能的解决办法可以在这个博客上找到。

#4


9  

Setting locale on date formatter to en_US fixes the problem for me:

在日期格式化器上设置locale to en_US为我解决问题:

    NSDateFormatter * f = [[NSDateFormatter alloc] init];
    [f setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
    f.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    f.calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
    f.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease];

I'm not sure if adding the calendar is also needed, but this works well.

我不确定是否需要添加日历,但是这很有效。

#5


4  

I think this is the solution .

我认为这就是答案。

NSDateFormatter *df =[[NSDateFormatter alloc] init];
        [df setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
        NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];

[df setLocale: usLocale];

[usLocale release];

 NSDate *documento_en_Linea =[[[NSDate alloc] init]autorelease];

documento_en_Linea=[df dateFromString:@"2010-07-16 21:40:33"];

[df release];

        NSLog(@"fdocumentoenLineaUTC:%@!",documento_en_Linea);


//ouput  
     fdocumentoenLineaUTC:2010-07-16 09:40:33 p.m. -0500!

#6


1  

For those finding this question who want to use NSDateFormatter to parse 24-hour time and are hitting this bug, using NSDateComponents to parse dates and times which have a known format sidesteps this issue:

对于那些想要使用NSDateFormatter来解析24小时时间并使用NSDateComponents解析具有已知格式的日期和时间的人,可以解决这个问题:

NSString *dateStr = @"2010-07-05";
NSString *timeStr = @"13:30";

NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = [[dateStr substringToIndex:4] intValue];
components.month = [[dateStr substringWithRange:NSMakeRange(5, 2)] intValue];
components.day = [[dateStr substringFromIndex:8] intValue];
components.hour = [[timeStr substringToIndex:2] intValue];
components.minute = [[timeStr substringFromIndex:3] intValue];

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDate *date = [calendar dateFromComponents:components];

[components release];
[calendar release];

#7


0  

This should also work (I am seeing some bizzare results though).

这也应该行得通(我看到了一些比兹尔的结果)。

-(NSString*)lowLevTime:(NSString*)stringFormat {
    char buffer[50];
    const char *format = [stringFormat UTF8String];
    time_t rawtime;
    struct tm * timeinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    strftime(buffer, sizeof(buffer), format, timeinfo);
    return [NSString  stringWithCString:buffer encoding:NSASCIIStringEncoding];
}

#8


0  

Short answer: try [dateFormatter setDateFormat:@"yyyyMMddhhmmss"]; for 12 hour format (note the lowercase hh).

简短回答:尝试[dateFormatter setDateFormat:@"yyyyMMddhhmmss"];12小时格式(注意小写hh)。

It's been a frustrating topic because so many websites indicate to use HH for hours (including the official Apple documentation), but that sets it to 24 hour format, whereas hh uses 12 hour format. See http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns for more details.

这是一个令人沮丧的话题,因为很多网站显示要使用HH数小时(包括苹果官方文档),但这将它设置为24小时格式,而HH使用12小时格式。详情请参见http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns。

As a bonus, note that you can also use KK or kk for hour of the day format, which will likely be off by one.

另外,请注意,您也可以使用KK或KK作为一天中的一小时格式,它可能会减少1小时。

Update: I was recently looking at NSLocale (https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference.html) and it would seem that you can use autoupdatingCurrentLocale to apply changes made from within the app to the Locale. The upshot of this is that even if the phone is set to use a 24 hour clock (like when you switched to France), you can make a 12/24 toggle for the app that won't impact any other apps on the phone, or require you to leave the app to make the change.

更新:我最近在查看NSLocale (https://developer.apple.com/library/mac/#文档/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference /Reference.html),似乎您可以使用autoupdatingCurrentLocale来将应用程序内的更改应用到Locale。的结果是,即使手机将使用24小时时钟(比如当你转向法国),你可以12/24切换应用程序不会影响任何其他应用程序在手机上,或者要求你离开应用程序改变。

#1


12  

Using the code you posted on both the simulator and a phone with the 2.1 firmware and 24-hour time set to off, I never had an AM/PM appended to dateStr when I do:

使用你在模拟器上发布的代码和一部装有2.1固件、24小时关机的手机,我从来没有在dateStr中添加过AM/PM,当我这样做的时候:

NSLog(@"%@", dateStr);

Are you doing anything else with dateStr that you didn't post here? How are you checking the value?

你还在使用dateStr做什么吗?如何检查值?

Follow up

跟进

Try turning the am/pm setting on then off. I didn't have the problem either, until I did that. I am printing it out the same way you are.

试着把am/pm打开然后关掉。我也没有问题,直到我这样做。我用和你们一样的方式打印出来。

Okay, I see it when I do this also. It's gotta be a bug. I recommend you file a bug report and just check for and filter out the unwanted characters in the meantime.

我也看到了。一定是有问题。我建议您提交一个bug报告,同时检查并过滤掉不需要的字符。

#2


28  

The reason for this behaviour is Locale, set the correct Locale, Set the local of your NSDateFormatter to en_US_POSIX will fix this. It works for both 24-hour and 12 hour format.

这种行为的原因是Locale,设置正确的Locale,将NSDateFormatter的local设置为en_US_POSIX将修复这一点。它适用于24小时和12小时的格式。

On iPhone OS, the user can override the default AM/PM versus 24-hour time setting (via Settings > General > Date & Time > 24-Hour Time), which causes NSDateFormatter to rewrite the format string you set. From apple doc

在iPhone OS上,用户可以覆盖默认的AM/PM和24小时时间设置(通过设置>常规>日期和时间> 24小时时间),这会导致NSDateFormatter重写您设置的格式字符串

Try this,

试试这个,

NSDate *today = [[NSDate alloc] init];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
[dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
NSString *dateStr = [dateFormatter stringFromDate:today];

#3


14  

Here's the explanation of the iPhone SDK bug (also still there in 3.1 beta SDK)

下面是对iPhone SDK漏洞的解释(在3.1 beta SDK中也有)

First, a little background on the iPhone user interface. When iPhone users change their region format between, say, “United States” and “France”, the users’ “24-Hour Time” setting is automatically switched to the mode that is most prevalent in that region. In France, that would set 24-Hour Time to “ON”, and in the U.S., that would set it to “OFF”. The users can then manually override that setting and that’s where trouble starts.

首先,介绍一下iPhone用户界面的一些背景知识。当iPhone用户改变他们的区域格式时,比如“美国”和“法国”,用户的“24小时”设置会自动切换到该地区最流行的模式。在法国,这将把24小时的时间设定为“打开”,在美国则是这样,这将把它设置为“OFF”。然后用户可以手动覆盖该设置,这就是问题开始的地方。

The problem comes from NSDateFormatter somehow “getting stuck” in the 12 or 24-hour time mode that the user has manually selected. So if a French user manually selects 12-hour mode, and the application requested NSDateFormatter to output time with the 24-hour format “HHmm”, it would actually receive time in a 12-hour format, e.g. “01:00 PM”, as if the application had instead requested “hhmm aa”. The reverse would happen if a US user manually selected 24-hour mode: outputting time with the 12-hour format “hhmm aa” would actually get you time in the 24-hour format instead, e.g. “17:00″.

问题来自于NSDateFormatter,它以某种方式在用户手动选择的12或24小时时间模式中“卡住”。因此,如果一个法国用户手动选择12小时模式,应用程序请求NSDateFormatter以24小时格式“HHmm”输出时间,那么它实际上会以12小时格式接收时间,例如“01:00 PM”,就好像应用程序请求的是“HHmm aa”。如果美国用户手动选择24小时模式,则会出现相反的情况:用12小时格式的“hhmm aa”输出时间,实际上会得到24小时格式的时间,例如“17:00”。

More details and a possible workaround can be found on this blog.

更多的细节和可能的解决办法可以在这个博客上找到。

#4


9  

Setting locale on date formatter to en_US fixes the problem for me:

在日期格式化器上设置locale to en_US为我解决问题:

    NSDateFormatter * f = [[NSDateFormatter alloc] init];
    [f setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
    f.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    f.calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
    f.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease];

I'm not sure if adding the calendar is also needed, but this works well.

我不确定是否需要添加日历,但是这很有效。

#5


4  

I think this is the solution .

我认为这就是答案。

NSDateFormatter *df =[[NSDateFormatter alloc] init];
        [df setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
        NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];

[df setLocale: usLocale];

[usLocale release];

 NSDate *documento_en_Linea =[[[NSDate alloc] init]autorelease];

documento_en_Linea=[df dateFromString:@"2010-07-16 21:40:33"];

[df release];

        NSLog(@"fdocumentoenLineaUTC:%@!",documento_en_Linea);


//ouput  
     fdocumentoenLineaUTC:2010-07-16 09:40:33 p.m. -0500!

#6


1  

For those finding this question who want to use NSDateFormatter to parse 24-hour time and are hitting this bug, using NSDateComponents to parse dates and times which have a known format sidesteps this issue:

对于那些想要使用NSDateFormatter来解析24小时时间并使用NSDateComponents解析具有已知格式的日期和时间的人,可以解决这个问题:

NSString *dateStr = @"2010-07-05";
NSString *timeStr = @"13:30";

NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = [[dateStr substringToIndex:4] intValue];
components.month = [[dateStr substringWithRange:NSMakeRange(5, 2)] intValue];
components.day = [[dateStr substringFromIndex:8] intValue];
components.hour = [[timeStr substringToIndex:2] intValue];
components.minute = [[timeStr substringFromIndex:3] intValue];

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDate *date = [calendar dateFromComponents:components];

[components release];
[calendar release];

#7


0  

This should also work (I am seeing some bizzare results though).

这也应该行得通(我看到了一些比兹尔的结果)。

-(NSString*)lowLevTime:(NSString*)stringFormat {
    char buffer[50];
    const char *format = [stringFormat UTF8String];
    time_t rawtime;
    struct tm * timeinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    strftime(buffer, sizeof(buffer), format, timeinfo);
    return [NSString  stringWithCString:buffer encoding:NSASCIIStringEncoding];
}

#8


0  

Short answer: try [dateFormatter setDateFormat:@"yyyyMMddhhmmss"]; for 12 hour format (note the lowercase hh).

简短回答:尝试[dateFormatter setDateFormat:@"yyyyMMddhhmmss"];12小时格式(注意小写hh)。

It's been a frustrating topic because so many websites indicate to use HH for hours (including the official Apple documentation), but that sets it to 24 hour format, whereas hh uses 12 hour format. See http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns for more details.

这是一个令人沮丧的话题,因为很多网站显示要使用HH数小时(包括苹果官方文档),但这将它设置为24小时格式,而HH使用12小时格式。详情请参见http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns。

As a bonus, note that you can also use KK or kk for hour of the day format, which will likely be off by one.

另外,请注意,您也可以使用KK或KK作为一天中的一小时格式,它可能会减少1小时。

Update: I was recently looking at NSLocale (https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference.html) and it would seem that you can use autoupdatingCurrentLocale to apply changes made from within the app to the Locale. The upshot of this is that even if the phone is set to use a 24 hour clock (like when you switched to France), you can make a 12/24 toggle for the app that won't impact any other apps on the phone, or require you to leave the app to make the change.

更新:我最近在查看NSLocale (https://developer.apple.com/library/mac/#文档/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference /Reference.html),似乎您可以使用autoupdatingCurrentLocale来将应用程序内的更改应用到Locale。的结果是,即使手机将使用24小时时钟(比如当你转向法国),你可以12/24切换应用程序不会影响任何其他应用程序在手机上,或者要求你离开应用程序改变。