NSDate与不同时区的另一个NSDate的本地时间相同

时间:2016-07-09 14:16:50

标签: ios objective-c calendar nsdate nscalendar

我有一个约会时间:

Friday, July 8, 2016 at 6:30:00 PM India Standard Time

我想要这样的约会时间:

Friday, July 8, 2016 at 6:30:00 PM Central Daylight Time

我不想将NSDateFormatter的日期从一个时区转换为另一个时区,因为此次转换会给我

Friday, July 8, 2016 at 8:00:00 AM Central Daylight Time

我想要相同的日期时间,但是在不同的时区。我怎么能这样做?

2 个答案:

答案 0 :(得分:1)

您可以通过将日期拆分为原始时区中的组件,在组件上设置目标时区以及检索结果日期(它不会是相同的日期/时间)来实现此目的。

import Foundation

let calendar = NSCalendar.currentCalendar()
let date = NSDate()
let origTz = NSTimeZone(abbreviation: "IST")!
let destTz = NSTimeZone(abbreviation: "CDT")!
let components = calendar.componentsInTimeZone(origTz, fromDate: date)
components.timeZone = destTz
let res = components.date!
let fmt = NSDateFormatter()
fmt.timeZone = destTz
fmt.locale = NSLocale(localeIdentifier: "en_US_POSIX")
fmt.dateStyle = .FullStyle
fmt.timeStyle = .FullStyle
fmt.timeZone = origTz
print(fmt.stringFromDate(date)) // Sunday, July 10, 2016 at 2:14:21 AM India Standard Time
fmt.timeZone = destTz
print(fmt.stringFromDate(res))  // Sunday, July 10, 2016 at 2:14:21 AM Central Daylight Time

答案 1 :(得分:1)

dasblinkenlight的答案绝对正确,但我会更全面地解释一下,并在ObjC中显示步骤而不是Swift。你不希望在不同的时区有相同的日期;你想要相同的当地时间(或墙上时间):一个人看到时钟时会看到什么。

同一日期在不同地区有不同的当地时间:2016年7月8日星期五下午6:30:00印度标准时间 2016年7月8日星期五8:00 :00日中部夏令时。当加尔各答的一个人看着时钟并看到下午6:30时,奥马哈的一个人看着她的时钟会在上午8点看到。

首先,仅为了演示的目的,我们将使用日期解析器从您给出的字符串创建原始日期。您只需从通知对象中获取日期。

NSString * originalDateString = @"Friday, July 8, 2016 at 6:30:00 PM India Standard Time";

NSDateFormatter * parser = [NSDateFormatter new];
[parser setDateStyle:NSDateFormatterFullStyle];
[parser setTimeStyle:NSDateFormatterFullStyle];
NSDate * originalDate = [parser dateFromString:originalDateString];

虽然原始字符串包含时区信息,但日期不包含。然而,墙上时间取决于区域,因此我们需要一个时区对象用于下一步。您也可以从通知对象中获取此信息。在这里,我们只需从其标识符NSTimeZone * originalTZ = [NSTimeZone timeZoneWithAbbreviation:@"IST"];

创建一个

我们需要NSDateComponents来表示区域中日期的本地时间值。 NSCalendar负责将日期分成这些组件:

NSCalendar * cal = [NSCalendar currentCalendar];
NSDateComponents * localComps;
localComps = [cal componentsInTimeZone:originalTZ
                              fromDate:originalDate];

如果您现在检查localComps,您会看到这些值封装了您期望的待机时间:2016-07-08 18:30:00。现在我们已经分解了这些值,我们基本上可以将它们放入另一个区域而无需翻译。也就是说,如上所述,不将值重新解释为绝对时间,这将给出2016-07-08 08:00:00。只需更改时区(再次,您将从通知而不是缩写中获取区域):

NSTimeZone * destinationTZ = [NSTimeZone timeZoneWithAbbreviation:@"CDT"];
[localComps setTimeZone:destinationTZ];

现在日历可以从这些组件构造一个新的日期对象。 NSDate * destinationDate = [cal dateFromComponents:localComps]; *

此日期是与时区无关的时刻,表示2016年7月8日星期五下午6:30:00中部夏令时。与任何NSDate一样,如果您只是将其打印出来,它将以GMT格式化。如果要查看预期的墙时间值,则需要使用设置为目标时区的格式化程序。

*正如dasblinkenlight的回答显示的那样,localComps有一个关联的日历,所以它也能够创建一个日期。我认为这会更清楚一点。