在iOS开发中,经常会遇到各种各样的时间问题,8小时时差,时间戳,求时间间隔,农历等等。解决办法网上比比皆是,但大多零零散散,很多资料并没有说明其中问题。这里集中总结一下,以便于以后查阅和供大家参考。有我自己的理解,错漏之处请大家吐槽。
NSDate的8小时问题
初始化一个NSDate时间[NSDate date],获取的是零时区的时间(格林尼治的时间: 年-月-日 时:分:秒: +时区),而北京时间是东八区时间,因为时区不同,所以打印的时间相差了8小时。此刻表示的时间是一样的。
打印结果前面的时间是北京时间:2016-12-07 10:44:24.470。而date打印出来的时间显示少了8小时,因为它表示的是零时区(+0000)时间02:44:24。此刻对应东八区的北京时间就是10:44:24。只是时区不同,表示的时间点是一样的。好比1公斤和2斤,重量是一样的。[NSDate date]获取的时间单位是零时区(+0000),我们所要的北京时间的单位是东八区(+0800)。
系统会默认[NSDate date]获取的时间为零时区时间,而经过NSDateFormatter转化为字符串时间就是当前所在时区的准确时间,并没有8小时误差。
上文中NSDate时间转为字符串时间并没有设置NSDateFormatter的timeZone。不设置会默认使用当前所在的时区,与设置系统时区formatter.timeZone = [NSTimeZone systemTimeZone]的效果是一样的。
也可以设置时区,获取指定时区的字符串时间
NSDateFormatter的指定格式是:@"yyyy-MM-dd HH:mm:ss Z"。这里面的Z指的是时区。要转化的字符串时间格式必须和这个格式匹配,上面给定的字符串时间是:@"2016-12-07 14:06:24 +0800",是一个东八区时间,转化为NSDate后是零区时间2016-12-07 06:06:24 +0000,字面显示上少了8小时,其实时间一样。
其实如果上面给定的字符串时间为@"2016-12-07 14:06:24 +0000",转化出来的NSDate时间会完全一样,因为字符串时间为零时区时间,不存在时区误差。大家可以试一下。
当不指定字符串时间的时区时,即没有后面的+0800,同时要把NSDateFormatter时间格式里的Z去掉,保证格式匹配。系统会认为字符串时间是系统所在时区的时间,转化为NSDate时间是零时区时间。
同样,也可以使用formatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];这种方式指定字符串时间的时区,和用Z对应+0000是一样的。
因为[NSDate date]得出的时间是零时区时间,当我们要获取当前所在时区的NSDate时间时,通常会用以下方法:
上面代码中zone是当前时区,interval是当前时区和零时区时间的差值,最后结果localDate是零时区时间date加上这个差值interval,得到当前时区的NSDate时间。更有甚者,在开发中直接加8*60*60或28800这样的值,因为相差8小时嘛。这样在东八区没问题,在其他时区时间就错了。
其实这种做法是不科学的,因为得到的最终时间还是零时区时间,时间后面明显是+0000,在使用中一般不显示时区,所以认为当做当前时区的时间使用也未尝不可。此为大坑!
坑1:
这时如果转为字符串时间,又会增加8小时。因为做时间转换的时候,系统会认为这个NSDate是零时区,得到的字符串时间是东八区的。
解决办法是:将错就错,字符串时间也设置为零时区的字符串时间。从深坑跌入更深的坑!
这里的@"UTC"是指世界标准时间,也是现在用的时间标准,东八区比这个时间也是快8小时,这里填@"GMT"也是可以的。
坑2:
在与后台交互时,有时需要+0000时区,这时只能手动拼接字符串更改这个时区字段,改为正确的时区。
所以,在开发中尽量不要这么做,当时间要求显示、存储或与后台交互的时候,使用字符串时间!不要使用转化的NSDate。
时间换算,时间戳的概念
时间戳是指1970年1月1日0时0分0秒到当前时间的秒数。注意:这里的当前时间是指零时区的NSDate时间。
2016-12-07 16:13:57.834 timeTest[35211:3255842] 系统零时区NSDate时间 = 2016-12-07 08:13:57 +0000
2016-12-07 16:13:57.834 timeTest[35211:3255842] 系统零时区NSDate时间转化为时间戳 = 1481098438
2016-12-07 16:13:57.835 timeTest[35211:3255842] 转化为本地NSDate时间 = 2016-12-07 16:13:57 +0000
2016-12-07 16:13:57.835 timeTest[35211:3255842] 本地NSDate时间转化为时间戳 = 1481127238
2016-12-07 16:13:57.836 timeTest[35211:3255842] 最终转为字符串时间1 = 2016-12-07 16:13:57 +0800, 时间2 = 2016-12-08 00:13:57 +0800
NSDateComponents *dateComps = [cal components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond|NSCalendarUnitWeekday|NSCalendarUnitWeekOfMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitTimeZone fromDate:date];
NSLog(@
"时间 = %@"
, date);
NSLog(@
"年=%ld,月=%ld,日=%ld,时=%ld,分=%ld,秒=%ld,周=%ld,本月第%ld周,本年第%ld周,时区=%@"
, dateComps.year, dateComps.month, dateComps.day, dateComps.hour, dateComps.minute, dateComps.second, dateComps.weekday, dateComps.weekOfMonth, dateComps.weekOfYear, dateComps.timeZone.name);
NSDateComponents创建方法中添加的枚举NSCalendarUnit,是后面要获取的年月日时分秒必须对应添加的。比如要获取年dateComps.year,就需要添加枚举NSCalendarUnitYear。
可以看到,[NSDate date]时间可以使用NSCalendar直接获取当前时区的时分秒,打印的时和时区即可看出。这是[NSCalendar currentCalendar]日历对象初始化的原因,也可以用[[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]指定Identifier的方式初始化阳历日历。可以试试指定Identifier为NSCalendarIdentifierChinese,打印的是中国农历。
dateComps.weekOfMonth是今天属于本月的第几周。
dateComps.weekOfYear是今天属于本年的第几周。
dateComps.weekday是星期,这个和日常使用有些不同。上述程序打印的是周=4,但2016-12-07是周三。这里weekday的对应关系是:周日-1,周一-2,周二-3,周三-4,周四-5,周五-6,周六-7。毕竟国外惯例周日是每周的第一天。
获取农历的工具方法,可根据需求添加农历节日和二十四节气
NSArray *cDayName = [NSArray arrayWithObjects:@
"*"
,@
"初一"
,@
"初二"
,@
"初三"
,@
"初四"
,@
"初五"
,@
"初六"
,@
"初七"
,@
"初八"
,@
"初九"
,@
"初十"
,@
"十一"
,@
"十二"
,@
"十三"
,@
"十四"
,@
"十五"
,@
"十六"
,@
"十七"
,@
"十八"
,@
"十九"
,@
"二十"
,@
"廿一"
,@
"廿二"
,@
"廿三"
,@
"廿四"
,@
"廿五"
,@
"廿六"
,@
"廿七"
,@
"廿八"
,@
"廿九"
,@
"三十"
,nil];
NSArray *cMonName = [NSArray arrayWithObjects:@
"*"
,@
"正月"
,@
"二月"
,@
"三月"
,@
"四月"
,@
"五月"
,@
"六月"
,@
"七月"
,@
"八月"
,@
"九月"
,@
"十月"
,@
"冬月"
,@
"腊月"
,nil];
const int wMonthAdd[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
const int wNongliData[100] = {2635,333387,1701,1748,267701,694,2391,133423,1175,396438
,3402,3749,331177,1453,694,201326,2350,465197,3221,3402
,400202,2901,1386,267611,605,2349,137515,2709,464533,1738
,2901,330421,1242,2651,199255,1323,529706,3733,1706,398762
,2741,1206,267438,2647,1318,204070,3477,461653,1386,2413
,330077,1197,2637,268877,3365,531109,2900,2922,398042,2395
,1179,267415,2635,661067,1701,1748,398772,2742,2391,330031
,1175,1611,200010,3749,527717,1452,2742,332397,2350,3222
,268949,3402,3493,133973,1386,464219,605,2349,334123,2709
,2890,267946,2773,592565,1210,2651,395863,1323,2707,265877};
static int nTheDate,nIsEnd,m,k,n,i,nBit;
nTheDate = (wCurYear - 1921) * 365 + (wCurYear - 1921) / 4 + wCurDay + wMonthAdd[wCurMonth - 1] - 38;
if
((!(wCurYear % 4)) && (wCurMonth > 2))
nTheDate = nTheDate + 1;
nIsEnd = 0;
m = 0;
while
(nIsEnd != 1) {
if
(wNongliData[m] < 4095)
k = 11;
k = 12;
n = k;
while
(n>=0) {
在iOS开发中,经常会遇到各种各样的时间问题,8小时时差,时间戳,求时间间隔,农历等等。解决办法网上比比皆是,但大多零零散散,很多资料并没有说明其中问题。这里集中总结一下,以便于以后查阅和供大家参考。有我自己的理解,错漏之处请大家吐槽。NSDate的8小时问题NSDate转字符串时间初始化一个NSDate时间[NSDate date],获取的是零时区的时间(格林
对于将N
SDate
类型转换为
时间
戳,相信大家肯定都会,这样的示例代码,在百度等搜索引擎上面一搜索就是一大篇的东西,但是,大家有没有注意到的是 通过那些方法转换得到的
时间
戳是 10位的数值,这个数值在转化为 N
SDate
类型的时候,就会出点儿错,你会发现,每一个
时间
的 毫秒都是为000的;
错误的毫秒输出
而正确的应该是下面这样的输出:
正确的毫秒输出
好了,接下来就是问题所在了:其实呢,并不是我们代码出错了,而是因为 [[N
SDate
date
] timeIntervalSince1970] 虽然可以获取到后面的毫秒、微秒 ,但是在保存的时候省略掉了。如一个
时间
戳不省略的情况下为
N
SDate
和 NSString 之间的相互转换是平常常用的方法,应用场景非常多。
N
SDate
和NSString之间的相互转换需要使用N
SDate
Formatter,N
SDate
Formatter提供了stringFrom
Date
和
date
FromString这两个方法,让我们进行转换。
N
SDate
Formatter转换格式
y 年份不带前导零(2009、2019)
yy 显示...
让技术开发讨论更纯粹!CocoaChina问答荣誉每周、每月龙虎榜!
1、如何如何将一个字符串如“ 2011
08
26134106”装化为任意的日期
时间格式
,下面列举两种类型:
NSString* string = @"2011
08
26134106";
N
SDate
Formatter *inputFormatt
在
iOS
开发中,经常会遇到各种各样的
时间
问题,8小时时差,
时间
戳,求
时间
间隔,农历等等。解决办法网上比比皆是,但大多零零散散,很多资料并没有说明其中问题。这里集中总结一下,以便于以后查阅和供大家参考。有我自己的理解,错漏之处请大家吐槽。
N
SDate
的8小时问题
N
SDate
转字符串
时间
初始化一个N
SDate
时间
[N
SDate
date
],获取的是零
时区
的
时间
(格林尼治的
时间
: 年-月-...
在
iOS
系统中,可以通过N
SDate
和NSTimeZone类来获取手机设定的
时区
信息。首先,可以使用N
SDate
类来获取当前的系统
时间
,然后使用NSTimeZone类的方法来获取
时区
信息。具体步骤如下:
1. 首先创建一个N
SDate
对象,可以使用[N
SDate
date
]方法来获取当前系统的
时间
。
2. 然后可以使用NSTimeZone的方法来获取当前手机设定的
时区
信息,可以使用[NSTimeZone systemTimeZone]方法来获取系统当前的
时区
信息。如果需要获取所有的可用
时区
信息,可以使用[NSTimeZone knownTimeZoneNames]方法获取一个包含所有可用
时区
名字的数组。
3. 获取到
时区
信息后,就可以根据需要对
时间
进行转换或者显示,可以使用NSTimeZone类的方法来进行
时区
的转换,比如使用timeZoneForSecondsFromGMT:方法根据指定的时差来获取相应的
时区
信息。
总的来说,在
iOS
系统中获取手机设定的
时区
信息可以通过N
SDate
和NSTimeZone类来实现,通过这些方法可以获取到系统当前的
时区
信息并对
时间
进行相应的转换和显示。