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显然,两个值不一样,而且在纽约时区下计算出的时间戳的值更大。

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 的时间戳。

整个地球分为二十四时区,每个时区都有自己的本地时间。但是在全球范围,我们需要一个标准时间。我们熟悉的标准时间是 格林尼治时间。格林尼治标准时间(中国大陆翻译:格林尼治平均时间或格林尼治标准时间,台、港、澳翻译:格林威治标准时间;英语:Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义为通过那里的经线。自1924年2月5日开始,格林尼治天文台每隔一小时会向全世界发放调时信息。理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空最高点时)的时间。由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能与实际的太阳时有误差,最大误差达16分钟。由于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治时间已经不再被作为标准时间使用。现在的标准时间,是由原子钟报时的UTC。其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间。

北京时区是东八区,领先UTC八个小时。时区差东为正,西为负。在此,把东八区时区差记为 +0800。纽约的时区是西五区,比UTC落后五个小时,记为 -0500. 即北京时间领先纽约时间十三个小时.

UTC 时间为1970年1月1号00:00:00的时候。北京时间是1970年1月1号8点,纽约时间还是1969年12月31号19:00。想象,每个时区有自己的时间坐标轴,原点代表的时间点是UTC的“1970年1月1号00:00:00”, 在坐标上标出各自的"2016-02-06 00:00:00"这一点,它们离原点的距离就是我们要算的时间戳。

timetamp.png

显然,将"2016-02-06 00:00:00"转化为格林尼治标准的时间戳。在纽约时区计算出来的值要比北京时区大。

如果将"2016-02-06 00:00:00"是服务端(东八区)下发的时间,我们在客户端需要转为时间戳,建议,把NSDateFormatter的时区设定在东八区。

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

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年,日本日历是平成28年。佛历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.1的bug,在设置中时区自动为纽约的时候,24小时制会自动关闭。自动为法国时区的时候,24小时制会开启。但是如果法国用户手动选择12小时制,"HH"的格式不起作用,程序返回的是"01:00 PM"这12小时类型的日期。

参考博客:

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.“将这一年中第一周的周日当作今年的第一天”.因此有时结果和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 ,这也有坑。比如一些日漫粉会把语言选为 "日语",关闭"24-小时制". 这时候:

    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.
换"时区"或者" 地域"后手动把24-小时制关闭,还是返回null. 具体原因,暂不明白。

此时开启"24-小时制"或者format的格式改HH为hh format setDateFormat:@"yyyy-MM-dd hh:mm:ss"]又有值返回。12小时制和24小时制

方法:

    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

iOS客户端NSDateFormatter那些坑相关推荐

  1. 汉信码在iOS客户端中的应用和遇到的坑

    先简单介绍一下的 汉信码,基本上和 QRCode 即二维码 大差不差,可但是,二维码 一般扫描出来是 非中文的字符串(一般为链接),这就是汉信码区别于二维码的地方,汉信码是涵盖中文的,而且是国家自主研 ...

  2. 开源中国iOS客户端学习

    开源中国iOS客户端学习 续写前言 <开源中国iOS客户端学习>续写前系列博客    http://blog.csdn.net/column/details/xfzl-kykhd.html ...

  3. iOS 客户端基于 WebP 图片格式的流量优化(下)

    在iOS 客户端基于 WebP 图片格式的流量优化(上)这篇文章中,已经介绍了WebP格式图片的下载使用,仅仅只有这样还远远不够,还需要对已经下载的图片数据进行缓存. 曾经有句名言『计算机世界有两大难 ...

  4. 58同城iOS客户端Hybrid框架探索

    作者:杜艳新,刘文军.58同城iOS高级研发工程师,专注于App Hybrid框架的架构研发,主导了58同城App的Hybird混合研发的系统架构以及研发. 责编:唐小引,欢迎技术投稿.约稿.给文章纠 ...

  5. 58 同城 iOS 客户端组件化演变历程

    导语: 架构的演进是为业务不断发展服务的,架构不能脱离业务,这是最基本的出发点.58 同城 iOS 客户端随着业务量和用户量的持续增长,架构也是不断受到挑战,采用什么样的架构去适应这些变化,对技术人员 ...

  6. 58 同城 iOS 客户端 Hybrid 框架探索

    [CSDN 编者按]58 同城 iOS 客户端的 Hybrid 框架在最初设计和演进的过程中,遇到了许多问题.为此,整个 Hybrid 框架产生了很大的变化.本文作者将遇到的典型问题进行了总结,并重点 ...

  7. 笔记|滴滴iOS客户端的架构,组件化,技术选型

    笔记来源infoq:滴滴iOS客户端的架构演变之路 1,状态机,把订单中的阶段,例如:出租车的等待抢单.出租车的等待接驾.专车的等待抢单.专车的等待接驾,都当成一种独立的状态,每 个状态机只需要知道可 ...

  8. iOS 入门开发踩坑实录

    其实人生也没有什么道理可讲,但是我们不必丧气,还是要期待,人生有奇遇. 前言 苹果开发者:iOS Developer 最近因为工作需要要开始搞iOS了,简单记录下我收集和学习的过程. 学习资料准备 组 ...

  9. 开源中国iOS客户端学习——(一)Prefix.pch文件

    2019独角兽企业重金招聘Python工程师标准>>> 当我们新建一个工程的时候,在Supporting FIles文件下会看到一个以  -Prefix.pch结尾文件的文件,pch ...

最新文章

  1. python第二大奇数_python-2.7 – matplotlib,包含奇数个子图
  2. NetBeans Weekly News 刊号 # 27 - Sep 24, 2008
  3. BZOJ 4034: [HAOI2015]T2 树链剖分
  4. 以“术”彰“道”,用匠心做技术—对话阿里云MVP刘洪峰
  5. MediaRecorder录像怎么旋转呀?
  6. 日常生活开支记账明细_中小企业真的需要代理记账吗?
  7. linux bcc_使用bcc / BPF在Linux中分析性能的7种工具
  8. 蔚来明年推出Gemini 该系列保持高端定位?
  9. linux之iftop命令
  10. IDEA上传项目到SVN
  11. 柯尼卡美能达一体机 扫描文件,不是全彩的,就首页和尾页是彩色,中间黑白
  12. CS188-Project 4
  13. 香农编码的gui编码_编码香农编码
  14. 如何存放青龙脚本文件(不用复制)
  15. 紫光华宇拼音输入法使用技巧
  16. Express的使用
  17. c语言数字和字母运算,计算器中的字母CE、C、MR、MC、MS、M+、M-等等各是什么意思?让我来告诉你吧!...
  18. C语言 一步步教你做一个带有图形界面的冒险小游戏
  19. 苹果推送通知办事教程 Apple Pushnb
  20. 从少儿编程讲讲开发行业的大趋势

热门文章

  1. android 斜边_撸了一个“可爱”的环形 Android 图表
  2. 企业级API网关的设计
  3. 微信公众平台开发30分钟入门教程
  4. oracle 分区 默认分区,Oracle 分区表分配分区
  5. 1601 - 挖胡萝卜
  6. 苹果启用iPhone 11 Pro Max,新增墨绿色?
  7. Java入门基础:Java JDBC封装简单的访问MySQL数据库类(BaseDao)
  8. 阿里巴巴开源技术汇总:115个软件(六)
  9. python遍历字符串数组_Python遍历numpy数组的实例
  10. 开心测试卷答案软件六下外研版,外研版(一起)英语六年级下册 Module 4 模块测试卷(含答案).doc...