按月/日对日期数组进行排序的最简洁方法,忽略年份

时间:2021-07-03 00:29:01

标签: swift

到目前为止,我的解决方案是将日期转换为格式化的字符串并对其进行排序。

例如:

extension Date {
    // Helper
    func formatted(_ format: String) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = format
        return dateFormatter.string(from: self)
    }
}

let sortedDates = myDates.sorted { $0.formatted("MM/dd") < $1.formatted("MM/dd") }

在不处理字符串的情况下,有没有更好的方法来实现这一点?

4 个答案:

答案 0 :(得分:1)

您可以创建一个结构体 MonthDay,它具有 month/day 的整数值,并使其符合 Comparable 以便在排序逻辑中使用。< /p>

import Foundation

extension Date {
    struct MonthDay: Comparable {
        let month: Int
        let day: Int
        
        init(date: Date) {
            let comps = Calendar.current.dateComponents([.month,.day], from: date)
            self.month = comps.month ?? 0
            self.day = comps.day ?? 0
        }
        
        static func <(lhs: MonthDay, rhs: MonthDay) -> Bool {
            return (lhs.month < rhs.month || (lhs.month == rhs.month && lhs.day < rhs.day))
        }
    }
}

有了上面的内容,您可以通过读取 month 中的 day/Date 值来轻松排序,如下所示。

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

let date1 = dateFormatter.date(from: "2020-07-30")!
let date2 = dateFormatter.date(from: "2021-07-01")!
let date3 = dateFormatter.date(from: "2019-07-28")!
let date4 = dateFormatter.date(from: "2021-06-30")!
let date5 = dateFormatter.date(from: "2016-10-13")!

let dates = [date1, date2, date3, date4, date5]
print(dates.map { dateFormatter.string(from: $0) })
// ["2020-07-30", "2021-07-01", "2019-07-28", "2021-06-30", "2016-10-13"]


let sorted = dates.sorted(by: { 
    Date.MonthDay(date: $0) < Date.MonthDay(date: $1) 
})
print(sorted.map { dateFormatter.string(from: $0) })
// ["2021-06-30", "2021-07-01", "2019-07-28", "2020-07-30", "2016-10-13"]

答案 1 :(得分:1)

如果有人想尝试,这里有一个适用于 Swift 5.5/Xcode 13 beta 的解决方案。

let monthDay = Date.FormatStyle()
    .day(.twoDigits)
    .month(.twoDigits)
    .locale(Locale(identifier: "en_US_POSIX"))

 let sortedDates = myDates
    .map { ($0.formatted(monthDay), $0) }
    .sorted { $0.0 < $1.0 }
    .map(\.1)

示例

let day = 24.0 * 60.0 * 60.0 
let month = day * 31
let year = day * 365

let myDates: [Date] = [.now,
                        .now.advanced(by: (year + day)),
                        .now.advanced(by: -(year + day)),
                        .now.advanced(by: -3 * day),
                        .now.advanced(by: 3 * day)
]

收益

<块引用>

[2021-06-30 09:57:51 +0000, 2020-07-02 09:57:51 +0000, 2021-07-03 09:57:51 +0000, 2022-07-04 09: 57:51 +0000, 2021-07-06 09:57:51 +0000]

答案 2 :(得分:0)

如果您想避免每次通过排序块时都创建新对象,那么您可以创建一个 Dictionary,将原始 Date 作为 Key,将 Day/Month 组件作为值.然后可以对其进行排序并作为原始日期的 Array 返回。

func sortDatesByDayMonth(_ dates: [Date]) -> [Date] {
    let calendar = Calendar.current
    
    var datesWithDayMonthOnly = [Date : Date]()

    for date in dates {
        var dateComponents = DateComponents()
        dateComponents = calendar.dateComponents([.day, .month], from: date)
        let dayMonthDate = calendar.date(from: dateComponents)
        datesWithDayMonthOnly[date] = dayMonthDate
    }

    return datesWithDayMonthOnly.sorted { $0.1 < $1.1 }.map { $0.key }
}

或者作为 ArrayTuples,这将处理两个日期完全相同的罕见情况:

func sortDatesByDayMonth(_ dates: [Date]) -> [Date] {
    let calendar = Calendar.current
    
    var datesWithDayMonthOnly = [(date: Date, dayMonthDate: Date)]()

    for date in dates {
        var dateComponents = DateComponents()
        dateComponents = calendar.dateComponents([.day, .month], from: date)
        
        if let dayMonthDate = calendar.date(from: dateComponents) {
            datesWithDayMonthOnly.append((date: date, dayMonthDate: dayMonthDate))
        }
    }

    return datesWithDayMonthOnly.sorted { $0.dayMonthDate < $1.dayMonthDate }.map { $0.date }
}

示例:

var dates = [Date]()

for _ in 1...20 {
    dates.append(Date(timeIntervalSince1970: Double.random(in: 0...Date().timeIntervalSince1970)))
}

sortDatesByDayMonth(dates)

示例输出:

[2005-01-08 18:26:45 +0000,
 1994-01-13 15:13:10 +0000,
 1986-01-26 03:48:43 +0000,
 1992-02-15 10:40:06 +0000,
 2005-03-20 12:33:41 +0000,
 1998-04-04 13:23:33 +0000,
 1982-04-25 17:21:55 +0000,
 1976-05-16 20:59:00 +0000,
 1995-05-20 03:53:41 +0000,
 2006-07-23 06:50:19 +0000,
 2017-08-23 08:16:49 +0000,
 1989-08-30 17:47:49 +0000,
 1986-09-07 03:05:49 +0000,
 1990-09-08 16:09:47 +0000,
 2007-10-14 03:46:24 +0000,
 1974-10-16 16:06:53 +0000,
 1977-11-04 14:15:43 +0000,
 1974-11-09 08:55:11 +0000,
 2011-12-02 07:23:57 +0000,
 1983-12-31 00:22:57 +0000]

答案 3 :(得分:-1)

    let date1 = DateComponents(calendar: .current, year: 2022, month: 07, day: 28, hour: 0, minute: 0).date!
    let date2 = Date()
    let date3 = DateComponents(calendar: .current, year: 1997, month: 06, day: 22, hour: 0, minute: 0).date!
    let date4 = DateComponents(calendar: .current, year: 2000, month: 07, day: 02, hour: 0, minute: 0).date!
    let date5 = DateComponents(calendar: .current, year: 1997, month: 07, day: 28, hour: 0, minute: 0).date!
    let date6 = DateComponents(calendar: .current, year: 2050, month: 08, day: 28, hour: 0, minute: 0).date!

    let calendar = Calendar.current
    let components = calendar.dateComponents([.month, .day], from: date1)
    let components2 = calendar.dateComponents([.month, .day], from: date2)
    let components3 = calendar.dateComponents([.month, .day], from: date3)
    let components4 = calendar.dateComponents([.month, .day], from: date4)
    let components5 = calendar.dateComponents([.month, .day], from: date5)
    let components6 = calendar.dateComponents([.month, .day], from: date6)
    
    var arrDate = [components,components2,components3,components4,components5,components6]
    
    arrDate.sort { lhs, rhs in
        if lhs.month! > rhs.month! {
            return true
        }else if lhs.month! < rhs.month!{
            return false
        }else if lhs.month! == rhs.month!{
            if lhs.day! > rhs.day! {
                return true
            }else if lhs.day! < rhs.day! {
                return false
            }else {
                return false
            }
        }
        return true
    }
    
    print(arrDate)

这样检查:)