iOS创建日期,忽略夏令时

时间:2013-01-28 20:05:13

标签: ios nsdate nscalendar nstimezone

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

这是我的代码,可以移动到下个月第一天的午夜约会:

+ (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,但这似乎没有什么区别。关于如何使时间保持恒定而不考虑夏令时变化的任何想法?

3 个答案:

答案 0 :(得分:7)

对于给定的日历日期/时间,通常不可能预测表示的实际时间(自纪元以来的秒数)。时区更改,DST规则更改。这是生活中的事实。夏令时在澳大利亚历史悠久。 DST规则在以色列非常难以预测。 DST规则最近在美国发生了变化,给微软带来了巨大的麻烦,因为微软存储的是秒而不是日历日期。

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

编辑:对于许多非常有用的背景,请参阅Date and Time Programming Guide

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

答案 1 :(得分:3)

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

答案 2 :(得分:2)

我遇到了同样的问题,人们说这不是一个问题(正如我在一些相关主题上看到的那样)并不能帮助解决问题。无论何时你必须处理时区和夏令时,这种问题都会受到伤害,我总觉得每次都必须重新学习它。

我正在尽可能多地处理纪元时代(它是一个图表应用程序),但有时我需要使用NSDate和NSCalendar(即,用于格式化轴标签,以及用于标记日历月,宿舍和年份)。我挣扎了一天左右,试图在日历上设置各种各样的时区等。

最后,我发现我的应用代表中的以下代码行极大地帮助了: -

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

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