iOS客户端NSDateFormatter那个坑

By admin in 天文台 on 2019年4月21日

NSDateFormatter 会收到用户偏好设置的影响,所以有一对坑:

时区校验

有时,大家供给把时光字符串调换为long类型的时间戳。比方上边例子:

    // 将"2016-02-06 00:00:00"转化为格林尼治标准的时间戳

    NSString *timeStr = @"2016-02-06 00:00:00" 
    NSDateFormatter *format = [[NSDateFormatter alloc] init];
    [format setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *fromdate = [format dateFromString:timeStr];    
    long long time = (long long)[fromdate timeIntervalSince1970];

但这边忽略了时区难题:
大家从模拟器中,“设置”-> “通用” -> “时间与日期”
->关闭自动安装,选取”纽约”时区。上面代码计算出的time值
1454734800000。 然后我们选“新加坡”时区,总结出的time值为
1454688000000料定,五个值不均等,而且在London时区下计算出的年华戳的值越来越大。

UTC (Coordinated Universal Time)

小编们来看timeIntervalSince1970函数,官方证实

The interval between the date object and 00:00:00 UTC on 1 January 1970。根据UTC标准,计算NSDate对象距离1970年1月1号  00:00:00 的时间戳。

任哪儿球分为二10肆时区,每一个时区都有谈得来的本地时间。然而在世上范围,我们要求3个正规时间。大家熟稔的正经时间是
格林尼治时间。格林尼治规范时间(中夏族民共和国民代表大会洲翻译:Green尼治平均时间或格林尼治标准时间,台、港、澳翻译:格林威治标准时间;罗马尼亚(România)语:Greenwich
Mean
Time,达托霉素T)是指位于U.K.London宁国市的皇室格林尼治天文台的专门的学问时间,因为本初子午线被定义为经过那里的经线。自1九2二年七月6日上马,格林尼治天文台每隔1钟头会向整个世界发放调时新闻。理论上的话,格林尼治标准时间的正午是指当阳光横穿格林尼治子午线时(也正是在格林尼治上空最高点时)的时刻。由于地球在它的椭圆轨道里的移位速度不均匀,那么些随时大概与事实上的太阳时有固有误差,最大相对误差达16分钟。由于地球每日的自转是有个别语无伦次的,而且正在缓慢减速,由此格林尼治时间已经不再被当作标准时间利用。今后的专门的工作时间,是由时钟报时的UTC。其以原未时秒长为底蕴,在时时上尽心接近于格林尼治标准时间。

京师时区是东八区,当先UTC两个小时。时区差东为正,西为负。在此,把东八区时区差记为
+0800。London的时区是西五区,比UTC落后四个钟头,记为 -0500.
即东京(Tokyo)时间超越伦敦时刻11个时辰.

UTC
时间为1970年1月1号00:00:00的时候。香港时间是1970年1月1号8点,London时间也许1969年12月31号19:00。想象,各种时区有友好的时间坐标轴,原点代表的时间点是UTC的“一玖七〇年6月一号00:00:00”,
在坐标上标注各自的”201陆-02-06
00:00:00″那或多或少,它们离原点的偏离便是我们要算的光阴戳。

天文台 1

timetamp.png

一目领悟,将”201陆-0贰-06
00:00:00″转化为格林尼治标准的岁月戳。在London时区总计出来的值要比法国首都时区大。

若是将”201陆-02-06
00:00:00″是服务端(东8区)下发的光阴,大家在客户端必要转为时间戳,指出,把NSDateFormatter的时区设定在东八区。

 [format setTime Zone:[NSTimeZone timeZoneWithName:@"Asia/Shanghai"]];

天文台 2

Paste_Image.png

timeZone

timeZone

// 这个方法的名字很委婉,known一词说明这是“他”已知的时区的名字。世界各地对自己所在的时区可能都有一定的命名,但是不一定被“他”收录。例如,中国大陆,只有重庆和上海被收录了(难道这是中国只使用一个时区的错误?!)。使用这个方法获得的时区名字,都是在iOS系统中/usr/share/zoneinfo/目录中保存时区数据。随着iOS版本的更新,这里面的数据会发生变动。当然,要是你的设备越狱了,你可以手动往该目录下添加时区文件。       
// 时区文件里面包括了一下内容:
//      当前时区相对于GMT的偏移量(s)
//      当前时区的名字缩写
//      当前时区是否使“夏时制”时区
// 因为时区文件中包含了"偏移量",所以通过“时区的名称”可以指定一个“时区”。
// 时区名称举例:
//      Africa/Abidjan
//      America/New_York
//      Asia/Shanghai
//      Asia/Hong_Kong
// 越狱的童鞋可以看出时区的名称和/usr/share/zoneinfo中的目录结构基本一一对应。
+ (NSArray *)knownTimeZoneNames;


// 获取所有的时区名称缩写
// 名称缩写与名称是一一对应的关系,例如:HKT = "Asia/Hong_Kong";
// 默认情况下,调用该方法回去/usr/share/zoneinfo目录下找时区名称缩写,但是当使用方法"+ (void)setAbbreviationDictionary:(NSDictionary *)dict;"后,将会只返回刚才设置的时区名称缩写。请看下文的代码实例!
// 名称缩写举例:
//      EST = "America/New_York";
//      GMT = GMT;
//      GST = "Asia/Dubai";
//      HKT = "Asia/Hong_Kong";
+ (NSDictionary *)abbreviationDictionary;

//  由时区的名称获得对应的NSTimeZone对象
//  通过时区名称可以获得时区文件,通过时区文件就可以获得“偏移量”,“名称缩写”,“是否使用夏时制”等信息。
+ (id)timeZoneWithName:(NSString *)tzName;

//  由时区名称缩写获得对应的NSTimeZone对象
//  这里的时区名称缩写有两种情况:
//  第一种是上面说的HKT这样的缩写,与时区名称一一对应,通过这样的缩写获得的NSTimeZone对象,与使用时区名称获得得NSTimeZone对象一样。(大概读取得是同一个时区文件)
//  第二种是"GMT+0800"这样格式得缩写,其实这就是偏移量。通过偏移量在iOS中是不能读到与之对应得时区文件的,因此就无法知道“时区名称”,“名称缩写”,“是否使用夏时制”这样的信息了。默认情况下,"时区名称"和"名称缩写"都会赋值为"GMT+0800","是否使用夏时制"则不会设置(默认不使用)。
+ (id)timeZoneWithAbbreviation:(NSString *)abbreviation;

//  由偏移量获得对应的NSTimeZone对象
//  只说一点:通过偏移量获得的NSTimeZone对象的“市区名称”,“名称缩写”都会赋值为"GMT+0800","是否使用夏时制"则不会设置(默认不使用)。
//  注意!!!!该方法不做参数的范围检查!!!
+ (id)timeZoneForSecondsFromGMT:(NSInteger)seconds;       // 不做安全性检查

日历校验

iOS
设置->通用->语言与地域->日历。有公历日本日历佛教日历.公元2016年,东瀛日历是平成2八年。佛历2560年。
从而只要用户在安装中选东瀛日历,下面代码总括的l时间戳又不雷同了:64189900800

补救措施: 手工业安装NSDateFormatter的日历

    [format setCalendar: [[NSCalendar alloc]
                          initWithCalendarIdentifier:NSGregorianCalendar]];

照旧安装locale.日历能够由NSLocale 中
NSLocaleCalendar那么些天性内定
官方网址证实:

NSDateFormatter treats the numbers in a string you parse as if they were in the user’s chosen calendar. For example, if the user selects the Buddhist calendar, parsing the year 2010 yields an NSDate object in 1467 in the Gregorian calendar. (For more about different calendrical systems and how to use them, see Date and Time Programming Guide.)

12 小时制 和24小时制

  • HH :24小时制
  • hh :12 小时制

那是iOS
SDK3.一的bug,在设置中时区自动为London的时候,二四钟头制会自动关闭。自动为法兰西时区的时候,24小时制会开启。不过只要法兰西共和国用户手动选项1贰小时制,”HH”的格式不起成效,程序重返的是”0一:00
PM”那1二小时类型的日子。

参照博客:

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.

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″.

YYYY和yyyy

天文台,working with Date and
Time

Pay special attention to the year format specifier @"yyyy". It is different than the capitalized @YYYY, which represents the year of the date’s week and not the year of the day. 99% of the time, you probably want to use @”yyyy”.
  • yyyy is ordinary calendar year.

  • YYYY is week-based calendar
    year.“将那一年中率先周的周五用作二零一九年的第3天”.由此有时结果和yyyy同样,有时就会不一样

Year (in "Week of Year" based calendars). Normally the length specifies the padding, but for two letters it also specifies the maximum length. This year designation is used in ISO year-week calendar as defined by ISO 8601, but can be used in non-Gregorian based calendar systems where week date processing is desired. May not always be the same value as calendar year.

Date Field Symbol
Table

言语和时间制

没有错 0 0 ,那也有坑。例如部分日漫粉会把语言选为 “葡萄牙语”,关闭”二四-时辰制”.
这时候:

    NSDateFormatter *format = [[NSDateFormatter alloc] init];
    [format setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    [format setTimeZone:[NSTimeZone timeZoneWithName:@"Asia/Shanghai"]];

    [format setCalendar: [[NSCalendar alloc]
                          initWithCalendarIdentifier:NSGregorianCalendar]];
    NSDate *fromdate = [format dateFromString:timeString];
    long long time = (long long)[fromdate timeIntervalSince1970];
    NSLog(@"%@", fromdate);
    NSLog(@"%lld", time);

那样的代码NSDate对象为null.time为0.
换”时区”可能” 地域”后手动把二四-时辰制关闭,依然回到null.
具体原因,暂不掌握。

这时候敞开”24-小时制”或然format的格式改HH为hh
format setDateFormat:@"yyyy-MM-dd hh:mm:ss"]又有值重返。12小时制和二4小时制

方法:

    NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh"];

NSLocale对象能够钦命语言。

    NSLog(@"language:%@", [NSLocale preferredLanguages]);
    NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh"];
    [format setLocale:locale];
    NSLog(@"%@",[locale objectForKey:NSLocaleLanguageCode]);

输出结果:

language:(
 "ja-US",  // 用户选择的是日本语言
"zh-Hans-US",
"en-US"
)
2016-02-14 11:47:09.527 importDemo[3025:1406067] zh

今非昔比时区城市

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 亚洲必赢手机官网 版权所有