เปรียบเทียบ NSDate โดยใช้ Swift


153

ฉันกำลังทำงานกับแอพที่ต้องตรวจสอบวันครบกำหนดสำหรับการบ้าน ฉันต้องการทราบว่าวันที่ครบกำหนดนั้นอยู่ภายในสัปดาห์หน้าหรือไม่และหากเป็นวันที่จะดำเนินการ
เอกสารส่วนใหญ่ที่ฉันพบได้คือใน Objective-C และฉันไม่สามารถหาวิธีที่จะทำได้ใน Swift ขอบคุณสำหรับความช่วยเหลือ !!


2
swift ไม่มีคลาสวันที่ที่คุณใช้คลาส ObjectD C NSDate - ดังนั้นคุณจึงได้พบเอกสารที่ถูกต้อง
mmmmmm

ซ้ำเป็นไปได้ของNSDates เปรียบเทียบองค์ประกอบโดยไม่ต้องเวลา มีคำตอบที่ดีมากมาย
jww

คำตอบที่เกี่ยวข้อง: stackoverflow.com/questions/29652771/…
jkdev

2
Swift 3 มีDateคลาส มันเป็นสะพานเชื่อมไปแต่จะเรียกว่าNSDate Date
BallpointBen

คำตอบ:


188

ฉันชอบใช้ส่วนขยายเพื่อให้โค้ดอ่านง่ายขึ้น ต่อไปนี้เป็นส่วนขยาย NSDate สองสามตัวที่สามารถช่วยล้างรหัสของคุณและทำให้เข้าใจง่าย ฉันวางไว้ในไฟล์ 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
    }
}

ตอนนี้ถ้าคุณสามารถทำสิ่งนี้:

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

28
คุณควรทำให้รหัสของคุณง่ายขึ้น return self.compare(dateToCompare) == NSComparisonResult.OrderedDescending
Olav Gausaker

5
isEqualToDate ให้บริการโดย Apple เช่นกัน การประกาศขัดแย้งกับสิ่งที่ Apple กำหนดไว้
Shamas S - Reinstate Monica

4
ไม่ใช่ทุกวันมี 24 ชั่วโมง
Leo Dabus

9
คำตอบนี้แย่มากและไม่ควรเป็นคำตอบที่ยอมรับ ไม่เคยเพิ่มช่วงเวลาวันที่สร้างขึ้นโดยคุณ นั่นเป็นเหตุผลที่แม่นยำNSDateComponentsที่มีอยู่ มีจำนวนมากของกรณีขอบที่ไม่ได้ถูกจับได้อย่างถูกต้องและมันทำให้รู้สึกไม่เพิ่มความสอดคล้องกับไม่มีการComparable NSDateฉันขอแนะนำให้ใช้วิธีการแก้ปัญหาของจอห์น
fpg1503

3
ทางออกที่ดีกว่าคือการทำให้ NSDate Equatable, Comparable แล้วคุณก็ทำได้date1 < date2
aryaxt

209

หากคุณต้องการให้การสนับสนุน==, <, >, <=หรือ>=สำหรับNSDates คุณเพียงแค่ต้องประกาศที่ไหนสักแห่งนี้:

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

2
@ Isuru Comparableเป็นผู้สืบทอดของEquatableโปรโตคอลดังนั้นคุณไม่จำเป็นต้องประกาศความสอดคล้องกับทั้งสองอย่าง
John Estropia

2
แค่สงสัยว่าทำไมมันไม่ได้ถูกสร้างขึ้นตามค่าเริ่มต้น!
dVaffection

3
@dVaffection ใน Objective-C (ที่ NSDate และเพื่อน ๆ มีการประกาศ) ถ้าคุณเปรียบเทียบโดยใช้==, <, >ฯลฯ คุณจะได้รับผลของการเปรียบเทียบที่อยู่ในความทรงจำของพวกเขาไม่ได้เปรียบเทียบค่าที่แท้จริงของพวกเขา ใน Swift พวกเขายังคงได้รับการปฏิบัติเหมือนเป็นข้อมูลอ้างอิงดังนั้นฉันคิดว่าตัวเลือกคือ (1) ใช้การเปรียบเทียบแบบตัวชี้ตามที่อยู่ใน ObjC หรือ (2) กำจัดความสับสนโดยไม่ใช้การเปรียบเทียบ
John Estropia

2
ประโยชน์เพิ่มเติมของวิธีนี้Array.maxElement()คือจากนั้นจะมีอาร์เรย์ของ NSDates ให้โดยอัตโนมัติ
pr1001

1
@MarcioCruz นั่นเป็นเพียงความต้องการที่รวดเร็วว่าการดำเนินการทั้งหมดของผู้ประกอบการควรอยู่ในขอบเขตทั่วโลก ดูการสนทนาได้ที่นี่: stackoverflow.com/questions/35246003/…
John Estropia

54

นี่คือวิธีที่คุณเปรียบเทียบ NSDates สองรายการใน Swift ฉันเพิ่งทดสอบในสนามเด็กเล่นของ 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");
}

ดังนั้นเพื่อตรวจสอบว่าวันที่dueDateภายในหนึ่งสัปดาห์นับจากนี้:

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

2
สั่งมากไปน้อยหมายความว่า date1> date2?
Henry oscannlain-miller

1
ใช่ @ Henryoscannlain-miller
เลิกทำ

46

ฉันมักจะทำมันในหนึ่งบรรทัด:

let greater = date1.timeIntervalSince1970 < date2.timeIntervalSince1970

ยังคงสามารถอ่านได้ในifบล็อก


12

ใน Swift3 โครงสร้างDateในFoundationตอนนี้ใช้Comparableโปรโตคอล ดังนั้น Swift2 ก่อนNSDateวิธีการได้รับการแทนที่ด้วยเครื่อง DateSwift3

/**
 `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
}

บันทึก ...

ใน Swift3, Dateเป็นมันหมายความว่ามันเป็นstruct คือมันเป็นvalue typeNSDateclassreference 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`.

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

6

หากคุณต้องการเปรียบเทียบวันที่ที่มีความละเอียดมาก (เช่นวันหรือปีเดียวกัน) บน swift 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
 }
}

สำหรับการเปรียบเทียบปฏิทินอื่นเปลี่ยน. day เป็น;

. ปี. เดือน. วัน. สองนาที. วินาที


5

Swift ใช้การเปรียบเทียบวันที่แล้วเพียงแค่ใช้ date1> date2 และต่อไปเรื่อย ๆ

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

4

ใน Swift 3 Date มีการเปรียบเทียบดังนั้นเราจึงสามารถเปรียบเทียบวันที่เช่น

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

let isGreater = date1 > date2
print(isGreater)

let isEqual = date1 == date2
print(isEqual)

หรืออีกวิธีหนึ่ง

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

วิธีที่ดีกว่าการสร้างextensionในวันที่

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
  }

}

การใช้ let isGreater = date1.isGreater(than: date2)


3

ฟังก์ชั่นนี้ใช้งานได้สำหรับฉันในการเปรียบเทียบว่าหนึ่งวัน (startDate) เกิดขึ้นหลังจากวันที่สิ้นสุดซึ่งทั้งคู่ถูกกำหนดเป็นตัวแปร NSDate:

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

2

การใช้งานใน 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
})

2
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateData: String = dateFormatter.stringFromDate(date1)
let testDate: String = dateFormatter.stringFromDate(date2)
print(dateData == testDate)

1
someArray.sort({($0.dateAdded?.timeIntervalSinceReferenceDate)! < ($1.dateAdded?.timeIntervalSinceReferenceDate)!})

dateAdded เป็นตัวแปร NSDate ในวัตถุของฉัน

class MyClass {
    let dateAdded: NSDate?
}

1

เรามีสถานการณ์ที่จะตรวจสอบเวลาปัจจุบันอยู่ที่ b / w สองครั้ง (สองวัน) ตัวอย่างเช่นฉันต้องการตรวจสอบการโกหกปัจจุบันระหว่างคลินิก (โรงพยาบาล) เวลาเปิดและเวลาปิด

ใช้รหัสง่าย ๆ

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

1

สำหรับ swift 3 คุณสามารถใช้ฟังก์ชันด้านล่างเพื่อเปรียบเทียบระหว่างวันที่สองวัน

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 สามารถเปลี่ยนแปลงได้ตามข้อ จำกัด ที่คุณต้องการใช้การเปรียบเทียบของคุณ


1

เพื่อต่อยอดกับ SashaZ

Swift iOS 8 ขึ้นไปเมื่อคุณต้องการมากกว่าการเปรียบเทียบขนาดใหญ่หรือเล็กกว่าวันที่ ตัวอย่างเช่นมันเป็นวันเดียวกันหรือวันก่อนหน้า ...

หมายเหตุ:อย่าลืมเขตเวลา เขตเวลาของปฏิทินมีค่าเริ่มต้น แต่ถ้าคุณไม่ชอบค่าเริ่มต้นคุณจะต้องตั้งค่าเขตเวลาด้วยตัวเอง หากต้องการทราบว่าเป็นวันใดคุณต้องทราบว่าคุณขอเขตเวลาใด

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

ใช้มันแบบนี้:

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

จากตัวอย่างที่ซับซ้อนมากขึ้น ค้นหาและกรองวันที่ทั้งหมดในอาร์เรย์ซึ่งมาจากวันเดียวกันกับ "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)) }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.