【问题标题】:Incorrect time string with NSDateFormatter with Daylight Saving Time带有夏令时的 NSDateFormatter 的时间字符串不正确
【发布时间】:2015-02-10 17:35:58
【问题描述】:

我在我的应用程序中使用CET 作为我的默认timezone。在德国 Daylight 节省时间将从 2015 年 3 月 29 日开始。现在我正在做一些测试,看看我的日期是否会在将来正确转换。我使用以下代码对其进行了测试。

NSTimeZone *timeZone = [NSTimeZone timeZoneWithAbbreviation:@"CET"];
[NSTimeZone setDefaultTimeZone:timeZone];

NSDate *now = [NSDate date]; // 10 Feb, 2015
NSDate *dateAfter29March = [now dateByAddingMonths:2]; // 10 April, 2015

NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss ZZZ"];
[formatter setTimeZone:timeZone];

NSLog(@" NOW DATE -> %@",[formatter stringFromDate:now]);
NSLog(@" DATE AFTER 29 March -> %@",[formatter stringFromDate:dateAfter29March]);

添加月份的分类方法是

- (NSDate *)dateByAddingMonths:(NSInteger) dMonths {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.month = dMonths;
    NSCalendar *calendar = [NSCalendar currentCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

控制台输出如下:

NOW DATE -> 2015-02-10 18:28:05 +0100
DATE AFTER 29 March -> 2015-04-10 18:28:05 +0200

我预计 3 月 29 日之后的约会时间是 17:28:05,因为现在比白天时间少一小时。我究竟做错了什么?

PS:我也尝试在标签中设置输出字符串,并没有发生任何变化。

【问题讨论】:

  • 显示dateByAddingMonths:的代码。
  • 是的,问题是你的方法dateByAddingMonths:。我在操场上试过var dateAfter29March = now.dateByAddingTimeInterval(2*30*24*60*60),效果很好(显示:"Apr 11, 2015, 7:49 PM",现在=Feb 10, 2015, 6:53 PM")。
  • 我已经更新了我的代码。
  • @Q80 永远不要使用这样的代码添加时间间隔。
  • @AbidHussain 添加一些 NSLog 语句来记录 nowdateAfter29March 除了记录相应的字符串。

标签: ios objective-c swift nsdate nsdateformatter


【解决方案1】:

我真的不明白你在抱怨什么。

您要求操作系统将日期添加两个月。添加两个月意味着它使用日历,并同时返回两个月后的日期,即该月的同一天。它应该将 DST 的变化考虑在内,而且确实如此。这就是增加两个月的意思。

想象一下,我们总是在每月的第一天早上 10 点开会。无论是否是夏令时,您都希望在上午 10 点开会。

【讨论】:

  • 我喜欢那个会议的例子。由于我遇到了 DST 问题,我不再喜欢 DST。在此之前,我是中立的。 PostgreSQL 至少存储时区数据,MySQL 不存储:P
【解决方案2】:

试试这个;

[NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

NSDate *now = [NSDate date]; // 10 Feb, 2015
NSDate *dateAfter29March = [self dateByAddingMonths:2 date:now]; // 10 April, 2015


NSLog(@"now -> %@", now);
NSLog(@"dateAfter29March -> %@", dateAfter29March);
NSLog(@"========================================");


NSTimeZone *timeZone = [NSTimeZone timeZoneWithAbbreviation:@"CET"];

NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss ZZZ"];
[formatter setTimeZone:timeZone];

NSLog(@"NOW DATE -> %@",[formatter stringFromDate:now]);
NSLog(@"DATE AFTER 29 March -> %@",[formatter stringFromDate:dateAfter29March]);

对我来说效果很好。查看日志

now -> 2015-02-11 06:01:56 +0000
dateAfter29March -> 2015-04-11 06:01:56 +0000
========================================
NOW DATE -> 2015-02-11 07:01:56 +0100
DATE AFTER 29 March -> 2015-04-11 08:01:56 +0200

【讨论】:

    【解决方案3】:

    您可以使用 nextDaylightSavingTimeTransition 找出您所在时区的下一个夏令时转换时间:

    NSTimeZone(abbreviation: "CET")!.nextDaylightSavingTimeTransition!   // "Mar 28, 2015, 22:00"
    

    您可以创建一个 NSDateFormatter 扩展来使用 CET 时区格式化您的时间,如下所示:

    extension NSDate {
        var time:String {
            let formatter = NSDateFormatter()
            formatter.timeZone = NSTimeZone(abbreviation: "CET")
            formatter.dateFormat = "HH:mm"
            return formatter.stringFromDate(self)
        }
    }
    
    
    
    let futureDate = NSCalendar.currentCalendar().dateWithEra(1, year: 2015, month: 3, day: 27, hour: 13, minute: 0, second: 0, nanosecond: 0)!
    let futureDateDLST = NSCalendar.currentCalendar().dateWithEra(1, year: 2015, month: 3, day: 29, hour: 13, minute: 0, second: 0, nanosecond: 0)!
    
    futureDate.time      // 17:00"
    futureDateDLST.time  // "18:00"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-25
      • 2014-04-21
      • 2019-08-17
      • 1970-01-01
      • 2015-06-03
      • 2020-07-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多