【问题标题】:Get UTC time and local time from NSDate object从 NSDate 对象获取 UTC 时间和本地时间
【发布时间】:2014-09-15 01:12:51
【问题描述】:

在 Objective-c 中,以下代码使用 date API 生成 UTC 日期时间信息。

NSDate *currentUTCDate = [NSDate date]

然而,在 Swift 中,

let date = NSDate.date()

结果为本地日期和时间。

我有两个问题:

  1. 如何在 NSDate 对象中获取 UTC 时间和本地时间(date 提供本地时间)。
  2. 如何从 NSDate 对象中获取秒数的精度。

编辑 1:感谢所有输入,但我不是在寻找 NSDateFormatter 对象或字符串值。我只是在寻找 NSDate 对象(但是我们将它们煮熟,但这是要求)。
参见第 1 点。

【问题讨论】:

  • NSDate 提供亚秒级精度。
  • NSDate 是一个时刻。没有 UTC 日期或本地日期之类的东西。这只是你如何显示它的问题。
  • NSDate 实例基于自格林威治标准时间 2001 年 1 月 1 日第一个时刻以来的时间间隔。因此,创建日期的时区没有任何区别,也不会影响 NSDate 值。
  • 来自 Apple Docs:“NSDate 的唯一原始方法 timeIntervalSinceReferenceDate 为 NSDate 接口中的所有其他方法提供了基础。此方法返回相对于绝对参考日期的时间值 -格林威治标准时间 2001 年 1 月 1 日的第一时间。”

标签: ios objective-c swift nsdate


【解决方案1】:

NSDate 是一个特定的时间点没有时区。将其视为自参考日期以来经过的秒数。自特定参考日期以来,一个时区与另一个时区相比已经过去了多少秒? 答案是一样的。

根据您输出该日期的方式(包括查看调试器),您可能会在不同的时区得到答案。

如果它们同时运行,它们的值是相同的。它们都是自参考日期以来的秒数,可以在 输出时 格式化为 UTC 或本地时间。在日期变量中,它们都是 UTC。

目标-C:

NSDate *UTCDate = [NSDate date]

斯威夫特:

let UTCDate = NSDate.date()

为了解释这一点,我们可以在 Playground 中使用 NSDateFormatter:

import UIKit

let date = NSDate.date()
    // "Jul 23, 2014, 11:01 AM" <-- looks local without seconds. But:

var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
let defaultTimeZoneStr = formatter.stringFromDate(date)
    // "2014-07-23 11:01:35 -0700" <-- same date, local, but with seconds
formatter.timeZone = NSTimeZone(abbreviation: "UTC")
let utcTimeZoneStr = formatter.stringFromDate(date)
    // "2014-07-23 18:01:41 +0000" <-- same date, now in UTC

日期输出会有所不同,但日期是不变的。这正是你所说的。没有本地 NSDate 这样的东西。

至于如何取出微秒,可以用这个(放在同一个playground的底部):

let seconds = date.timeIntervalSince1970
let microseconds = Int(seconds * 1000) % 1000 // chops off seconds

要比较两个日期,您可以使用date.compare(otherDate)

【讨论】:

  • 需要注意的一点是,如果您使用调试器检查日期值,它很容易以本地时间显示,而如果您在调试时使用po 显示它(或仅使用 NSLog)它将始终以 UTC 显示。
  • 其实时间是以GMT为准的。
  • 谢谢。另外,正如我所提到的,我想比较日期等。所以我想使用NSDate 类型输入这两个时间值。有没有办法做到这一点。 NSFormatter 解决不了任何问题。
  • dateA.compare(dateB);
  • 比较日期很容易,我已经添加了这一点。但是由于您的问题是关于您看到的不同日期,所以解释为什么您看到不同的日期很重要。而 NSDateFormatter 是最好的方法。 :)
【解决方案2】:

Xcode 9 • Swift 4(也适用于 Swift 3.x)

extension Formatter {
    // create static date formatters for your date representations
    static let preciseLocalTime: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "HH:mm:ss.SSS"
        return formatter
    }()
    static let preciseGMTTime: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "HH:mm:ss.SSS"
        return formatter
    }()
}

extension Date {
    // you can create a read-only computed property to return just the nanoseconds from your date time
    var nanosecond: Int { return Calendar.current.component(.nanosecond,  from: self)   }
    // the same for your local time
    var preciseLocalTime: String {
        return Formatter.preciseLocalTime.string(for: self) ?? ""
    }
    // or GMT time
    var preciseGMTTime: String {
        return Formatter.preciseGMTTime.string(for: self) ?? ""
    }
}

游乐场测试

Date().preciseLocalTime // "09:13:17.385"  GMT-3
Date().preciseGMTTime   // "12:13:17.386"  GMT
Date().nanosecond       // 386268973

这可能有助于您格式化日期:

【讨论】:

    【解决方案3】:

    文档说date 方法返回一个设置为当前日期和时间的新日期,无论使用何种语言。

    问题可能出在您使用NSDateFormatter 显示日期的地方。 NSDate 只是时间线上的一个点。谈论NSDate 时没有时区。我做了一个测试。

    斯威夫特

    print(NSDate())
    

    输出:2014-07-23 17:56:45 +0000

    目标-C

    NSLog(@"%@", [NSDate date]);
    

    输出:2014-07-23 17:58:15 +0000

    结果 - 没有区别。

    【讨论】:

    • 谢谢。显然,操场出于某种原因向我显示了当地时间。也许这只是一个错误(IDK)。我只是在查询let x = NSDate.date()
    • 不是错误;就是这样。你没有指定时区或格式,所以你得到什么。我的猜测是它是当前时区、美国中日期格式和美国短时间格式。
    • 是的,不是错误。 NSDate 对象的 description 将在日志中显示您当前设备上的本地时区,但实际上所有日期都是 GMT 或 UTC。然后,您的设置将显示设置为您所在时区的日期日志。这是正确的。如果我不在格林威治标准时间,可以说(格林威治标准时间 +1 小时),那么在我创建日期后,日期将在日志中显示 2014-07-23 16:56:45 +0000(格林威治标准时间或 UTC)。实际上,这是2014-07-23 17:56:45 +0000(我的本地时区)。想象一下它们存储在 GTM 或 UTC 中,并根据您的时区而变化。
    • @skymook 如果UTC日期是2014-07-23 16:56:45 +0000,则本地日期实际上是2014-07-23 17:56:45 +0100+0100表示与UTC时间的偏移量。
    • 我认为这个答案不能回答这里提出的问题。提出的问题是如何在 iOS 中获取 UTC 日期以及如何从 Date() 对象中获取精确秒数。
    【解决方案4】:

    日期与任何时区无关,因此请使用 Dateformatter 并附加时区以进行显示:

    迅速:

    let date = NSDate()
    let dateFormatter = NSDateFormatter()
    let timeZone = NSTimeZone(name: "UTC")
    
    dateFormatter.timeZone = timeZone
    
    println(dateFormatter.stringFromDate(date))
    

    objC:

    NSDate *date = [NSDate date];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    
    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
    [dateFormatter setTimeZone:timeZone];       
    NSLog(@"%@", [dateFormatter stringFromDate:date]);
    

    【讨论】:

    • 其实日期是以格林威治标准时间为准。如果不是基于特定时区,则无法显示为另一个时区。
    • 恐怕它不是基于 GMT 的。如果有的话,你可以称之为基于 UTC 但对我来说 UTC = zulu time = no timezone。简而言之,UTC 与 .GMT 的区别在于,使用 GMT,一些 DaylightSavings 时间是相关的
    • 您从哪里获得“GMT,一些夏令时时间已连接”的信息。也许您正在考虑 BST?
    • 来自 Apple 文档:“格林威治标准时间 2001 年 1 月 1 日的第一刻。”这不是一个 1970 年 1 月 1 日的 Unix 时间戳。UTC 确实取代了 GMT,并且在大多数情况下,UTC 可以与 GMT 互换使用。
    • 是的,我错了,我确实记错了,但 GMT 不是 UTC 并且日期没有时区;)
    【解决方案5】:
    let date = Date() 
    print(date) // printed date is UTC 
    

    如果您使用的是 playground,请使用打印语句检查时间。 Playground 会显示当地时间,直到您打印出来。不要依赖操场的右侧面板。

    此代码以 UTC 格式给出日期。如果你需要本地时间,你应该调用下面的扩展,时区为Timezone.current

     extension Date {
    
       var currentUTCTimeZoneDate: String {
            let formatter = DateFormatter()
            formatter.timeZone = TimeZone(identifier: "UTC")
            formatter.amSymbol = "AM"
            formatter.pmSymbol = "PM"
            formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    
            return formatter.string(from: self)
        }
    }
    

    对于 UTC 时间,像这样使用它:Date().currentUTCTimeZoneDate

    【讨论】:

      【解决方案6】:

      目前(对 Swift 进行了最新更改),NSDate.date() 不再可用。

      相反,您只需要初始化 NSDate 并获取当前日期和时间。
      在操场上尝试一下:

      var d = NSDate()
      d
      

      你会得到:

      Oct 22, 2014, 12:20 PM"  
      

      【讨论】:

      • 那个字符串就是你得到的。偶然 :) 没有格式化程序,输出基于调试器的语言环境。
      • 这不是关于字符串,而是关于获取当前日期时间,并且只需实例化 NSDate,正如我所说,您也将获得当前日期时间。
      • 您的字符串是您的本地时间,票的内容是:“在objective-c中,以下代码[X}产生UTC日期时间信息,在swift中它产生本地日期和时间。{X}" ==> 调试器日期格式化程序
      • 这决不能回答问题(或者,就此而言,表明问题背后的基本假设是无效的)。
      【解决方案7】:

      斯威夫特 3

      您可以根据您当前的时区从 UTC 获取日期

      extension Date {
          func currentTimeZoneDate() -> String {
              let dtf = DateFormatter()
              dtf.timeZone = TimeZone.current
              dtf.dateFormat = "yyyy-MM-dd HH:mm:ss"
      
              return dtf.string(from: self)
          }
      }
      

      这样调用:

      Date().currentTimeZoneDate()
      

      【讨论】:

      • 这将给出当前时区日期。不是 UTC。
      【解决方案8】:

      我的 Xcode 版本 6.1.1 (6A2008a)

      在操场上,像这样测试:

      // I'm in East Timezone 8
      let x = NSDate() //Output:"Dec 29, 2014, 11:37 AM"
      let y = NSDate.init() //Output:"Dec 29, 2014, 11:37 AM"
      println(x) //Output:"2014-12-29 03:37:24 +0000"
      
      
      // seconds since 2001
      x.hash //Output:441,517,044
      x.hashValue //Output:441,517,044
      x.timeIntervalSinceReferenceDate //Output:441,517,044.875367
      
      // seconds since 1970
      x.timeIntervalSince1970 //Output:1,419,824,244.87537
      

      【讨论】:

        【解决方案9】:

        我发现了一种在 Swift4 中获取 UTC 的更简单方法。把这段代码放在操场上

        let date = Date() 
        *//"Mar 15, 2018 at 4:01 PM"*
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
        dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
        
        let newDate = dateFormatter.string(from: date) 
        *//"2018-03-15 21:05:04 +0000"*
        

        【讨论】:

          【解决方案10】:

          除了其他答案之外,您还可以为 Date 类编写一个扩展,以获取特定 TimeZone 中的格式化数据,使其成为实用函数以供将来使用。喜欢

           extension Date {
          
           func dateInTimeZone(timeZoneIdentifier: String, dateFormat: String) -> String  {
           let dtf = DateFormatter()
           dtf.timeZone = TimeZone(identifier: timeZoneIdentifier)
           dtf.dateFormat = dateFormat
          
           return dtf.string(from: self)
           }
          }
          

          现在你可以这样称呼它

           Date().dateInTimeZone(timeZoneIdentifier: "UTC", dateFormat: "yyyy-MM-dd HH:mm:ss");
          

          【讨论】:

            猜你喜欢
            • 2018-07-02
            • 2012-10-08
            • 1970-01-01
            • 1970-01-01
            • 2014-03-03
            • 1970-01-01
            • 2012-09-23
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多