使用NSDateFormatter将UTC转换为本地时间

cat*_*eof 9 time cocoa cocoa-touch nsdateformatter date-parsing

我从iOS应用中的服务器获取以下字符串:

20140621-061250

如何将其转换为当地时间?

如何定义日期格式化程序?它是否正确?

dateFormatter.dateFormat = @"YYYYMMd-HHmmss"; 
Run Code Online (Sandbox Code Playgroud)

Car*_*zey 36

问题并没有明确指出转换的含义,但是无论最终目标如何,您应该做的第一件事就是使用正确配置来正确解析服务器响应NSDateFormatter.这需要指定正确的格式字符串,并且必须在格式化程序上明确设置时区,否则它将从本地时间推断出来,这在大多数情况下是不正确的.

指定格式字符串

让我们看看提供的输入字符串:

20140621-061250

这使用了年份的四位数字,月份的两位数字(零填充)和当天的两位数(可能也是零填充).接下来是a -,然后两位数表示小时,2位数表示分钟,2位数表示秒.

参考Unicode日期格式标准,我们可以通过以下方式派生格式字符串.表示日历年的四位数将替换yyyy为格式字符串.使用MM了一个月,dd这一天.接下来就是字面意思-.几个小时,我认为它将是24小时格式,否则这个响应是模糊的,所以我们使用HH.分钟是mm秒和秒ss.连接格式说明符会产生以下格式字符串,我们将在下一步中使用它:

yyyyMMdd-HHmmss
Run Code Online (Sandbox Code Playgroud)

在我们的程序中,这看起来像:

NSString *dateFormat = @"yyyyMMdd-HHmmss";
Run Code Online (Sandbox Code Playgroud)

配置输入日期格式化程序

上面的时间格式没有指定时区,但是因为您已经为服务器响应提供了表示UTC时间的规范,我们可以将其编码到我们的应用程序中.因此,我们实例化一个NSDateFormatter,设置正确的时区,并设置日期格式:

NSTimeZone *inputTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
NSDateFormatter *inputDateFormatter = [[NSDateFormatter alloc] init];
[inputDateFormatter setTimeZone:inputTimeZone];
[inputDateFormatter setDateFormat:dateFormat];
Run Code Online (Sandbox Code Playgroud)

将输入字符串转换为 NSDate

出于演示目的,我们对从服务器响应中收到的字符串进行硬编码; 你将这个定义替换为inputString从服务器获得的定义:

NSString *inputString = @"20140621-061250";
NSDate *date = [inputDateFormatter dateFromString:inputString];
Run Code Online (Sandbox Code Playgroud)

此时,我们有必要的对象来进行任何进一步的转换或计算 - NSDate表示服务器传达的时间.请记住,a NSDate只是一个时间戳 - 它与时区无关,它只在转换日期的字符串表示或从日历的表示形式转换时起作用NSDateComponents.

下一步

问题没有明确指出需要什么类型的转换,因此我们将看到一个格式化日期的示例,以与服务器响应相同的格式显示(尽管我不能想到这个可能的用例)特别是代码,老实说).步骤非常相似 - 我们指定格式字符串,时区,配置日期格式化程序,然后从日期生成一个字符串(以指定的格式):

NSTimeZone *outputTimeZone = [NSTimeZone localTimeZone];
NSDateFormatter *outputDateFormatter = [[NSDateFormatter alloc] init];
[outputDateFormatter setTimeZone:outputTimeZone];
[outputDateFormatter setDateFormat:dateFormat];
NSString *outputString = [outputDateFormatter stringFromDate:date];
Run Code Online (Sandbox Code Playgroud)

由于我在UTC-06:00,打印outputString提供以下内容:

20140621-001250

如果您向用户显示此日期,或者使用an 来获取实例在日期进行算术运算或计算,那么您可能会想要使用setDateStyle:setTimeStyle:不是格式字符串.向用户显示详细日期字符串的示例:NSCalendarNSDateComponents

NSTimeZone *outputTimeZone = [NSTimeZone localTimeZone];
NSDateFormatter *outputDateFormatter = [[NSDateFormatter alloc] init];
[outputDateFormatter setTimeZone:outputTimeZone];
[outputDateFormatter setDateStyle:NSDateFormatterFullStyle];
[outputDateFormatter setTimeStyle:NSDateFormatterFullStyle];
NSString *outputString = [outputDateFormatter stringFromDate:date];
Run Code Online (Sandbox Code Playgroud)

outputString在这里打印给我们以下内容:

2014年6月21日星期六上午12:12:50山区夏令时

请注意,适当设置时区将处理夏令时的转换.使用上面的格式化器样式代码将输入字符串更改为"20141121-061250"会给我们显示以下日期(请注意,Mountain Standard Time是UTC-7):

2014年11月20日星期四晚上11:12:50山区标准时间

摘要

每当您以表示日历日期和时间的字符串形式获取日期输入时,您的第一步是使用已NSDateFormatter配置的输入格式,时区以及可能的区域设置和日历来转换它,具体取决于输入的来源和您的要求.这将产生一个NSDate毫不含糊的时刻表示.创建之后NSDate,可以根据应用程序的需要对其进行格式化,设置样式或将其转换为日期组件.


Dan*_*iel 9

要将字符串放入NSDate,您可以像这样使用NSDateFormatter:

NSString *myDateAsAStringValue = @"20140621-061250"
NSDateFormatter *df = [[NSDateFormatter alloc] init];    
[df setDateFormat:@"yyyyMMdd-HHmmss"];
NSDate *myDate = [df dateFromString: myDateAsAStringValue];
Run Code Online (Sandbox Code Playgroud)

您可能想阅读有关使用日期和时间的这篇文章

编辑:

要将其解析为UTC,您必须添加以下行:

[df setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
Run Code Online (Sandbox Code Playgroud)

此外,当您使用NSLog打印它时,如果您使用相同的NSDateFormatter,您将获得输入字符串作为输出(因为您应用解析函数的反转).

以下是完整的代码,用于解析和获取标准格式的输出:

//The input
NSString *myDateAsAStringValue = @"20140621-061250";

//create the formatter for parsing
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
[df setDateFormat:@"yyyyMMdd-HHmmss"];

//parsing the string and converting it to NSDate
NSDate *myDate = [df dateFromString: myDateAsAStringValue];

//create the formatter for the output
NSDateFormatter *out_df = [[NSDateFormatter alloc] init];
[out_df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssz"];

//output the date
NSLog(@"the date is %@",[out_df stringFromDate:myDate]);
Run Code Online (Sandbox Code Playgroud)


Kin*_*ard 8

使用NSDate扩展的Swift中的一个可能的解决方案(也许它可以帮助未来的这个问题的观众):

import UIKit

// For your personal information: NSDate() initializer 
// always returns a date in UTC, no matter the time zone specified.
extension NSDate {
    // Convert UTC (or GMT) to local time
    func toLocalTime() -> NSDate {
        let timezone: NSTimeZone = NSTimeZone.localTimeZone()
        let seconds: NSTimeInterval = NSTimeInterval(timezone.secondsFromGMTForDate(self))
        return NSDate(timeInterval: seconds, sinceDate: self)
    }

    // Convert local time to UTC (or GMT)
    func toGlobalTime() -> NSDate {
        let timezone: NSTimeZone = NSTimeZone.localTimeZone()
        let seconds: NSTimeInterval = -NSTimeInterval(timezone.secondsFromGMTForDate(self))
        return NSDate(timeInterval: seconds, sinceDate: self)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是错的.日期没有时区.这只是一个时间点.通过这样做,你正在改变日期,你不应该.如果您需要知道不同时区的时间组件(如小时),您应该使用日历方法`func dateComponents(在timeZone:TimeZone,从date:Date) - > DateComponents`或使用DateFormatter并更改时区以显示UTC时间 (2认同)