10

我正在尝试使用日期并在未来创建日期,但夏令时不断妨碍我的时间。

这是我将日期移至下个月第一天午夜的代码:

+ (NSDate *)firstDayOfNextMonthForDate:(NSDate*)date
{
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    calendar.timeZone = [NSTimeZone systemTimeZone];
    calendar.locale = [NSLocale currentLocale];

    NSDate *currentDate = [NSDate dateByAddingMonths:1 toDate:date];
    NSDateComponents *components = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                                                    fromDate:currentDate];

    [components setDay:1];
    [components setHour:0];
    [components setMinute:0];
    [components setSecond:0];

    return [calendar dateFromComponents:components];
}

+ (NSDate *) dateByAddingMonths: (NSInteger) monthsToAdd toDate:(NSDate*)date
{
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    calendar.timeZone = [NSTimeZone systemTimeZone];
    calendar.locale = [NSLocale currentLocale];

    NSDateComponents * months = [[NSDateComponents alloc] init];
    [months setMonth: monthsToAdd];

    return [calendar dateByAddingComponents: months toDate: date options: 0];
}

当我在某个日期迭代地运行该方法时,它给出了日期:

2013-02-01 00:00:00 +0000
2013-03-01 00:00:00 +0000
2013-03-31 23:00:00 +0000 should be 2013-04-01 00:00:00 +0000
2013-04-30 23:00:00 +0000 should be 2013-05-01 00:00:00 +0000

我最初的想法是不使用systemTimeZone,但这似乎并没有什么不同。关于如何使时间恒定而不考虑夏令时变化的任何想法?

4

4 回答 4

8

对于给定的日历日期/时间,作为一般规则,不可能预测所代表的实际时间(自纪元以来的秒数)。时区改变,DST 规则改变。这是生活中的事实。DST 在澳大利亚有一段饱受折磨的历史。DST 规则在以色列非常难以预测。DST 规则最近在美国发生了变化,这让存储秒数而不是日历日期的微软非常头疼。

NSDate当你的意思是永远不要保存NSDateComponents。如果您的意思是“2013 年 5 月 1 日在伦敦”,则将“2013 年 5 月 1 日在伦敦”保存在您的数据库中。然后计算NSDate尽可能接近实际事件的off。NSDateComponents如果您关心日历的事情(如月份),请使用所有日历数学。NSDate如果您真的只关心秒数,请只做数学。

编辑:有关许多非常有用的背景,请参阅日期和时间编程指南

还有一个关于日历组件的旁注:当我说“2013 年 5 月 1 日在伦敦”时,这并不意味着“5 月 1 日的午夜”。不要去添加你并不真正想要的日历组件。

于 2013-01-28T21:15:40.417 回答
4

请记住,您的程序打印到日志的是 GMT 时间,而不是您的本地时间。因此,在您当地时区切换到 DST 之后的日期,GMT 将偏移一小时是正确的。

于 2013-01-28T20:54:19.003 回答
3

我遇到了同样的问题,人们说这实际上不是问题(正如我在一些相关线程上看到的那样)并没有帮助解决这种情况。每当你必须处理时区和 DST 时,这种问题就会很痛苦,而且我总觉得我每次都必须重新学习它。

我尽可能地处理纪元时间(它是一个图表应用程序),但有时我需要使用 NSDate 和 NSCalendar(即,用于格式化轴标签,以及用于标记日历月、季度和年)。我为此苦苦挣扎了一天左右,试图在日历等上设置不同的时区。

最后,我发现我的应用程序委托中的以下代码行有很大帮助:-

// prevent DST bugs by setting default timezone for app
    if let utcZone = NSTimeZone(abbreviation: "UTC") {
        NSTimeZone.setDefaultTimeZone(utcZone)
    }

最重要的是,必须对源数据进行清理,因此每当我使用NSDateFormatter传入数据时,我确保将其时区设置为数据源的正确时区(在我的情况下,它是 GMT)。这消除了数据源中令人讨厌的 DST 问题,并确保所有生成的 NSDates 都可以很好地转换为纪元时间,而无需担心 DST。

于 2016-03-03T11:42:40.623 回答
0

另一种解决方案是检查日期的小时部分,如果它是 1 或 23(而不是 0),只需分别使用 Calendar.current.date(byAdding: .hour, value: -1, to: currentDate) 或更改日期Calendar.current.date(byAdding: .hour, value: 1, to: currentDate)

于 2021-10-26T15:22:46.097 回答