为什么NSCalendar的compareDate似乎需要设置UTC时区才能正常工作



我创建了两个日期,如下所示:

let date1 = stringToDate("2015-02-12 12:29:29")!
let date2 = stringToDate("2015-02-11 19:18:49")!
func stringToDate(var dateString: String) -> NSDate? {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = NSTimeZone(name: "UTC")
return dateFormatter.dateFromString(dateString)
}

正如你所看到的,这两个日期不同,也不在同一天。

为了测试两个日期是否在同一天,我使用以下方法:

func isSameDayThan(date1: NSDate, date2: NSDate) -> Bool {
let calendar = NSCalendar.currentCalendar()
calendar.timeZone = NSTimeZone(abbreviation: "GMT+10")!
return calendar.compareDate(date1, toDate: date2, toUnitGranularity: .DayCalendarUnit) == .OrderedSame
}

在那里,我没有精确计算日历上的时区。我的设备的本地时区设置为GMT+10。

在这种情况下,isSameDayThan(date1, date2)->真正的

如果我将时区更改为低于或等于GMT+04,那么我得到isSameDayThan(date1, date2)->false。

我不明白的是,根据时区的不同,结果会有所不同,但我正在比较两个NSDate(),如果我没有错的话,NSDate()与时区无关。

时区之所以发挥作用,是因为您将日期与取决于时区的粒度进行比较。所以你实际上是在与当地的日期表示进行比较。通常用于描述NSDate的时间点模型不知道天数和周数。从抽象的角度来看(即宇宙中任何地方都相同的时间点),它实际上甚至不知道秒。

不管怎样,如果你想与==进行比较,你显然不需要时区。这是唯一真正独立于地方代表性的比较。如果两个时间点完全相同,那么它们是相等的。容易的

除了直接的==比较之外的所有内容都必须转换为本地单位。你不仅要使用正确的日历,还要使用正确的时区。

幸运的是,没有日历上的天数比24小时更短或更长。也没有以秒为单位的时区。因为我们知道,你可以通过简单的计算来查看日期是否在同一分钟内。例如:

Int(date1.timeIntervalSince1970 / 60) == Int(date2.timeIntervalSince1970 / 60)

不需要日历,因为我们(目前)没有分钟长度不超过60秒的日历。不需要时区,因为我们没有偏移量在秒数上不同的时区。

但我们有一些时区的偏移量只有一小时的几分之一。例如,偏移量为+05:30的印度时区。因此,从小时开始,粒度单位的边界取决于时区。

如果您有两个设置为9:25和9:35 UTC的NSDates,如果您在任何偏移量在分钟数上没有差异的时区进行比较(例如,+x:00中的00),则它们在同一小时内。它们在UTC的同一小时,在UTC+5:00和UTC-5:00的同一时间。

但如果你在印度时区进行比较,这两个日期实际上是在不同的时间。因为国际标准时间9:25 UTC是2:55,而国际标准时间9:35 UTC是3:05。

在您的示例中,您正在与当天的粒度进行比较。这需要考虑所有时区。但我们仍然可以忽略日历,因为所有日历都使用24小时的天数。

但如果你想比较一周、一个月或一年的粒度,你也必须考虑日历。有些日历的月份完全不同。在格里高利历中,两个日期在同一个月并不意味着它们在希伯来历中在同一月。


是的,它很复杂。这就是所有日期计算显得如此冗长的原因。人们经常试图隐藏一个奇特的辅助函数背后的复杂性。这往往会导致问题。所以要注意isSameDay()这样的创建功能
每次比较日期时,您都必须决定使用哪个时区和日历。如果您依赖助手函数,您将错过一个实际应该与UTC而不是本地时区进行比较的实例。

TL;DR:如果与粒度进行比较,则应始终设置正确的日历和时区。

这两个日期在UTC时区中是不同的日期。但在GMT+10时区,它们都是同一天——2月12日。

2015-02-12 12:29:29 UTC=2015-02-12 22:29:29 UTC+10
2015-02-11 19:18:49 UTC=2015-03-12 05:18:49 UTC+10

默认情况下,比较是在本地时区进行的,但您的日期对象是专门在UTC时区创建的。

如果使用默认时区从字符串中创建NSDate对象,并使用默认时区进行比较,则日期将有两个不同的日期。

相关内容

  • 没有找到相关文章

最新更新