iOS日期格式的本地化

iOS日期格式的本地化

最近公司制作了一款国际版App,测试过程中时间的显示一直都OK。但是有一天一测试人员展示了一张截图,显示他的手机上一条购买记录的购买时间显示为:2558-01-05 xx:xx:xx。

为什么会显示为这样一个奇怪的年份呢?

时间的相关知识

在编程语言中,时间的本质是一个整数(浮点数),表示当前时间自1970年1月1日00:00:00秒后的(毫)秒数。
在iOS系统上NSDate类用的是浮点数,单位为秒数。
这种表示很容易比较时间的先后,计算时间的差值。

世界各地的人们在书写和表达时间时有各自格式、历法、时区、冬夏令时。

####格式:

  • yyyy-mm-dd HH:MM:ss
  • mm/dd/yyyy HH:MM:ss
  • dd/mm/yyyy HH:MM:ss

历法:

  • 世界现在的通用公历(格历)
  • 佛历
  • 日本历
  • 中国农历

时区:

  • 地球划分为24个时区,以英国格林尼治天文台子午线开始分为东西各12个时区。同一时间在不同的时区的显示结果不同。
  • 北京时间为东八区,中国疆域越3到4个时区。乌鲁木齐日出比北京晚两个小时。

冬夏令时

  • 以主时区日出时间保持稳定为目的的一种表示时间的方式。夏天将时间提前一个小时。所以调整日会出现当天有两个凌晨一点或某一天只有23个小时的情况。
  • 中国大陆也曾经使用过这种计时方式。

时间的本地化

大部分用户并没有上面时间的相关知识。所以需要把时间展示为当地人能理解的相关方式。

所以在呈现时间时,需要考虑格式化的方式。

苹果公司建议不要指定具体的格式字符串,使用苹果内置的格式来把时间的呈现格式本地化。

1
2
3
4
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateStyle:NSDateFormatterLongStyle];
[df setTimeStyle:NSDateFormatterMediumStyle];
NSString * formatDateString = [df stringFromDate:[NSDate dateWithTimeIntervalSince1970:...]];

本地化表示的时间内容到时间的转换

有时候我们需要从一个本地化的时间表示来获得原始时间值。
这时候我们需要知道时间表示的4个重要信息:历法、时区、冬夏令时、格式。

下面是一个获取IAP购买凭证中的购买时间的代码例子。

1
2
3
4
5
6
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[formatter setCalendar:[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]];
NSString *dateString = ......;
NSDate *purchaseDate = [formatter dateFromString:dateString];

时间内容的存储

从MVC的角度来说: NSDate是M, “2015-04-16 08:08:00”是时间的一个V表示。
所以最优方法是保存NSDate,也就是时间表示的秒数。

其实数据库也就是底层就是用数值型类型来表示时间的。

如果在数据模型中直接保存时间的数据化表示,那么在应用国际化后就会出现显示和统计上的混乱。

问题的答案

佛历的2558年就是公元纪年的2015年。测试人员不小心把手机日历改为佛历了。而开发人员是使用yyyy-MM-dd HH:mm:ss来格式化时间的。
改用苹果的建议的方式,日期显示为 “佛历2558年x月x日 00:34”。
在公历下显示为:2015年x月x日 10:55”。

至此问题解决。