如何计算不同时区的两个 NSDate 对象之间的天数差异?

Posted

技术标签:

【中文标题】如何计算不同时区的两个 NSDate 对象之间的天数差异?【英文标题】:How to calculate days difference between two NSDate objects in different time zones? 【发布时间】:2017-02-11 13:48:01 【问题描述】:

我有两个从 UTC 日期开始的 NSDate。 让我们称他们为(A 和 B)

我知道 A 代表中国的一天,B 代表美国的一天。 (我知道时区。)如何计算两者之间的天数差异...?

我一直在使用下面的方法,显然是不正确的。

class func daysDifferenceIn(firstDate: NSDate, firstTimeZone: String, secondDate: NSDate, secondTimeZone: String) -> Int 
    objc_sync_enter(self)

    let firstDateComponents = NSCalendar.CommonCalendar.componentsInTimeZone(NSTimeZone(name: firstTimeZone)!, fromDate: firstDate)
    let secondDateComponents = NSCalendar.CommonCalendar.componentsInTimeZone(NSTimeZone(name: secondTimeZone)!, fromDate: secondDate)
    NSCalendar.CommonCalendar.timeZone = NSTimeZone(name: firstTimeZone)!
    let firstCalDate = NSCalendar.CommonCalendar.dateFromComponents(firstDateComponents)
    NSCalendar.CommonCalendar.timeZone = NSTimeZone(name: secondTimeZone)!
    let secondCalDate = NSCalendar.CommonCalendar.dateFromComponents(secondDateComponents)
    objc_sync_exit(self)

    return firstCalDate!.numberOfDaysUntilDateTime(secondCalDate!)


func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int 
    let calendar = NSCalendar.CommonCalendar
    if let timeZone = timeZone 
        calendar.timeZone = timeZone
    

    var fromDate: NSDate?, toDate: NSDate?

    calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self)
    calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime)

    let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: [])

    return difference.day

我可以手动从 firstDateComponentssecondDateComponents 中减去日分量,这是我不想做的,因为我必须寻找 31 和 28 等边缘情况。 任何帮助表示赞赏。谢谢。

更新

第一个日期是 2017-02-10 16:15:00 +0000 第二个日期是 2017-02-11 03:20:00 +0000 两者都是 UTC。

firstTimeZone 字符串“亚洲/上海” secondTimeZone 字符串 "America/Los_Angeles"

所以天差是-1天。基本上我正在实施航班状态,当航班在起飞前 1 天降落时,您可以看到以下链接。因为它从西飞到东。

https://www.google.co.in/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=ua+890

也是对日期组件的描述。

Printing description of firstDateComponents:
<NSDateComponents: 0x600000142310>
    Calendar: <CFCalendar 0x60000088b6d0 [0x10c5d3df0]>identifier = 'gregorian'
    TimeZone: Asia/Shanghai (GMT+8) offset 28800
    Era: 1
    Calendar Year: 2017
    Month: 2
    Leap month: no
    Day: 11
    Hour: 0
    Minute: 15
    Second: 0
    Nanosecond: 0
    Quarter: 0
    Year for Week of Year: 2017
    Week of Year: 6
    Week of Month: 2
    Weekday: 7
    Weekday Ordinal: 2
Printing description of secondDateComponents:
<NSDateComponents: 0x60000014b8f0>
    Calendar: <CFCalendar 0x60000049b620 [0x10c5d3df0]>identifier = 'gregorian'
    TimeZone: America/Los_Angeles (PST) offset -28800
    Era: 1
    Calendar Year: 2017
    Month: 2
    Leap month: no
    Day: 10
    Hour: 19
    Minute: 20
    Second: 0
    Nanosecond: 0
    Quarter: 0
    Year for Week of Year: 2017
    Week of Year: 6
    Week of Month: 2
    Weekday: 6
    Weekday Ordinal: 2

【问题讨论】:

如果这两个日期在中国是同一天,而在美国是不同的日子,你会期待什么结果? @MartinR 你可以看到我对这个问题的更新。 相关:NSDate for the same local time as another NSDate in different time zones @JoshCaswell:确实。现在多次阅读了这个问题,这似乎是这里真正想要的。 【参考方案1】:

这是一个奇怪的案例。您正在寻找在特定时区评估两个 Dates 的日历日期之间的差异。

我做了一些游戏,并想出了适用于同一年日期的代码:

let date = Date()

guard let nycTimeZone = TimeZone(abbreviation: "EST"),
  let nzTimeZone = TimeZone(abbreviation: "NZDT") else 
    fatalError()

var nycCalendar = Calendar(identifier: .gregorian)
nycCalendar.timeZone = nycTimeZone
var nzCalendar = Calendar(identifier: .gregorian)
nzCalendar.timeZone = nzTimeZone

let now = Date()

let nycDayOfYear = nycCalendar.ordinality(of: .day, in: .year, for: now)

var nzDayOfYear = nzCalendar.ordinality(of: .day, in: .year, for: now)

我使用纽约和新西兰奥克兰作为我的时区,因为在撰写本文时,这些时区的日期不同。

截至目前(2017 年 2 月 11 日下午 12:00 左右,美国东部标准时间 (UTC - 5)),上面的代码给出了

nycDayOfYear = 42

nzDayOfYear = 43

要跨年份进行计算需要做一些工作。

奇怪的是,下面的代码:

var nzDayOfEra = nzCalendar.ordinality(of: .day, in: .era, for: now)
let nycDayOfEra = nycCalendar.ordinality(of: .day, in: .era, for: now)

为 NZ 和 NYC 提供相同的值。我不知道为什么。

编辑:

好的,我做了一些实验,得到了可以工作的代码。我所做的是使用设置为每次本地时区的日历将两个日期转换为月/日/年日期组件。然后我使用dateComponents(_:from:to:)的方法来计算这2个DateComponents之间的差异,以天为单位:

import UIKit

let date = Date()

guard let nycTimeZone = TimeZone(abbreviation: "EST"),
  let nzTimeZone = TimeZone(abbreviation: "NZDT") else 
    fatalError()

var nycCalendar = Calendar(identifier: .gregorian)
nycCalendar.timeZone = nycTimeZone
var nzCalendar = Calendar(identifier: .gregorian)
nzCalendar.timeZone = nzTimeZone

let now = Date()


let nycDateComponents = nycCalendar.dateComponents([.month, .day, .year], from: now)
let nzDateComponents = nzCalendar.dateComponents([.month, .day, .year], from: now)

let difference = Calendar.current.dateComponents([.day],
  from: nycDateComponents,
    to: nzDateComponents)

let daysDifference = difference.days

在撰写本文时,daysDifference 为 1。由于我们使用的是 dateComponents(_:from:to:) 函数,因此它负责计算 2 个月/天/年 DateComponents 之间的天数差异。

【讨论】:

这很有帮助,但我正在寻找更完整的证明答案。还是谢谢。 查看我的答案的编辑。我添加了可以为您提供所需答案的代码。 我还发布了一个答案,有人在没有任何 cmets 的情况下投了反对票。你的解决方案也不错。您认为我从您的代码中获取提示的答案有什么问题吗...? 查看我对您的回答的评论。我在尝试使用基于时代的计算时得到了错误的结果。 您实际上正在做的是获取两个日期并获取它们之间相对于当地时区的差异。您所做的第一件事是删除时区信息...如果您有两个日期时间字符串(包括时区)并将它们解析为您的本地时区,然后得到之间的天数,这正是您会得到的结果他们。【参考方案2】:

NSDate 代表一个时刻。它没有时区。只有日期的字符串表示具有时区信息。

如果您有日期,只需计算它们之间的天数。不用担心时区。

通常:

let difference = calendar.components(.Day, fromDate: self, toDate: toDate!, options: [])
return difference.day

应该够了。

【讨论】:

轻微吹毛求疵:“只需计算天数......不要担心时区” 可能会产生误导。天数的差异仅对日历和时区有意义。这当然可以是默认日历和本地时区。 @Sulthan 你可以看看我对问题的更新。 "只有日期的字符串表示才有时区信息。"不,这并不完全正确。考虑将NSDate 转换为DateComponents。您获得的年/月/日/小时/分钟值将因时区而异。 Date 对象在特定日历中的表达式取决于时区,无论该表示是基于数字还是基于字符串。 OP 询问了一个不寻常的问题:找出地球上位于不同时区的 2 个不同位置的日历日期差异。例如,现在新西兰奥克兰是 2 月 13 日,但纽约市是 2 月 12 日。在这种情况下,OP 希望得到 1 天差异的结果。他想要担心时区。 @DuncanC 我不认为这是一个不寻常的问题。我认为这是一个不可能的问题。虽然我们可以设计一个解决方案,但该解决方案将有太多的边缘情况。【参考方案3】:

您是否尝试过使用let interval = laterDate.timeIntervalSinceDate(earlierDate)?这将以秒为单位返回两个日期之间的差异。

【讨论】:

以上是关于如何计算不同时区的两个 NSDate 对象之间的天数差异?的主要内容,如果未能解决你的问题,请参考以下文章

如何在以下示例中计算出日差

NSDate 似乎如何知道它是 TimeZone?

在具有正确日期的python中转换和计算日期时间对象的时区

objective-c calendar 日期

在两个NSDate之间获得准确的时间差?

创建具有特定时区的 NSDate 对象