【问题标题】:NSDate() or Date() shows the wrong timeNSDate() 或 Date() 显示错误的时间
【发布时间】:2017-02-17 14:53:25
【问题描述】:

当我尝试记录当前日期时:

print(NSDate())

print(Date()) 

(在 Swift 3 中)

或任何日期对象,它显示错误的时间。比如现在是16:12左右,但是上面显示了

2016-10-08 20:11:40 +0000

我的日期是不是在错误的时区?如何确定我的日期以获得正确的时区?

为什么会这样,我该如何解决?如何在打印语句或调试器中轻松显示本地时区的任意日期?

(请注意,这个问题是一个“响铃”,因此我可以提供一个简单的 Swift 3/Swift 2 Date/NSDate 扩展,让您可以轻松地在本地时区显示任何日期对象。

【问题讨论】:

    标签: swift date nsdate


    【解决方案1】:

    NSDate(或 Swift ≥ V3 中的日期)没有时区。它记录了全世界的一个瞬间。

    在内部,日期对象记录自“纪元日期”或 2001 年 1 月 1 日午夜以来的秒数,Greenwich Mean Time,又名 UTC。

    我们通常会考虑当地时区的日期。

    如果您使用

    记录日期
    print(NSDate()) 
    

    系统显示当前日期,但它以 UTC/格林威治标准时间表示。所以时间看起来正确的唯一地方就是那个时区。

    如果你发出调试器命令,你会在调试器中遇到同样的问题

    e NSDate()
    

    这是一种痛苦。我个人希望 iOS/Mac OS 能够使用用户当前的时区显示日期,但他们没有。

    编辑#2:

    对我之前使用的本地化字符串的改进使其更易于使用的是创建Date 类的扩展:

    extension Date {
        func localString(dateStyle: DateFormatter.Style = .medium, timeStyle: DateFormatter.Style = .medium) -> String {
            return DateFormatter.localizedString(from: self, dateStyle: dateStyle, timeStyle: timeStyle)
        }
    }
    

    这样你就可以使用Date().localString()这样的表达式,或者如果你只想打印时间,你可以使用Date().localString(dateStyle:.none)

    编辑:

    我刚刚发现NSDateFormatter(Swift 3 中的DateFormatter)有一个类方法localizedString。这就是我下面的扩展所做的,但更简单、更干净。这是声明:

    class func localizedString(from date: Date, dateStyle dstyle: DateFormatter.Style, timeStyle tstyle: DateFormatter.Style) -> String
    

    所以你只需使用

    let now = Date()
    print (DateFormatter.localizedString(
      from: now, 
      dateStyle: .short, 
      timeStyle: .short))
    

    您几乎可以忽略下面的所有内容。


    我创建了一个 NSDate 类的类别(Swift 3 中的日期),它有一个方法 localDateString,可以显示用户本地时区的日期。

    这是 Swift 3 形式的类别:(文件名 Date_displayString.swift)

    extension Date {
      @nonobjc static var localFormatter: DateFormatter = {
        let dateStringFormatter = DateFormatter()
        dateStringFormatter.dateStyle = .medium
        dateStringFormatter.timeStyle = .medium
        return dateStringFormatter
      }()
      
      func localDateString() -> String
      {
        return Date.localFormatter.string(from: self)
      }
    }
    

    在 Swift 2 中:

    extension NSDate {
       @nonobjc static var localFormatter: NSDateFormatter = {
        let dateStringFormatter = NSDateFormatter()
        dateStringFormatter.dateStyle = .MediumStyle
        dateStringFormatter.timeStyle = .MediumStyle
        return dateStringFormatter
      }()
      
    public func localDateString() -> String
      {
        return NSDate.localFormatter.stringFromDate(self)
      }
    }
    

    (如果您喜欢不同的日期格式,可以很容易地修改日期格式化程序使用的格式。在您需要的任何时区显示日期和时间也很简单。)

    我建议将此文件的适当 Swift 2/Swift 3 版本放入您的所有项目中。

    然后你可以使用

    斯威夫特 2:

    print(NSDate().localDateString())
    

    斯威夫特 3:

    print(Date().localDateString())
    

    【讨论】:

    • 如果您尝试表示使用static 变量的规范答案,那么我认为您最好回复NSLocale.currentLocaleDidChangeNotification(又名NSCurrentLocaleDidChangeNotification)并无效/重置缓存的格式化程序.如果您不想进入那个兔子洞,那么带有staticextension 可能不属于此“规范”答案的一部分,只需将其保留在“使用DateFormatter 就像这样。 ..”。
    • 抢,点了。我想“规范答案”有点多,因为用户可以更改您指出的语言环境。更像是对常见开发/调试问题的便携、简单的解决方案。由于这主要是为了开发支持,因此切换语言环境似乎不是问题。
    【解决方案2】:

    为您的时区更正日期的一种简单方法是使用TimeZone.current.secondsFromGMT()

    例如,对于本地时间戳值是这样的:

    let currentLocalTimestamp = (Int(Date().timeIntervalSince1970) + TimeZone.current.secondsFromGMT())

    【讨论】:

    • 它不会给我们精确到毫秒或尼诺秒
    • 这正是你不应该做的事情。
    • 呃。不,这不是处理时区的好方法。
    猜你喜欢
    • 2020-03-15
    • 2011-02-14
    • 1970-01-01
    • 2013-12-16
    • 1970-01-01
    • 2021-03-22
    相关资源
    最近更新 更多