Bir Swift Date nesnesi nasıl oluşturulur?


156

Swift xcode içindeki bir tarihten bir tarih nesnesi nasıl oluşturulur?

örneğin javascript ile şunları yapabilirsiniz: var day = new Date('2014-05-20');


10
NSDateObjective-C gibi kullanın ?
rmaddy

Yanıtlar:


263

Swift'in kendi Datetipi var. Kullanmanıza gerek yok NSDate.

Swift'te Tarih ve Saat Oluşturma

Swift'te tarihler ve saatler, 1 Ocak 2001 referans tarihinden bu yana 00:00:00 UTC değerinden bu yana geçen saniye sayısını ölçen 64 bit kayan noktalı bir sayıya kaydedilir . Bu Dateyapıda ifade edilir . Aşağıdakiler size güncel tarih ve saati verecektir:

let currentDateTime = Date()

Başka tarih saatleri oluşturmak için aşağıdaki yöntemlerden birini kullanabilirsiniz.

Yöntem 1

2001 referans tarihinden önceki veya sonraki saniye sayısını biliyorsanız, bunu kullanabilirsiniz.

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

Yöntem 2

Tabii ki, bir yapmak için yıllar, aylar, günler ve saatler (göreli saniye yerine) kullanmak daha kolay olurdu Date. Bunun için DateComponentsbileşenleri belirtmek ve sonra Calendartarihi oluşturmak için kullanabilirsiniz. CalendarVerir Datebağlamı. Aksi takdirde, hangi saat dilimini veya takvimi ifade edeceğini nasıl bilebilir?

// 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.current // user calendar
let someDateTime = userCalendar.date(from: dateComponents)

Diğer saat dilimi kısaltmaları burada bulunabilir . Bunu boş bırakırsanız, varsayılan değer kullanıcının saat dilimini kullanmaktır.

Yöntem 3

En özlü yol (ama mutlaka en iyisi değil) kullanmak olabilir DateFormatter.

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

Unicode teknik standartlar diğer biçimleri göstermek olduğunu DateFormatterdestekler.

notlar

Tarih ve saatin okunabilir bir biçimde nasıl görüntüleneceği ile ilgili tam cevabımı görün . Ayrıca bu mükemmel makaleleri okuyun:


118

Bu en iyi, mevcut NSDatesınıfa bir uzantı kullanılarak yapılır .

Aşağıdaki uzantı, tarih dizesini belirttiğiniz biçimde kullanarak geçerli yerel ayarda bir tarih oluşturacak yeni bir başlatıcı ekler.

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)
    }
 }

Artık Swift'ten bir NSDate oluşturarak şunları yapabilirsiniz:

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

Bu uygulamanın, NSDatebu şekilde birçok s oluşturmayı umuyorsanız performans nedenleriyle yapmak isteyebileceğiniz NSDateFormatter'ı önbelleğe almadığını lütfen unutmayın .

Ayrıca, NSDatedoğru ayrıştırılamayan bir dize geçirerek bir başlatmaya çalışırsanız bu uygulamanın çökeceğini unutmayın . Bunun nedeni, döndürülen isteğe bağlı değerin zorla açılmasıdır dateFromString. nilKötü ayrıştırmalarda bir geri dönmek isterseniz, ideal olarak başarısız bir başlatıcı kullanabilirsiniz; ancak Swift 1.2'deki bir sınırlama nedeniyle bunu şimdi (Haziran 2015) yapamazsınız, bu yüzden bir sonraki en iyi seçim bir sınıf fabrikası yöntemi kullanmaktır.

Her iki sorunu da ele alan daha ayrıntılı bir örnek: https://gist.github.com/algal/09b08515460b7bd229fa .


Swift 5 için güncelleme

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)
    }
}

9
Peki "kolaylık" kelimesi burada ne yapar?
james Burns

18
Uzantının, aslında mevcut bir atanmış başlatıcıya başlatmayı temsil eden bir başlatıcı sağladığını belirtir; bu durumda NSDate.init (timeInterval:, sinceDate :) başlatıcısıdır. Bu, Swift Programlama Dili kitabının 275. sayfasında açıklanmaktadır.
algal

1
Yukarıdaki kodda gördüğüm bir kusur NSDateFormatterişleve her erişildiğinde yeniden oluşturuluyor . Gibi tarihi Biçimlendirme Kılavuzu devletler oluşturmak ucuz bir işlem değildir . Ayrıca, sınıf iOS7'den beri iş parçacığı açısından güvenlidir, bu yüzden tüm NSDateuzantılar için güvenle kullanabilirsiniz .
Yevhen Dubinin

@eugenedubinin doğru. bu yüzden "bu uygulama performans nedenleriyle yapmak isteyebileceğiniz NSDateFormatter'ı önbelleğe almaz" dedim.
algal

1
Swift 1.2'deki sınırlama nedir? "Failable başlatıcı" özelliği, Swift 1.1'den beri kullanılabilmektedir .
Franklin Yu

48

Swift'in kendi Tarih türü yok, ancak mevcut Kakao NSDatetürünü kullanıyorsunuz, örneğin:

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
    }
}

Hangi gibi kullanabilirsiniz:

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

Satırı değiştirmek zorunda kaldım: var date = gregorian? .DateFromComponents (c) ama nedenini anlamıyorum ve ayrıştırma tarihi DateFmt.dateFromString de şikayetçi. Herhangi bir ipucu var mı? Ah, işlevin dönüş türünü NSDate'den NSDate'e değiştirdim mi? hangi derlemek sağlar. Ama neden geçersiz olması gerektiğinden emin değilim.
Senatör

1
@TheSenator NSCalendar init isteğe bağlı (?) Döndürür, böylece gregorian isteğe bağlı (?) Olur. O kadar gregoryan? .DateFromCoomponents'e erişmek için isteğe bağlı zincirleme için isteğe bağlı bir ihtiyaca erişmek, değeri gregoryan (NSCalendar) seçeneklerinden açmak için İsteğe bağlı zincirleme. Burada
iluvatar_GR

NSGregorianCalendar, iOS 8'den itibaren kullanımdan kaldırıldı, bu nedenle NSCalendarIdentifierGregorian'ı kullanın
Adam Knights

2
Senatör Şikayet coz Swift'in Date yapısı vardır ve bu kod Date'i sınıf olarak yeniden açıklar. Bu yüzden u 'uzatma tarihi' ve 'statik fonk' gibi bir şey yapmalısınız
Zaporozhchenko Oleksandr

Dizeyi ayrıştırma tarihi hakkında bir not. İçin "yyyy-AA-aa" ile bir dizi "1979/07/01" NSDateFormatteryöntemi date(from:). Geri döner nil. Bu sorunu fabric.io kilitlenme günlüğünde buldum.
AechoLiu

12

Swift 4.2'de şöyle yaptım:

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
    }
}

Kullanımı:

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

Bir gün olarak '15'i geçmeme rağmen iade tarihi 14'üncü? Düşünceler?
Luke Zammit

@LukeZammit Saat dilimi ekledateComponents
Adrian

bunu şanssız denedim - dateComponents.timeZone = TimeZone.current, düşünceler lütfen?
Luke Zammit

5

Apple belgelerine göre

Misal :

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

3
Güzel ama soruyu cevaplamıyor, soru zaman aralıklarıyla ilgili değil.
zaph

4

Swift 3.0'da bu amaçla tarih nesnesi ayarladınız.

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 istediğiniz her yerde. Ayrı bir dosya oluşturun, buna "Uzantı" deyin, idk.
Zaporozhchenko Oleksandr

2

Şahsen ben bir failable başlatıcı olması gerektiğini düşünüyorum:

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
        }
    }
}

Aksi takdirde, geçersiz biçime sahip bir dize bir istisna oluşturur.


2

@ Mythz cevabına göre, swift3sözdizimini kullanarak uzantısının güncellenmiş sürümünü yayınlamaya karar verdim .

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)
    }
}

parseYöntem kullanmıyorum , ancak birisinin ihtiyacı varsa, bu yayını güncelleyeceğim.


1

Sık sık bir yerden tarih değerlerini diğeri için zaman değerleriyle birleştirmem gerekiyor. Bunu başarmak için bir yardımcı fonksiyon yazdım.

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)!

0

Apple'ın Veri Biçimlendirme Kılavuzu'na göre

Tarih biçimlendirici oluşturmak ucuz bir işlem değildir. Bir biçimlendiriciyi sık sık kullanmanız gerekiyorsa, genellikle tek bir örneği önbelleğe almak, birden çok örneği oluşturmak ve atmaktan daha etkilidir. Bir yaklaşım statik bir değişken kullanmaktır

Ve @Leon ile bunun failable başlatıcısı olması gerektiğine katılırken, tohum verilerini girdiğinizde, falan edilemeyen bir tane olabilir (tıpkı olduğu gibi UIImage(imageLiteralResourceName:)).

İşte yaklaşımım:

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)
    }
}

Ve şimdi sadece aramanın tadını çıkarın:

// For seed data
Date(dateLiteralString: "2020-03-30")

// When parsing data
guard let date = Date(yyyyMMdd: "2020-03-30") else { return nil }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.