How to make an array of the current week dates Swift

Viewed 921

I am working on a project where I need the dates of the current week. I am currently using this function to get the date of the present day.

func getDay() -> String {
    let date = Date()
    let formatter = DateFormatter()
    formatter.dateFormat = "dd.MM.yyyy"
    let result = formatter.string(from: date)
    return result
}

It works fine for getting me the one date, but I don't know how to get all 7 dates of the current week. If anyone can help it would be greatly appreciated.

1 Answers

You can get today's yearForWeekOfYear and weekOfYear calendar components and construct a new date from it. It will give you the first day of the week. If you want your week to start from Monday you need to use iso8601 calendar, if you would like to have your week to start on Sunday you can use Gregorian calendar. To avoid some extreme cases you should do all your calendrical calculations using noon time. Not all dates starts at midnight.

let dateComponents = Calendar(identifier: .gregorian).dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date())
let startOfWeek = Calendar(identifier: .gregorian).date(from: dateComponents)!
let startOfWeekNoon = Calendar(identifier: .gregorian).date(bySettingHour: 12, minute: 0, second: 0, of: startOfWeek)!
let weekDays = (0...6).map { Calendar(identifier: .gregorian).date(byAdding: .day, value: $0, to: startOfWeekNoon)! }
weekDays  // ["Jun 7, 2020 at 12:00 PM", "Jun 8, 2020 at 12:00 PM", "Jun 9, 2020 at 12:00 PM", "Jun 10, 2020 at 12:00 PM", "Jun 11, 2020 at 12:00 PM", "Jun 12, 2020 at 12:00 PM", "Jun 13, 2020 at 12:00 PM"]

Expanding on that you can extend Date and create some helpers:

extension Calendar {
    static let iso8601 = Calendar(identifier: .iso8601)
    static let gregorian = Calendar(identifier: .gregorian)
}

extension Date {
    func byAdding(component: Calendar.Component, value: Int, wrappingComponents: Bool = false, using calendar: Calendar = .current) -> Date? {
        calendar.date(byAdding: component, value: value, to: self, wrappingComponents: wrappingComponents)
    }
    func dateComponents(_ components: Set<Calendar.Component>, using calendar: Calendar = .current) -> DateComponents {
        calendar.dateComponents(components, from: self)
    }
    func startOfWeek(using calendar: Calendar = .current) -> Date {
        calendar.date(from: dateComponents([.yearForWeekOfYear, .weekOfYear], using: calendar))!
    }
    var noon: Date {
        Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
    }
    func daysOfWeek(using calendar: Calendar = .current) -> [Date] {
        let startOfWeek = self.startOfWeek(using: calendar).noon
        return (0...6).map { startOfWeek.byAdding(component: .day, value: $0, using: calendar)! }
    }
}

usage:

// this will give you all days of the current week starting monday
Date().daysOfWeek(using: .iso8601)  // ["Jun 8, 2020 at 12:00 PM", "Jun 9, 2020 at 12:00 PM", "Jun 10, 2020 at 12:00 PM", "Jun 11, 2020 at 12:00 PM", "Jun 12, 2020 at 12:00 PM", "Jun 13, 2020 at 12:00 PM", "Jun 14, 2020 at 12:00 PM"]
// this will give you all days of the current week starting sunday
Date().daysOfWeek(using: .gregorian) // ["Jun 7, 2020 at 12:00 PM", "Jun 8, 2020 at 12:00 PM", "Jun 9, 2020 at 12:00 PM", "Jun 10, 2020 at 12:00 PM", "Jun 11, 2020 at 12:00 PM", "Jun 12, 2020 at 12:00 PM", "Jun 13, 2020 at 12:00 PM"]

To convert your date to a fixed date format you can create a custom date formatter extending Formatter and Date:

extension Formatter {
    static let ddMMyyyy: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.calendar = Calendar(identifier: .iso8601)
        dateFormatter.locale = .init(identifier: "en_US_POSIX")
        dateFormatter.dateFormat = "dd.MM.yyyy"
        return dateFormatter
    }()
}

extension Date {
    var ddMMyyyy: String { Formatter.ddMMyyyy.string(from: self) }
}

Now you can simply map your dates using the KeyPath:

Date().daysOfWeek(using: .gregorian).map(\.ddMMyyyy) // ["07.06.2020", "08.06.2020", "09.06.2020", "10.06.2020", "11.06.2020", "12.06.2020", "13.06.2020"]
Related