Perbandingan NSDate menggunakan Swift

153

Saya sedang mengerjakan suatu aplikasi yang membutuhkan pengecekan tanggal jatuh tempo untuk pekerjaan rumah. Saya ingin tahu apakah tanggal jatuh tempo adalah dalam minggu depan, dan apakah itu kemudian melakukan suatu tindakan.
Sebagian besar dokumentasi yang bisa saya temukan ada di Objective-C dan saya tidak tahu bagaimana melakukannya di Swift. Terima kasih untuk bantuannya!!

Henry pembuat oscannlain
sumber
2
swift tidak memiliki kelas tanggal Anda menggunakan kelas Objective C NSDate - jadi Anda telah menemukan dokumentasi yang benar
mmmmmm
Kemungkinan duplikat Membandingkan NSDates tanpa komponen waktu . Ada banyak jawaban yang sangat bagus.
jww
2
Swift 3 memang memiliki Datekelas. Itu dijembatani NSDate, tetapi disebut Date.
BallpointBen

Jawaban:

188

Saya suka menggunakan ekstensi untuk membuat kode lebih mudah dibaca. Berikut adalah beberapa ekstensi NSDate yang dapat membantu membersihkan kode Anda dan membuatnya mudah dimengerti. Saya menempatkan ini dalam file sharedCode.swift:

extension NSDate {

    func isGreaterThanDate(dateToCompare: NSDate) -> Bool {
        //Declare Variables
        var isGreater = false

        //Compare Values
        if self.compare(dateToCompare as Date) == ComparisonResult.orderedDescending {
            isGreater = true
        }

        //Return Result
        return isGreater
    }

    func isLessThanDate(dateToCompare: NSDate) -> Bool {
        //Declare Variables
        var isLess = false

        //Compare Values
        if self.compare(dateToCompare as Date) == ComparisonResult.orderedAscending {
            isLess = true
        }

        //Return Result
        return isLess
    }

    func equalToDate(dateToCompare: NSDate) -> Bool {
        //Declare Variables
        var isEqualTo = false

        //Compare Values
        if self.compare(dateToCompare as Date) == ComparisonResult.orderedSame {
            isEqualTo = true
        }

        //Return Result
        return isEqualTo
    }

    func addDays(daysToAdd: Int) -> NSDate {
        let secondsInDays: TimeInterval = Double(daysToAdd) * 60 * 60 * 24
        let dateWithDaysAdded: NSDate = self.addingTimeInterval(secondsInDays)

        //Return Result
        return dateWithDaysAdded
    }

    func addHours(hoursToAdd: Int) -> NSDate {
        let secondsInHours: TimeInterval = Double(hoursToAdd) * 60 * 60
        let dateWithHoursAdded: NSDate = self.addingTimeInterval(secondsInHours)

        //Return Result
        return dateWithHoursAdded
    }
}

Sekarang jika Anda dapat melakukan sesuatu seperti ini:

//Get Current Date/Time
var currentDateTime = NSDate()

//Get Reminder Date (which is Due date minus 7 days lets say)
var reminderDate = dueDate.addDays(-7)

//Check if reminderDate is Greater than Right now
if(reminderDate.isGreaterThanDate(currentDateTime)) {
    //Do Something...
}
pengguna2266987
sumber
28
Anda harus menyederhanakan kode Anda. return self.compare(dateToCompare) == NSComparisonResult.OrderedDescending
Olav Gausaker
5
isEqualToDate disediakan oleh Apple juga. Konflik deklarasi dengan yang ditentukan oleh Apple.
Shamas S - Pasang kembali Monica
4
Tidak setiap hari memiliki 24 jam
Leo Dabus
9
Jawaban ini mengerikan dan tidak boleh diterima. Jangan pernah menambahkan interval waktu ke tanggal yang Anda buat. Itulah mengapa NSDateComponentsada. Ada banyak kasus tepi yang tidak menjadi pegangan benar dan tidak masuk akal untuk tidak menambahkan kesesuaian dengan Comparableke NSDate. Saya akan merekomendasikan menggunakan solusi John .
fpg1503
3
Solusi yang lebih baik adalah membuat NSDate Equatable, Comparable, maka Anda bisa melakukannyadate1 < date2
aryaxt
209

Jika Anda ingin mendukung ==, <, >, <=, atau >=untuk NSDates, Anda hanya perlu untuk menyatakan suatu tempat ini:

public func ==(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs === rhs || lhs.compare(rhs) == .OrderedSame
}

public func <(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.compare(rhs) == .OrderedAscending
}

extension NSDate: Comparable { }
John Estropia
sumber
2
@ Isuru Comparableadalah turunan dari Equatableprotokol sehingga Anda tidak perlu menyatakan kesesuaian dengan keduanya.
John Estropia
2
Hanya ingin tahu mengapa itu tidak dibangun secara default ?!
dVaffection
3
@dVaffection Dalam Objective-C (di mana NSDate dan teman-teman dinyatakan), jika Anda membandingkan menggunakan ==, <, >, dll, Anda akan mendapatkan hasil dari perbandingan alamat mereka di memori, tidak perbandingan nilai aktual mereka. Di Swift, mereka masih diperlakukan sebagai referensi jadi saya pikir pilihannya adalah (1) tetap menggunakan perbandingan-pointer-seperti yang ada di ObjC, atau (2) menghilangkan kebingungan dengan tidak menyediakan implementasi untuk perbandingan.
John Estropia
2
Manfaat tambahan dari pendekatan ini adalah bahwa Array.maxElement(), dll. Kemudian secara otomatis tersedia dari array NSDates.
pr1001
1
@ MarcioCruz Itu hanya persyaratan Swift bahwa semua implementasi operator harus pada lingkup global. Lihat diskusi di sini: stackoverflow.com/questions/35246003/…
John Estropia
54

Ini adalah bagaimana Anda membandingkan dua NSDates di Swift, saya baru saja mengujinya di taman bermain Xcode:

if date1.compare(date2) == NSComparisonResult.OrderedDescending
{
    NSLog("date1 after date2");
} else if date1.compare(date2) == NSComparisonResult.OrderedAscending
{
    NSLog("date1 before date2");
} else
{
    NSLog("dates are equal");
}

Jadi untuk memeriksa apakah suatu kencan dueDatedalam seminggu dari sekarang:

let dueDate=...

let calendar = NSCalendar.currentCalendar()
let comps = NSDateComponents()
comps.day = 7
let date2 = calendar.dateByAddingComponents(comps, toDate: NSDate(), options: NSCalendarOptions.allZeros)

if dueDate.compare(date2!) == NSComparisonResult.OrderedDescending
{
    NSLog("not due within a week");
} else if dueDate.compare(date2!) == NSComparisonResult.OrderedAscending
{
    NSLog("due within a week");
} else
{
    NSLog("due in exactly a week (to the second, this will rarely happen in practice)");
}
Batalkan
sumber
2
apakah memerintahkan Descending berarti date1> date2?
Henry oscannlain-miller
1
Ya, @ Henryoscannlain-miller.
Undo
46

Saya selalu melakukannya dalam satu baris:

let greater = date1.timeIntervalSince1970 < date2.timeIntervalSince1970

Masih bisa dibaca di ifblok

Deteksi ulang
sumber
12

Di Swift3, Datestruct di Foundationsekarang mengimplementasikan Comparableprotokol. Jadi, NSDatependekatan Swift2 sebelumnya digantikan oleh Swift3 Date.

/**
 `Date` represents a single point in time.

 A `Date` is independent of a particular calendar or time zone. To represent a `Date` to a user, you must interpret it in the context of a `Calendar`.
*/
public struct Date : ReferenceConvertible, Comparable, Equatable {

    // .... more         

    /**
        Returns the interval between the receiver and another given date.

        - Parameter another: The date with which to compare the receiver.

        - Returns: The interval between the receiver and the `another` parameter. If the receiver is earlier than `anotherDate`, the return value is negative. If `anotherDate` is `nil`, the results are undefined.

        - SeeAlso: `timeIntervalSince1970`
        - SeeAlso: `timeIntervalSinceNow`
        - SeeAlso: `timeIntervalSinceReferenceDate`
        */
    public func timeIntervalSince(_ date: Date) -> TimeInterval

   // .... more 

    /// Returns true if the two `Date` values represent the same point in time.
    public static func ==(lhs: Date, rhs: Date) -> Bool

    /// Returns true if the left hand `Date` is earlier in time than the right hand `Date`.
    public static func <(lhs: Date, rhs: Date) -> Bool

    /// Returns true if the left hand `Date` is later in time than the right hand `Date`.
    public static func >(lhs: Date, rhs: Date) -> Bool

    /// Returns a `Date` with a specified amount of time added to it.
    public static func +(lhs: Date, rhs: TimeInterval) -> Date

    /// Returns a `Date` with a specified amount of time subtracted from it.
    public static func -(lhs: Date, rhs: TimeInterval) -> Date

  // .... more
}

Catatan ...

Dalam Swift3, Dateadalah struct, itu artinya value type. NSDateitu class, itu reference type.

// Swift3
let a = Date()
let b = a //< `b` will copy `a`. 

// So, the addresses between `a` and `b` are different.
// `Date` is some kind different with `NSDate`.
AechoLiu
sumber
6
extension NSDate {

    // MARK: - Dates comparison

    func isGreaterThanDate(dateToCompare: NSDate) -> Bool {

        return self.compare(dateToCompare) == NSComparisonResult.OrderedDescending
    }

    func isLessThanDate(dateToCompare: NSDate) -> Bool {

        return self.compare(dateToCompare) == NSComparisonResult.OrderedAscending
    }

    func equalToDate(dateToCompare: NSDate) -> Bool {

        return self.compare(dateToCompare) == NSComparisonResult.OrderedSame
    }
}
Yura Voevodin
sumber
6

Jika Anda ingin membandingkan tanggal dengan rincian (hanya pada hari atau tahun yang sama, dll) dengan cepat 3.

func compareDate(date1:NSDate, date2:NSDate, toUnitGranularity: NSCalendar.Unit) -> Bool {

 let order = NSCalendar.current.compare(date1 as Date, to: date2 as Date, toGranularity: .day)
 switch order {
 case .orderedSame:
   return true
 default:
   return false
 }
}

Untuk perbandingan kalender lainnya, ubah .hari menjadi;

.tahun .bulan .hari .jam .menit .detik

SashaZ
sumber
5

Swift sudah mengimplementasikan perbandingan tanggal, cukup gunakan date1> date2 dan seterusnya.

/// Returns true if the two `Date` values represent the same point in time.
public static func ==(lhs: Date, rhs: Date) -> Bool

/// Returns true if the left hand `Date` is earlier in time than the right hand `Date`.
public static func <(lhs: Date, rhs: Date) -> Bool

/// Returns true if the left hand `Date` is later in time than the right hand `Date`.
public static func >(lhs: Date, rhs: Date) -> Bool

/// Returns a `Date` with a specified amount of time added to it.
public static func +(lhs: Date, rhs: TimeInterval) -> Date

/// Returns a `Date` with a specified amount of time subtracted from it.
public static func -(lhs: Date, rhs: TimeInterval) -> Date

/// Add a `TimeInterval` to a `Date`.
///
/// - warning: This only adjusts an absolute value. If you wish to add calendrical concepts like hours, days, months then you must use a `Calendar`. That will take into account complexities like daylight saving time, months with different numbers of days, and more.
public static func +=(lhs: inout Date, rhs: TimeInterval)

/// Subtract a `TimeInterval` from a `Date`.
///
/// - warning: This only adjusts an absolute value. If you wish to add calendrical concepts like hours, days, months then you must use a `Calendar`. That will take into account complexities like daylight saving time, months with different numbers of days, and more.
public static func -=(lhs: inout Date, rhs: TimeInterval)
Trung Phan
sumber
4

di Swift 3, Date Sebanding sehingga kami dapat langsung membandingkan tanggal seperti

let date1 = Date()
let date2 = Date()

let isGreater = date1 > date2
print(isGreater)

let isEqual = date1 == date2
print(isEqual)

atau sebagai alternatif

let result = date1.compare(date2)
switch result {
    case .OrderedAscending     :   print("date 1 is earlier than date 2")
    case .OrderedDescending    :   print("date 1 is later than date 2")
    case .OrderedSame          :   print("two dates are the same")
}

cara pembuatan yang lebih baik extensionpada Tanggal

extension Date {

  fun isGreater(than date: Date) -> Bool {
    return self > date 
  }

  func isSmaller(than date: Date) -> Bool {
    return self < date
  }

  func isEqual(to date: Date) -> Bool {
    return self == date
  }

}

pemakaian let isGreater = date1.isGreater(than: date2)

Suhit Patil
sumber
3

Fungsi ini berfungsi untuk saya untuk membandingkan apakah satu tanggal (startDate) adalah setelah tanggal akhir di mana keduanya didefinisikan sebagai variabel NSDate:

if startDate.compare(endDate as Date) == ComparisonResult.orderedDescending
Diskprotek
sumber
2

implementasi di Swift

let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let files = NSFileManager.defaultManager().contentsOfDirectoryAtPath(documentsPath, error: nil)

let filesAndProperties = NSMutableArray()
for file in files! {

    let filePath = documentsPath.stringByAppendingString(file as NSString)
    let properties = NSFileManager.defaultManager().attributesOfItemAtPath(filePath, error: nil)
    let modDate = properties![NSFileModificationDate] as NSDate
    filesAndProperties.addObject(NSDictionary(objectsAndKeys: file, "path", modDate, "lastModDate"))
}

let sortedFiles = filesAndProperties.sortedArrayUsingComparator({
    (path1, path2) -> NSComparisonResult in

    var comp = (path1.objectForKey("lastModDate") as NSDate).compare(path2.objectForKey("lastModDate") as NSDate)
    if comp == .OrderedDescending {

        comp = .OrderedAscending
    } else if comp == .OrderedAscending {

        comp = .OrderedDescending
    }

    return comp
})
János
sumber
2
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateData: String = dateFormatter.stringFromDate(date1)
let testDate: String = dateFormatter.stringFromDate(date2)
print(dateData == testDate)
Trevor Jordet
sumber
1
someArray.sort({($0.dateAdded?.timeIntervalSinceReferenceDate)! < ($1.dateAdded?.timeIntervalSinceReferenceDate)!})

dateAdded adalah variabel NSDate di objek saya

class MyClass {
    let dateAdded: NSDate?
}
larod
sumber
1

Kami memiliki skenario untuk memeriksa waktu saat ini terletak dengan dua kali (dua tanggal). Misalnya, saya ingin memeriksa waktu saat ini antara waktu pembukaan dan waktu penutupan klinik (Rumah Sakit).

Gunakan Kode sederhana.

      NSDate * now = [NSDate date];
        NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
        [outputFormatter setDateFormat:@"HH:mm:ss"];

        //current time
        NSString *currentTimeString = [outputFormatter stringFromDate:now];
        NSDate *dateCurrent = [outputFormatter dateFromString:currentTimeString];


        NSString *timeStart = @"09:00:00";
        NSString *timeEnd = @"22:00:00";

        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"HH:mm:ss"];

        NSDate *dateStart= [formatter timeStart];
        NSDate *dateEnd = [formatter timeEnd];
        NSComparisonResult result = [dateCurrent compare:dateStart];
        NSComparisonResult resultSecond = [date2 compare:dateEnd];

if(result == NSOrderedDescending && resultSecond == NSOrderedDescending)
        {
            NSLog(@"current time lies in starting and end time");
    }else {
            NSLog(@"current time doesn't lie in starting and end time");
        }
Maninderjit Singh
sumber
1

Untuk swift 3, Anda dapat menggunakan fungsi di bawah ini untuk membandingkan antara dua tanggal.

func compareDate(dateInitial:Date, dateFinal:Date) -> Bool {
    let order = Calendar.current.compare(dateInitial, to: dateFinal, toGranularity: .day)
    switch order {
    case .orderedSame:
        return true
    default:
        return false
    }
}

toGranularity dapat diubah sesuai dengan kendala yang Anda inginkan untuk menerapkan perbandingan Anda.

Himanshu
sumber
1

Untuk memperluas pada SashaZ

Swift iOS 8 dan lebih tinggi Saat Anda membutuhkan lebih dari sekadar perbandingan tanggal yang lebih besar atau lebih kecil. Misalnya hari itu sama atau hari sebelumnya, ...

Catatan: Jangan pernah lupa zona waktu. Zona waktu kalender memiliki default, tetapi jika Anda tidak suka default, Anda harus mengatur sendiri zona waktu. Untuk mengetahui hari apa sekarang, Anda perlu tahu di zona waktu yang Anda tanyakan.

extension Date {
    func compareTo(date: Date, toGranularity: Calendar.Component ) -> ComparisonResult  {
        var cal = Calendar.current
        cal.timeZone = TimeZone(identifier: "Europe/Paris")!
        return cal.compare(self, to: date, toGranularity: toGranularity)
        }
    }

Gunakan seperti ini:

if thisDate.compareTo(date: Date(), toGranularity: .day) == .orderedDescending {
// thisDate is a previous day
}

Dari contoh yang lebih kompleks. Temukan dan filter semua tanggal dalam sebuah array, yang berasal dari hari yang sama dengan "findThisDay":

let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "Europe/Paris")
formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"

let findThisDay = formatter.date(from: "2018/11/05 08:11:08")!
_ = [
    formatter.date(from: "2018/12/05 08:08:08")!, 
    formatter.date(from: "2018/11/05 08:11:08")!,
    formatter.date(from: "2018/11/05 11:08:22")!,
    formatter.date(from: "2018/11/05 22:08:22")!,
    formatter.date(from: "2018/11/05 08:08:22")!,
    formatter.date(from: "2018/11/07 08:08:22")!,
    ]
    .filter{ findThisDay.compareTo(date: $0 , toGranularity: .day) == .orderedSame }
    .map { print(formatter.string(from: $0)) }
t1ser
sumber