【问题标题】:Question about NSDateFormatter and NSCalendar (involving Timezones)关于 NSDateFormatter 和 NSCalendar 的问题(涉及时区)
【发布时间】:2011-08-02 02:08:10
【问题描述】:

我有以下代码:

    self.formatter = [[NSDateFormatter alloc] init];
    [formatter setTimeZone:timeZone];
    [formatter setDateFormat:@"YYYY-MM-dd hh:mm:ss a z"];
    timeStampForCity = [formatter stringFromDate:[NSDate date]];
    NSLog(@"%@", timeStampForCity);
    updateDate = [formatter dateFromString:timeStampForCity];
    NSLog(@"%@", updateDate);

NSLog(@"%@", timeStampForCity); 输出:

2011-08-01 10:05:50 PM EDT

NSLog(@"%@", updateDate); 输出:

2011-08-02 02:05:50 +0000

我需要updateDate 来显示当前时区的时间(例如,如第一个 NSLog() 输出所示)。我该如何正确地做到这一点?

编辑 1

我也有这个代码:

    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit| NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSTimeZoneCalendarUnit;
    NSDateComponents *dateComponents = [gregorian components:unitFlags fromDate:[NSDate date]];
    [dateComponents setTimeZone:[NSTimeZone timeZoneWithName:cityNameFormatted]];
    updateDate = [gregorian dateFromComponents:dateComponents];
    [gregorian release];

但它显示的时区在许多地区是关闭的。

提前感谢您的帮助。

【问题讨论】:

  • 有什么问题?当您转换为字符串时,您将获得您指定的格式。当您转换回日期时,自然会使用默认日期格式记录结果:NSDate 仅包含日期/时间信息,不包含格式信息。
  • 我需要 EDT 中的日期或我指定的任何其他时区。

标签: objective-c ios nsdate nsdateformatter nstimezone


【解决方案1】:

我们又来了……

日期是一个独立的时间点。它存在并将永远存在,无论人类和我们的时间测量设备是否存在。时区是人类的发明,可以帮助我们不要发疯。陪审团仍然在他们是否有效。 :P

当您谈到想要“EDT 或任何其他时区的日期”时,您并没有掌握日期是什么。时区只是如何显示时间点的一个方面。

所以,你有一个NSDate。这个日期是正确的日期,不管你在哪个时区。那么你如何“显示当前时区的时间”呢?你使用NSDateFormatter

NSDate 本质上是不可读的。有一些方法可以表示日期,例如从不同时间点开始的秒间隔(它本身就是一个任意长的间隔)。但是,要使日期人类可读,只能通过将其格式化为字符串来完成。所以,让我们这样做:

NSDate *myDate = [NSDate date]; // or whatever date you want to make human-readable
NSDateFormatter *f = [[NSDateFormatter alloc] init];
[f setDateStyle:NSDateFormatterLongStyle];
[f setTimeStyle:NSDateFormatterLongStyle];

NSArray *timeZoneNames = [NSTimeZone knownTimeZoneNames];
for (NSString *name in timeZoneNames) {
    NSTimeZone *tz = [NSTimeZone timeZoneWithName:name];
    [f setTimeZone:tz];
    NSLog(@"%@", [f stringFromDate:date]);
}

现在,显然这个输出会非常长(我的输出超过 400 行)。但这里是该输出的一个示例:

...
August 2, 2011 1:03:38 AM GMT-03:00
August 2, 2011 12:03:38 AM AST
August 2, 2011 12:03:38 AM GMT-04:00
August 1, 2011 11:03:38 PM EST
August 2, 2011 1:03:38 AM GMT-03:00
August 1, 2011 11:03:38 PM CDT
August 2, 2011 12:03:38 AM AST
August 2, 2011 1:03:38 AM GMT-03:00
August 1, 2011 10:03:38 PM CST
August 2, 2011 12:03:38 AM AST
August 2, 2011 12:03:38 AM GMT-04:00
August 1, 2011 11:03:38 PM GMT-05:00
August 1, 2011 10:03:38 PM MDT
August 1, 2011 10:03:38 PM MDT
August 2, 2011 12:03:38 AM GMT-04:00
August 1, 2011 11:03:38 PM CDT
August 1, 2011 11:33:38 PM GMT-04:30
August 2, 2011 1:03:38 AM GMT-03:00
August 1, 2011 11:03:38 PM EST
August 1, 2011 11:03:38 PM CDT
August 1, 2011 10:03:38 PM MDT
...

那么,我们在这里看到了什么? 相同的日期有一大堆不同的字符串表示!整洁的!换句话说,formatter 的时区用于确定输出字符串的外观。

因此:日期本身与时区NOTHING。如果您希望日期以某种方式看起来,您必须配置 formatter 使其看起来像这种方式。


更新从您的评论中,我想我得到了您想要的。您希望 日期组件 为特定时区格式化吗?换句话说,您有一个时间点,您想知道(比如说)美国东部时区的小时/分钟/秒?

如果是这样,那么你就根据日历

NSDate *date = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
[cal setTimeZone:[NSTimeZone timeZoneWithName:@"EST"]];

NSDateComponents *components = [cal components:NSUIntegerMax fromDate:date];
NSLog(@"%@", components);

这会给你:

<NSDateComponents: 0x100124240> 
 Calendar: <CFCalendar 0x100133e90 [0x7fff7605cea0]>{identifier = 'gregorian'} / Time Zone: EST (GMT-05:00) offset -18000
 Era: 1
 Year: 2011
 Month: 8
 Day: 2
 Hour: 9
 Minute: 47
 Second: 21
 Week of Month: 1
 Week of Year: 31
 Year for Week of Year: 2011
 Weekday: 3
 Weekday Ordinal: 1
 Quarter: 0

【讨论】:

  • 好吧,这一切我都知道。我想要做的是将针对某个时区格式化的 NSDate 传递给我制作的 CA 模拟时钟。对于大多数城市,它不会输出指定时区的时间。我的 NSMutableArray 中的零星显示正确,但不是全部显示。
  • 另外,我非常感谢您的广泛回答。我想我可能会因为长期关注这个问题而体验到隧道视野。我会看看我是否可以根据你的建议想办法为时钟设置动画
  • 这是另一个应该允许多个赞成票的答案。
  • @Dave-Delong 我将以下代码放入:timeZone = [NSTimeZone timeZoneWithName:cityNameFormatted]; NSCalendar *cal = [NSCalendar currentCalendar]; [cal setTimeZone:timeZone]; NSDateComponents *components = [cal components:NSUIntegerMax fromDate:[NSDate date]]; NSLog(@"%@", components); 但 NSLog 没有输出任何内容,但内存中的地址 我不认为我错过了什么那里
  • 好吧,我想通了,但我首先用特定时区初始化了一个 NSCalendar 对象,然后使用 NSDateComponents 为该时区的日历提取小时/分钟/秒。然后,我用检索到的小时/分钟/秒构建了一个字符串,并使用dateFromString: 生成日期。这更像是一种 hack,然后是一个合法的解决方案,但它确实有效。感谢您的所有帮助!
猜你喜欢
  • 2023-03-05
  • 2012-01-16
  • 2013-09-16
  • 2018-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多