So sánh NSDate bằng Swift


153

Tôi đang làm việc trên một ứng dụng yêu cầu kiểm tra ngày đáo hạn cho bài tập về nhà. Tôi muốn biết liệu ngày đáo hạn có trong tuần tới không, và nếu đó là ngày thực hiện một hành động.
Hầu hết các tài liệu tôi có thể tìm thấy là trong Objective-C và tôi không thể tìm ra cách thực hiện nó trong Swift. Cảm ơn đã giúp đỡ!!


2
swift không có lớp ngày bạn sử dụng lớp Objective C NSDate - vì vậy bạn đã tìm thấy tài liệu chính xác
mmmmmm

Có thể trùng lặp so sánh NSDates mà không có thành phần thời gian . Có rất nhiều câu trả lời rất hay.
jww

Câu trả lời liên quan: stackoverflow.com/questions/29652771/ Lời
jkdev

2
Swift 3 không có Datelớp. Nó được bắc cầu đến NSDate, nhưng nó được gọi Date.
BallpointBen

Câu trả lời:


188

Tôi thích sử dụng các phần mở rộng để làm cho mã dễ đọc hơn. Dưới đây là một vài tiện ích mở rộng NSDate có thể giúp làm sạch mã của bạn và làm cho nó dễ hiểu. Tôi đặt cái này trong một tệp 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
    }
}

Bây giờ nếu bạn có thể làm một cái gì đó như thế này:

//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
Bạn nên đơn giản hóa mã của bạn. return self.compare(dateToCompare) == NSComparisonResult.OrderedDescending
Olav Gausaker

5
isEqualToDate cũng được cung cấp bởi Apple. Đó là tuyên bố mâu thuẫn với tuyên bố của Apple.
Shamas S - Tái lập Monica

4
Không phải ngày nào cũng có 24 giờ
Leo Dabus

9
Câu trả lời này là khủng khiếp và không bao giờ nên được chấp nhận. Đừng bao giờ thêm khoảng thời gian vào ngày được tạo bởi bạn. Đó chính xác là lý do NSDateComponentstồn tại. Có rất nhiều trường hợp cạnh không được xử lý đúng cách và thật vô nghĩa khi không thêm sự phù hợp Comparablevào NSDate. Tôi khuyên bạn nên sử dụng giải pháp của John .
fpg1503 17/2/2016

3
Một giải pháp tốt hơn là làm cho NSDate tương đương, có thể so sánh, sau đó bạn có thể làm một cách đơn giảndate1 < date2
aryaxt 11/03/2016

209

Nếu bạn muốn hỗ trợ ==, <, >, <=, hoặc >=cho NSDates, bạn chỉ cần phải khai báo này ở đâu đó:

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 Comparablelà hậu duệ của Equatablegiao thức, do đó bạn không cần phải khai báo sự phù hợp với cả hai.
John Estropia

2
Chỉ tò mò tại sao nó không được xây dựng theo mặc định?!
dVaffection

3
@dVaffection Trong Objective-C (nơi NSDate và bạn bè được khai báo), nếu bạn so sánh sử dụng ==, <, >, vv, bạn sẽ nhận được một kết quả của việc so sánh địa chỉ của họ trong bộ nhớ, không phải là so sánh giữa giá trị thực tế của họ. Trong Swift, chúng vẫn được coi là tài liệu tham khảo nên tôi nghĩ rằng sự lựa chọn là (1) giữ các so sánh bằng con trỏ khi chúng ở ObjC hoặc (2) loại bỏ sự nhầm lẫn bằng cách không cung cấp triển khai để so sánh.
John Estropia

2
Một lợi ích bổ sung của phương pháp này là Array.maxElement(), vv sau đó tự động có sẵn các mảng NSDates.
pr1001

1
@MarcioCruz Đó chỉ là một yêu cầu của Swift mà tất cả các cài đặt của nhà điều hành phải ở phạm vi toàn cầu. Xem cuộc thảo luận tại đây: stackoverflow.com/questions353246003/iêu
John Estropia

54

Đây là cách bạn so sánh hai NSDate trong Swift, tôi vừa thử nghiệm nó trong sân chơi của 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");
}

Vì vậy, để kiểm tra xem một ngày dueDatetrong vòng một tuần kể từ bây giờ:

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
đã ra lệnh Giảm dần có nghĩa là ngày1> ngày2?
Henry oscannlain-miller

1
Vâng, @ Henryoscannlain-miller.
Hoàn tác

46

Tôi luôn luôn làm điều đó trong một dòng:

let greater = date1.timeIntervalSince1970 < date2.timeIntervalSince1970

Vẫn có thể đọc được trong ifkhối


12

Trong Swift3, Datestruct trong Foundationhiện thực hiện Comparablegiao thức. Vì vậy, các NSDatecách tiếp cận Swift2 trước đây được áp dụng bởi 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
}

Ghi chú ...

Trong Swift3, Datestruct, nó có nghĩa là nó là value type. NSDateclass, nó là 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`.

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

Nếu bạn muốn so sánh ngày với độ chi tiết (chỉ cùng ngày hoặc năm, v.v.) trên 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
 }
}

Đối với các so sánh lịch khác thay đổi .day thành;

.year .month .day .hour .minute .second


5

Swift đã thực hiện So sánh ngày chỉ cần sử dụng date1> date2, v.v.

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

trong Swift 3, Date là So sánh để chúng ta có thể so sánh trực tiếp các ngày như

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

let isGreater = date1 > date2
print(isGreater)

let isEqual = date1 == date2
print(isEqual)

Hay cách khác

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

cách tốt hơn để tạo extensionvào ngày

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
  }

}

sử dụng let isGreater = date1.isGreater(than: date2)


3

Hàm này hoạt động với tôi để so sánh xem một ngày (startDate) có sau endDate hay không khi cả hai được định nghĩa là biến NSDate:

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

2

thực hiện trong 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 là một biến NSDate trong đối tượng của tôi

class MyClass {
    let dateAdded: NSDate?
}

1

Chúng tôi có kịch bản để kiểm tra thời gian hiện tại nằm b / w hai lần (hai ngày). Ví dụ, tôi muốn kiểm tra thời gian nói dối hiện tại giữa thời gian mở cửa của bệnh viện (Bệnh viện) và thời gian đóng cửa.

Sử dụng Mã đơn giản.

      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

Đối với swift 3, bạn có thể sử dụng chức năng dưới đây để so sánh giữa hai ngày.

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 có thể được thay đổi theo các ràng buộc mà bạn muốn áp dụng so sánh của mình.


1

Để mở rộng trên SashaZ

Swift iOS 8 trở lên Khi bạn cần nhiều hơn so với việc so sánh ngày lớn hơn hoặc đơn giản hơn. Ví dụ, đó là cùng ngày hoặc ngày hôm trước, ...

Lưu ý: Không bao giờ quên múi giờ. Múi giờ lịch có mặc định, nhưng nếu bạn không thích mặc định, bạn phải tự đặt múi giờ. Để biết đó là ngày nào, bạn cần biết múi giờ bạn đang hỏi.

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

Sử dụng nó như thế này:

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

Của một ví dụ phức tạp hơn. Tìm và lọc tất cả các ngày trong một mảng, từ cùng một ngày với "find ThisDay":

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)) }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.