İki NSDate arasındaki hızlı günler


112

Swift'deki iki NSDate / "yeni" Cocoa arasındaki gün sayısını almak için yeni ve harika bir olasılık olup olmadığını merak ediyorum.

Örneğin Ruby'deki gibi yapardım:

(end_date - start_date).to_i

5
Hala NSCalendar ve NSDateComponents kullanmanız gerektiğini düşünüyorum (bunun için SO'da yüzlerce cevap olması gerekir). - "Yeni ve harika bir olasılık" arıyorsanız , karşılaştırma için mevcut çözümünüzü göstermeniz faydalı olacaktır.
Martin R.

1
Bu artık çok kolay ve "NS" yi kullanmak zorunda değilsiniz. Kopyalayıp yapıştırmak için 2017 için bir cevap yazdım.
Fattie

Yanıtlar:


248

Saat farkını da göz önünde bulundurmalısınız. Örneğin, tarihleri ​​karşılaştırırsanız 2015-01-01 10:00ve 2015-01-02 09:00bu tarihler arasındaki günler 0 (sıfır) olarak dönecektir, çünkü bu tarihler arasındaki fark 24 saatten azdır (23 saattir).

Amacınız iki tarih arasındaki tam gün numarasını almaksa, bu sorunu şu şekilde çözebilirsiniz:

// Assuming that firstDate and secondDate are defined
// ...

let calendar = NSCalendar.currentCalendar()

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)

let flags = NSCalendarUnit.Day
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: [])

components.day  // This will return the number of day(s) between dates

Swift 3 ve Swift 4 Versiyonu

let calendar = Calendar.current

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: firstDate)
let date2 = calendar.startOfDay(for: secondDate)

let components = calendar.dateComponents([.day], from: date1, to: date2)

14
Aslında startOfDayForDate yerine öğlen 12: 00'yi kontrol etmek isteyebilirsiniz - saat dilimlerini ve DST'yi ayarlamanız nedeniyle daha az gürültü yapmalısınız.
brandonscript

11
Tarihleri ​​öğlen olarak ayarlamak şu şekilde yapılabilir:calendar.date(bySettingHour: 12, minute: 00, second: 00, of: calendar.startOfDay(for: firstDate))
MonsieurDart

Öğlen ayarlanması için kısa versiyonu ( startOfDay()gereksiz gibi görünüyor): calendar.date(bySettingHour: 12, minute: 0, second: 0, of: firstDate).
jamix

52

İşte Swift 2 için cevabım:

func daysBetweenDates(startDate: NSDate, endDate: NSDate) -> Int
{
    let calendar = NSCalendar.currentCalendar()

    let components = calendar.components([.Day], fromDate: startDate, toDate: endDate, options: [])

    return components.day
}

Bunu yukarıdaki @vikingosegundo yazısının bileşenleriyle başarıyla kullandım. İki tarih arasındaki doğru gün sayısını temsil eden bir tamsayı döndürür. <beğendim>
Hesabımı Sil

Hoşuma gitti ama işlev adı "daysBetweenDates" olmalı
mbonness

4
Bu döner 0 Karşılaştırdığımız eğer todayvetomorrow
Tevhîd

39

Birkaç Swift3 yanıtı görüyorum, bu yüzden kendi yanıtımı ekleyeceğim:

public static func daysBetween(start: Date, end: Date) -> Int {
   Calendar.current.dateComponents([.day], from: start, to: end).day!
}

Adlandırma daha Swifty hissettiriyor, tek satır ve en son dateComponents()yöntemi kullanıyor .


28

Benim tercüme Objective-C cevabı

let start = "2010-09-01"
let end = "2010-09-05"

let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"

let startDate:NSDate = dateFormatter.dateFromString(start)
let endDate:NSDate = dateFormatter.dateFromString(end)

let cal = NSCalendar.currentCalendar()


let unit:NSCalendarUnit = .Day

let components = cal.components(unit, fromDate: startDate, toDate: endDate, options: nil)


println(components)

sonuç

<NSDateComponents: 0x10280a8a0>
     Day: 4

En zor kısım, otomatik tamamlamanın tarih ve tarih arasındaki ısrarıydı NSDate?, ancak aslında NSDate!referansta gösterildiği gibi olmaları gerekir .

Her durumda birimi farklı şekilde belirtmek istediğinizden, bir operatörle nasıl iyi bir çözümün nasıl görüneceğini anlamıyorum. Zaman aralığını döndürebilirsiniz, ancak çok fazla kazanmayacaksınız.


Görünüşe .DayCalendarUnitgöre kullanımdan kaldırılmış. Şimdi .CalendarUnitDaybunun yerine kullanmanız gerektiğine inanıyorum .
TaylorAllred

2
seçenekler artık beklenen bir parametredir
Departamento B

2
Swift 2'yi çalıştırmak benim için çalışıyor:let components = cal.components(.Day, fromDate: startDate, toDate: endDate, options: [])
Andrej

Sadece @TaylorAllred .Dayşimdi
William GP

28

DateYıllar, aylar, günler, saatler, dakikalar, saniye cinsinden tarihler arasında fark elde etmek için çok güzel bir uzantı

extension Date {

    func years(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.year], from: sinceDate, to: self).year
    }

    func months(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.month], from: sinceDate, to: self).month
    }

    func days(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.day], from: sinceDate, to: self).day
    }

    func hours(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.hour], from: sinceDate, to: self).hour
    }

    func minutes(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.minute], from: sinceDate, to: self).minute
    }

    func seconds(sinceDate: Date) -> Int? {
        return Calendar.current.dateComponents([.second], from: sinceDate, to: self).second
    }

}

1
datesinceDatefonksiyon parametrelerinde olmalıdır .
TheTiger

@TheTiger - Bu cevabın en büyük hatasını vurguladığınız için çok teşekkür ederiz .. Cevabı pratik olarak test edip güncelleyeceğim.
Krunal

1
Zevkle! Bunu test ettim daysve iyi çalışıyor.
TheTiger

1
İyi cevap. Ben sadece öneririm func years(since date: Date) -> Int? { return Calendar.current.dateComponents[.year], from: date, to: self).years }ve sen de öyle diyebilirsin let y = date1.years(since: date2). Bu, modern adlandırma kurallarıyla daha tutarlı olabilir.
Rob

18

Swift 3 iOS 10 Beta 4 güncellemesi

func daysBetweenDates(startDate: Date, endDate: Date) -> Int {
    let calendar = Calendar.current
    let components = calendar.dateComponents([Calendar.Component.day], from: startDate, to: endDate)
    return components.day!
}

10

İşte Swift 3'ün cevabı (IOS 10 Beta için test edildi)

func daysBetweenDates(startDate: Date, endDate: Date) -> Int
{
    let calendar = Calendar.current
    let components = calendar.components([.day], from: startDate, to: endDate, options: [])
    return components.day!
}

O zaman buna böyle diyebilirsin

let pickedDate: Date = sender.date
let NumOfDays: Int = daysBetweenDates(startDate: pickedDate, endDate: Date())
    print("Num of Days: \(NumOfDays)")

7

Swift 3. Yukarıdaki öneri için Emin Buğra Saral'a teşekkürler startOfDay.

extension Date {

    func daysBetween(date: Date) -> Int {
        return Date.daysBetween(start: self, end: date)
    }

    static func daysBetween(start: Date, end: Date) -> Int {
        let calendar = Calendar.current

        // Replace the hour (time) of both dates with 00:00
        let date1 = calendar.startOfDay(for: start)
        let date2 = calendar.startOfDay(for: end)

        let a = calendar.dateComponents([.day], from: date1, to: date2)
        return a.value(for: .day)!
    }
}

Kullanımı:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let start = dateFormatter.date(from: "2017-01-01")!
let end = dateFormatter.date(from: "2018-01-01")!

let diff = Date.daysBetween(start: start, end: end) // 365

1
Birçok sorundan kaçınmak için ikisini de 00:00 yerine öğlene götürmek kesinlikle daha iyi olacaktır .
Fattie

3

Swift'in içine yerleştirilen şeyler hala çok basit. Bu erken aşamada olmaları gerektiği gibi. Ancak, aşırı yükleme operatörleri ve küresel etki alanı işlevlerinin getirdiği riskle kendi öğelerinizi ekleyebilirsiniz. Yine de modülünüz için yerel olacaklar.

let now = NSDate()
let seventies = NSDate(timeIntervalSince1970: 0)

// Standard solution still works
let days = NSCalendar.currentCalendar().components(.CalendarUnitDay, 
           fromDate: seventies, toDate: now, options: nil).day

// Flashy swift... maybe...
func -(lhs:NSDate, rhs:NSDate) -> DateRange {
    return DateRange(startDate: rhs, endDate: lhs)
}

class DateRange {
    let startDate:NSDate
    let endDate:NSDate
    var calendar = NSCalendar.currentCalendar()
    var days: Int {
        return calendar.components(.CalendarUnitDay, 
               fromDate: startDate, toDate: endDate, options: nil).day
    }
    var months: Int {
        return calendar.components(.CalendarUnitMonth, 
               fromDate: startDate, toDate: endDate, options: nil).month
    }
    init(startDate:NSDate, endDate:NSDate) {
        self.startDate = startDate
        self.endDate = endDate
    }
}

// Now you can do this...
(now - seventies).months
(now - seventies).days

19
Etmeyin bir günün uzunluğu için (24 * 60 * 60) kullanın. Bu, gün ışığından yararlanma saati geçişlerini hesaba katmaz.
Martin R.

NSDate'in her zaman GMT kullandığından ve gün ışığından yararlanmanın bunun üzerine sadece bir biçimlendirme veya yerelleştirme olduğu için bunu ayarlayacağını düşünüyorum. Elbette aylar, yıllar veya gerçekten değişken uzunluktaki herhangi bir şey için daha zorlaşır.
Daniel Schlaug

1
@MartinR Buna inanmak için denemeliydim ama gerçekten, şimdi yaptığım için wikipedia'da da bundan bahsettiğini gördüm. Haklısın. Bana karşı inatçı olduğun için teşekkürler.
Daniel Schlaug

1
Doğru olacak şekilde düzenlenmiştir. Ama gösterişlilik bir şekilde kayboldu.
Daniel Schlaug

1
konum, zaman noktası ve takvim sistemi ile tanımlanır. İbrani takviminin artık ayı var. harika bir wwdc videosu var: takvim hesaplaması yapmak - her kakao kodlayıcı için mutlaka görülmesi gereken bir şey.
vikingosegundo

3

İşte Swift 3 için cevabım:

func daysBetweenDates(startDate: NSDate, endDate: NSDate, inTimeZone timeZone: TimeZone? = nil) -> Int {
    var calendar = Calendar.current
    if let timeZone = timeZone {
        calendar.timeZone = timeZone
    }
    let dateComponents = calendar.dateComponents([.day], from: startDate.startOfDay, to: endDate.startOfDay)
    return dateComponents.day!
}

2

Henüz Swift'e özgü standart kitaplık neredeyse yok; sadece yalın temel sayısal, dize ve koleksiyon türleri.

Uzantıları kullanarak bu tür kısayolları tanımlamak tamamen mümkündür, ancak kullanıma hazır API'ler söz konusu olduğunda "yeni" Kakao yoktur; Swift, zaten mevcut olan aynı eski ayrıntılı Cocoa API'leriyle doğrudan eşleşir.


2

Bu iş parçacığı bir yaşında olmasına rağmen sürümümü ekleyeceğim. Kodum şöyle görünüyor:

    var name = txtName.stringValue // Get the users name

    // Get the date components from the window controls
    var dateComponents = NSDateComponents()
    dateComponents.day = txtDOBDay.integerValue
    dateComponents.month = txtDOBMonth.integerValue
    dateComponents.year = txtDOBYear.integerValue

    // Make a Gregorian calendar
    let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)

    // Get the two dates we need
    var birthdate = calendar?.dateFromComponents(dateComponents)
    let currentDate = NSDate()

    var durationDateComponents = calendar?.components(NSCalendarUnit.CalendarUnitDay, fromDate: birthdate!, toDate: currentDate, options: nil)

    let numberOfDaysAlive = durationDateComponents?.day

    println("\(numberOfDaysAlive!)")

    txtGreeting.stringValue = "Hello \(name), You have been alive for \(numberOfDaysAlive!) days."

Umarım birine yardımcı olur.

Alkış,


2

Erin'in yöntemi Swift 3'e güncellendi, Bu, bugünden sonraki günleri gösterir (günün saati dikkate alınmadan)

func daysBetweenDates( endDate: Date) -> Int 
    let calendar: Calendar = Calendar.current 
    let date1 = calendar.startOfDay(for: Date()) 
    let date2 = calendar.startOfDay(for: secondDate) 
    return calendar.dateComponents([.day], from: date1, to: date2).day! 
}

2

Bu, Datebugün ile bugün arasındaki günlerde mutlak bir fark döndürür :

extension Date {
  func daysFromToday() -> Int {
    return abs(Calendar.current.dateComponents([.day], from: self, to: Date()).day!)
  }
}

ve sonra kullanın:

if someDate.daysFromToday() >= 7 {
  // at least a week from today
}

2

Aşağıdaki uzantıyı kullanabilirsiniz:

public extension Date {
    func daysTo(_ date: Date) -> Int? {
        let calendar = Calendar.current

        // Replace the hour (time) of both dates with 00:00
        let date1 = calendar.startOfDay(for: self)
        let date2 = calendar.startOfDay(for: date)

        let components = calendar.dateComponents([.day], from: date1, to: date2)
        return components.day  // This will return the number of day(s) between dates
    }
}

O zaman şöyle diyebilirsiniz:

startDate.daysTo(endDate)

1

Swift 3.2

extension DateComponentsFormatter {
    func difference(from fromDate: Date, to toDate: Date) -> String? {
        self.allowedUnits = [.year,.month,.weekOfMonth,.day]
        self.maximumUnitCount = 1
        self.unitsStyle = .full
        return self.string(from: fromDate, to: toDate)
    }
}

1

Tüm cevaplar güzel. Ancak Yerelleştirmeler için iki tarih arasında birkaç ondalık gün hesaplamamız gerekir. böylece sürdürülebilir ondalık biçimi sağlayabiliriz.

// This method returns the fractional number of days between to dates
func getFractionalDaysBetweenDates(date1: Date, date2: Date) -> Double {

    let components = Calendar.current.dateComponents([.day, .hour], from: date1, to: date2)

    var decimalDays = Double(components.day!)
    decimalDays += Double(components.hour!) / 24.0

    return decimalDays
}

1
extension Date {
    func daysFromToday() -> Int {
        return Calendar.current.dateComponents([.day], from: self, to: Date()).day!
    }
}

O zaman bunu gibi kullan

    func dayCount(dateString: String) -> String{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMM dd,yyyy hh:mm a"
        let fetchedDate = dateFormatter.date(from: dateString)


        let day = fetchedDate?.daysFromToday()
        if day! > -1{
            return "\(day!) days passed."
        }else{
        return "\(day! * -1) days left."
        }
    }

1

Bu, Günleri karşılaştırmak için kesin zaman olarak gece yarısı yerine öğlen kullanma önerisini içeren, Emin'in Swift 5 cevabının güncellenmiş bir versiyonudur. Ayrıca, isteğe bağlı bir döndürerek çeşitli tarih işlevlerinin olası başarısızlıklarını da ele alır.

    ///
    /// This is an approximation; it does not account for time differences. It will set the time to 1200 (noon) and provide the absolute number
    /// of days between now and the given date. If the result is negative, it should be read as "days ago" instead of "days from today."
    /// Returns nil if something goes wrong initializing or adjusting dates.
    ///

    func daysFromToday() -> Int?
    {
        let calendar = NSCalendar.current

        // Replace the hour (time) of both dates with noon. (Noon is less likely to be affected by DST changes, timezones, etc. than midnight.)
        guard let date1 = calendar.date(bySettingHour: 12, minute: 00, second: 00, of: calendar.startOfDay(for: Date())),
              let date2 = calendar.date(bySettingHour: 12, minute: 00, second: 00, of: calendar.startOfDay(for: self)) else
        {
            return nil
        }

        return calendar.dateComponents([.day], from: date1, to: date2).day
    }

Swift yerel Takvimini kullanmalısınız (NS'yi bırakın). Saati 12: 00'ye ayarlarken korumanın kullanılması anlamsızdır. Asla başarısız olmayacak.
Leo Dabus

Saati öğlen olarak ayarlamadan önce startOfDay'i çağırmak da anlamsızdır.
Leo Dabus

0

Swift 3 - Bugünden bugüne kadar geçen gün sayısı

func daysUntilDate(endDateComponents: DateComponents) -> Int
    {
        let cal = Calendar.current
        var components = cal.dateComponents([.era, .year, .month, .day], from: NSDate() as Date)
        let today = cal.date(from: components)
        let otherDate = cal.date(from: endDateComponents)

        components = cal.dateComponents([Calendar.Component.day], from: (today! as Date), to: otherDate!)
        return components.day!
    }

Bunun gibi işlevi çağır

// Days from today until date
   var examnDate = DateComponents()
   examnDate.year = 2016
   examnDate.month = 12
   examnDate.day = 15
   let daysCount = daysUntilDate(endDateComponents: examnDate)

0

daha kolay seçenek, Tarih üzerinde bir uzantı oluşturmaktır

public extension Date {

        public var currentCalendar: Calendar {
            return Calendar.autoupdatingCurrent
        }

        public func daysBetween(_ date: Date) -> Int {
            let components = currentCalendar.dateComponents([.day], from: self, to: date)
            return components.day!
        }
    }

0
  func completeOffset(from date:Date) -> String? {

    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .brief

    return  formatter.string(from: Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second], from: date, to: self))




}

dizi olarak yılın ay günlerine ve saatlerine ihtiyacınız varsa bunu kullanın

var yarın = Calendar.current.date (Ekleyerek: .day, değer: 1, kime: Tarih ())!

let dc = tomorrow.completeOffset (from: Date ())


0

Güzel kullanışlı tek astar:

extension Date {
  var daysFromNow: Int {
    return Calendar.current.dateComponents([.day], from: Date(), to: self).day!
  }
}

0

Swift 4

 func getDateHeader(indexPath: Int) -> String {
    let formatter2 = DateFormatter()
    formatter2.dateFormat = "MM-dd-yyyy"
    var dateDeadline : Date?

    dateDeadline = formatter2.date(from: arrCompletedDate[indexPath] as! String)

    let currentTime = dateDeadline?.unixTimestamp
    let calendar = NSCalendar.current

    let date = NSDate(timeIntervalSince1970: Double(currentTime!))
    if calendar.isDateInYesterday(date as Date) { return "Yesterday" }
    else if calendar.isDateInToday(date as Date) { return "Today" }
    else if calendar.isDateInTomorrow(date as Date) { return "Tomorrow" }
    else {
        let startOfNow = calendar.startOfDay(for: NSDate() as Date)
        let startOfTimeStamp = calendar.startOfDay(for: date as Date)
        let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
        let day = components.day!
        if day < 1 { return "\(abs(day)) days ago" }
        else { return "In \(day) days" }
    }
}

0

Swift 5.2.4 çözümü:

import UIKit

let calendar = Calendar.current

let start = "2010-09-01"
let end = "2010-09-05"

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"

let firstDate = dateFormatter.date(from: start)!
let secondDate = dateFormatter.date(from: end)!

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: firstDate)
let date2 = calendar.startOfDay(for: secondDate)

let components = calendar.dateComponents([Calendar.Component.day], from: date1, to: date2)

components.day  // This will return the number of day(s) between dates

-1

2017 sürümü, kopyala ve yapıştır

func simpleIndex(ofDate: Date) -> Int {
    
    // index here just means today 0, yesterday -1, tomorrow 1 etc.
    
    let c = Calendar.current
    let todayRightNow = Date()
    
    let d = c.date(bySetting: .hour, value: 13, of: ofDate)
    let t = c.date(bySetting: .hour, value: 13, of: todayRightNow)
    
    if d == nil || today == nil {
    
        print("weird problem simpleIndex#ofDate")
        return 0
    }
    
    let r = c.dateComponents([.day], from: today!, to: d!)
    // yesterday is negative one, tomorrow is one
    
    if let o = r.value(for: .day) {
        
        return o
    }
    else {
    
        print("another weird problem simpleIndex#ofDate")
        return 0
    }
}

-2
let calendar = NSCalendar.currentCalendar();
let component1 = calendar.component(.Day, fromDate: fromDate)
let component2 = calendar.component(.Day, fromDate: toDate)
let difference  = component1 - component2

1
tarihlerin sayı bölümü arasındaki farkı ölçer - yani 21 Ocak - 22 Şubat olması gerektiği gibi 32 gün değil 1 gün verecektir
Peter Johnson
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.