【问题标题】:How do you create a Swift Date object?你如何创建一个 Swift Date 对象?
【发布时间】:2014-07-28 04:56:43
【问题描述】:

如何在 swift xcode 中根据日期创建日期对象。

例如,在 javascript 中你会这样做: var day = new Date('2014-05-20');

【问题讨论】:

  • 像在 Objective-C 中一样使用NSDate

标签: ios iphone swift nsdate


【解决方案1】:

Swift 有自己的 Date 类型。无需使用NSDate

在 Swift 中创建日期和时间

在 Swift 中,日期和时间存储在一个 64 位浮点数中,测量自参考日期 2001 年 1 月 1 日 00:00:00 UTC 以来的秒数。这在Date structure 中表示。以下将为您提供当前日期和时间:

let currentDateTime = Date()

要创建其他日期时间,您可以使用以下方法之一。

方法一

如果您知道 2001 年参考日期之前或之后的秒数,则可以使用它。

let someDateTime = Date(timeIntervalSinceReferenceDate: -123456789.0) // Feb 2, 1997, 10:26 AM

方法二

当然,使用年、月、日和小时(而不是相对秒数)来创建Date 会更容易。为此,您可以使用DateComponents 指定组件,然后使用Calendar 创建日期。 Calendar 给出了 Date 上下文。否则,它怎么知道用什么时区或日历来表达呢?

// Specify date components
var dateComponents = DateComponents()
dateComponents.year = 1980
dateComponents.month = 7
dateComponents.day = 11
dateComponents.timeZone = TimeZone(abbreviation: "JST") // Japan Standard Time
dateComponents.hour = 8
dateComponents.minute = 34

// Create date from components
let userCalendar = Calendar(identifier: .gregorian) // since the components above (like year 1980) are for Gregorian
let someDateTime = userCalendar.date(from: dateComponents)

其他时区缩写可以在here找到。如果您将其留空,则默认使用用户的时区。

方法3

最简洁的方式(但不一定是最好的)可能是使用DateFormatter

let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
let someDateTime = formatter.date(from: "2016/10/08 22:31")

DateFormatter 支持的Unicode technical standards show other formats

注意事项

请参阅my full answer,了解如何以可读格式显示日期和时间。另请阅读以下优秀文章:

【讨论】:

    【解决方案2】:

    最好使用现有NSDate 类的扩展来完成。

    以下扩展添加了一个新的初始化程序,它将使用您指定格式的日期字符串在当前语言环境中创建一个日期。

    extension NSDate
    {
        convenience
          init(dateString:String) {
          let dateStringFormatter = NSDateFormatter()
          dateStringFormatter.dateFormat = "yyyy-MM-dd"
          dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
          let d = dateStringFormatter.dateFromString(dateString)!
          self.init(timeInterval:0, sinceDate:d)
        }
     }
    

    现在您可以通过以下方式从 Swift 创建 NSDate:

    NSDate(dateString:"2014-06-06")
    

    请注意,此实现不会缓存 NSDateFormatter,如果您希望以这种方式创建许多 NSDates,出于性能原因您可能希望这样做。

    还请注意,如果您尝试通过传入无法正确解析的字符串来初始化NSDate,则此实现将简单地崩溃。这是因为dateFromString 返回的可选值被强制解包。如果您想在解析错误时返回nil,理想情况下您会使用可失败的初始化程序;但你现在不能这样做(2015 年 6 月),因为 Swift 1.2 的限制,所以你的下一个最佳选择是使用类工厂方法。

    解决这两个问题的更详细的示例如下:https://gist.github.com/algal/09b08515460b7bd229fa


    Swift 5 更新

    extension Date {
        init(_ dateString:String) {
            let dateStringFormatter = DateFormatter()
            dateStringFormatter.dateFormat = "yyyy-MM-dd"
            dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale
            let date = dateStringFormatter.date(from: dateString)!
            self.init(timeInterval:0, since:date)
        }
    }
    

    【讨论】:

    • 那么“方便”这个词在这里做什么?
    • 它表明扩展提供了一个初始化器,它实际上将初始化委托给一个已经存在的指定初始化器,在这种情况下是 NSDate.init(timeInterval:,sinceDate:) 初始化器。这在 The Swift Programming Language book 的第 275 页中有描述。
    • 我在上面的代码中看到的一个缺陷是每次访问函数时都重新创建NSDateFormatter。正如Date Formatting Guide 所述,创建日期格式化程序并不是一项廉价的操作。此外,自 iOS7 以来,该类是线程安全的,因此可以安全地将其用于所有 NSDate 扩展。
    • @eugenedubinin 正确。这就是为什么我说“这个实现不缓存 NSDateFormatter,你可能出于性能原因想要这样做”。
    • Swift 1.2 有什么限制?功能“失败的初始化程序”是available since Swift 1.1
    【解决方案3】:

    Swift 没有自己的 Date 类型,但是你可以使用现有的 Cocoa NSDate 类型,例如:

    class Date {
    
        class func from(year: Int, month: Int, day: Int) -> Date {
            let gregorianCalendar = NSCalendar(calendarIdentifier: .gregorian)!
    
            var dateComponents = DateComponents()
            dateComponents.year = year
            dateComponents.month = month
            dateComponents.day = day
    
            let date = gregorianCalendar.date(from: dateComponents)!
            return date
        }
    
        class func parse(_ string: String, format: String = "yyyy-MM-dd") -> Date {
            let dateFormatter = DateFormatter()
            dateFormatter.timeZone = NSTimeZone.default
            dateFormatter.dateFormat = format
    
            let date = dateFormatter.date(from: string)!
            return date
        }
    }
    

    你可以像这样使用:

    var date = Date.parse("2014-05-20")
    var date = Date.from(year: 2014, month: 05, day: 20)
    

    【讨论】:

    • 我不得不换行: var date = gregorian?.dateFromComponents(c) 但我不明白为什么,解析返回 dateFmt.dateFromString 也在抱怨。有什么线索吗?啊,我把函数的返回类型从NSDate改成了NSDate了?这让它编译。但我不确定为什么它需要为空。
    • @TheSenator NSCalendar init 返回一个可选的 (?) 所以 gregorian 是一个可选的 (?)。访问可选链接以访问它,因此 gregorian?.dateFromCoomponents 是从选项 gregorian (NSCalendar) 中解包值的可选链接。更多关于可选链接here
    • NSGregorianCalendar 自 iOS 8 起已弃用,因此请改用 NSCalendarIdentifierGregorian
    • @The Senator Complains coz Swift 具有 Date 结构,并且此代码再次将 Date 重新声明为类。所以你应该这样做:'extension Date'和'static func'
    • 关于将字符串解析回日期的备忘录。 NSDateFormatter 方法 date(from:) 的字符串“1979-07-01”和“yyyy-MM-dd”。它返回nil。我在 fabric.io 崩溃日志中发现了这个问题。
    【解决方案4】:

    这是我在 Swift 4.2 中的做法:

    extension Date {
    
        /// Create a date from specified parameters
        ///
        /// - Parameters:
        ///   - year: The desired year
        ///   - month: The desired month
        ///   - day: The desired day
        /// - Returns: A `Date` object
        static func from(year: Int, month: Int, day: Int) -> Date? {
            let calendar = Calendar(identifier: .gregorian)
            var dateComponents = DateComponents()
            dateComponents.year = year
            dateComponents.month = month
            dateComponents.day = day
            return calendar.date(from: dateComponents) ?? nil
        }
    }
    

    用法:

    let marsOpportunityLaunchDate = Date.from(year: 2003, month: 07, day: 07)
    

    【讨论】:

    • 虽然我将“15”作为一天传递,但返回的日期是 14 号?想法?
    • @LukeZammit 将时区添加到dateComponents
    • 尝试了这个但没有成功 - dateComponents.timeZone = TimeZone.current,请考虑一下?
    • 您尝试使用卢克的日期是什么时候?你确定它存在吗?因为有些日期被跳过了。
    【解决方案5】:

    根据Apple documentation

    例子:

    var myObject = NSDate()
    let futureDate = myObject.dateByAddingTimeInterval(10)
    let timeSinceNow = myObject.timeIntervalSinceNow
    

    【讨论】:

    • 很好但没有回答问题,问题与时间间隔无关。
    【解决方案6】:

    在 Swift 3.0 中,您已经为此设置了日期对象。

    extension Date
    {
        init(dateString:String) {
            let dateStringFormatter = DateFormatter()
            dateStringFormatter.dateFormat = "yyyy-MM-dd"
            dateStringFormatter.locale = Locale(identifier: "en_US_POSIX")
            let d = dateStringFormatter.date(from: dateString)!
            self(timeInterval:0, since:d)
        }
    }
    

    【讨论】:

    • @Zonker.in.Geneva 随处可见。创建单独的文件,称之为“扩展”,idk .
    【解决方案7】:

    我个人认为它应该是一个失败的初始化器:

    extension Date {
    
        init?(dateString: String) {
            let dateStringFormatter = DateFormatter()
            dateStringFormatter.dateFormat = "yyyy-MM-dd"
            if let d = dateStringFormatter.date(from: dateString) {
                self.init(timeInterval: 0, since: d)
            } else {
                return nil
            }
        }
    }
    

    否则格式无效的字符串会引发异常。

    【讨论】:

      【解决方案8】:

      根据@mythz 的回答,我决定使用swift3 语法发布他的扩展的更新版本。

      extension Date {
          static func from(_ year: Int, _ month: Int, _ day: Int) -> Date?
          {
              let gregorianCalendar = Calendar(identifier: .gregorian)
              let dateComponents = DateComponents(calendar: gregorianCalendar, year: year, month: month, day: day)
              return gregorianCalendar.date(from: dateComponents)
          }
      }
      

      我不使用parse方法,但是如果有人需要,我会更新这个帖子。

      【讨论】:

        【解决方案9】:

        我经常需要将一个地方的日期值与另一个地方的时间值结合起来。我写了一个辅助函数来完成这个。

        let startDateTimeComponents = NSDateComponents()
        startDateTimeComponents.year = NSCalendar.currentCalendar().components(NSCalendarUnit.Year, fromDate: date).year
        startDateTimeComponents.month = NSCalendar.currentCalendar().components(NSCalendarUnit.Month, fromDate: date).month
        startDateTimeComponents.day = NSCalendar.currentCalendar().components(NSCalendarUnit.Day, fromDate: date).day
        startDateTimeComponents.hour = NSCalendar.currentCalendar().components(NSCalendarUnit.Hour, fromDate: time).hour
        startDateTimeComponents.minute = NSCalendar.currentCalendar().components(NSCalendarUnit.Minute, fromDate: time).minute
        let startDateCalendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
        combinedDateTime = startDateCalendar!.dateFromComponents(startDateTimeComponents)!
        

        【讨论】:

          【解决方案10】:

          根据苹果的Data Formatting Guide

          创建日期格式化程序并不是一项廉价的操作。如果你很可能 要经常使用格式化程序,缓存通常更有效 单个实例而不是创建和处置多个实例。 一种方法是使用静态变量

          虽然我同意@Leon 的观点,这最好是一个可失败的初始化程序,但并不总是必须如此(就像UIImage(imageLiteralResourceName:) 会在资源不存在时崩溃一样)。

          所以这是我的方法:

          extension DateFormatter {
            static let yyyyMMdd: DateFormatter = {
              let formatter = DateFormatter()
              formatter.dateFormat = "yyyy-MM-dd"
              formatter.calendar = Calendar(identifier: .iso8601)
              formatter.timeZone = TimeZone(secondsFromGMT: 0)
              formatter.locale = Locale(identifier: "en_US_POSIX")
              return formatter
            }()
          }
          
          extension Date {
              init?(yyyyMMdd: String) {
                  guard let date = DateFormatter.yyyyMMdd.date(from: yyyyMMdd) else { return nil }
                  self.init(timeInterval: 0, since: date)
              }
          
              init(dateLiteralString yyyyMMdd: String) {
                  let date = DateFormatter.yyyyMMdd.date(from: yyyyMMdd)!
                  self.init(timeInterval: 0, since: date)
              }
          }
          

          现在享受简单的调用:

          // For cases where the date exists for sure (eg. seed data)
          Date(dateLiteralString: "2020-03-30")
          
          // The rest of the time (eg. parsing unknown data)
          guard let date = Date(yyyyMMdd: "2020-03-30") else { return nil }
          

          【讨论】:

            猜你喜欢
            • 2018-03-06
            • 1970-01-01
            • 2018-10-10
            • 1970-01-01
            • 1970-01-01
            • 2016-12-30
            • 2010-09-05
            • 2015-12-02
            相关资源
            最近更新 更多