Получить первый день всех недель текущего месяца в iOS swift

#ios #swift #charts #nsdateformatter

#iOS #swift #Диаграммы #nsdateformatter

Вопрос:

введите описание изображения здесь

Мне нужно отобразить текущий месяц / первый день недели на оси X графика. Кто-нибудь может мне помочь с этим? Как я могу получить первый день текущего месяца за все недели.

Ответ №1:

Вы можете создать DateComponents с помощью компонентов:

 year: someYear,
month: someMonth,
weekday: someCalendar.firstWeekday,
weekOfMonth: n
  

используйте Calendar.date(from:) , чтобы получить Date соответствующие этим компонентам. Теперь вам просто нужно изменить n значение от 1 до 5 и поместить каждый результат в массив.

 var firstsOfWeek = [Date]()
let year = 2020
let month = 10
let calendar = Calendar.current

for n in 1...5 {
    let dc = DateComponents(
        year: year,
        month: month,
        weekday: calendar.firstWeekday,
        weekOfMonth: n
    )
    firstsOfWeek.append(calendar.date(from: dc)!)
}
  

Однако date(from:) вернет дату, которой нет, someMonth если первая неделя someMonth находится внутри только частично someMonth . Например, (при условии, что неделя начинается в воскресенье) первая неделя октября 2020 года начинается 27 сентября и date(from:) даст вам эту дату, если вы спросите, какой дате соответствует weekOfMonth: 1 .

Если вам не нужна эта дата. просто добавьте флажок, чтобы включать только начало месяца, если это также начало недели, и измените диапазон цикла for на 2...5 :

 let firstDayOfMonth = calendar.date(from: DateComponents(year: year, month: month))!
if calendar.component(.weekday, from: firstDayOfMonth) == calendar.firstWeekday {
    firstsOfWeek.append(firstDayOfMonth)
}
for n in 2...5 {
...
  

Но обратите внимание, что если вы сделаете это, результирующий массив иногда будет содержать 4 элемента, а иногда и 5 элементов.

Ответ №2:

Вы можете получить .yearForWeekOfYear для текущей даты, получить диапазон weekOfYear в месяце для этой даты и вернуть все даты в том же месяце для диапазона:

 extension Date {
    func month(using calendar: Calendar = .current) -> Int {
        calendar.component(.month, from: self)
    }
    func firstWeekdaysInMonth(using calendar: Calendar = .current) -> [Date] {
        var components = calendar.dateComponents([.calendar, .yearForWeekOfYear], from: self)
        return calendar.range(of: .weekOfYear, in: .month, for: self)?.compactMap {
            components.weekOfYear = $0
            return components.date?.month(using: calendar) == month(using: calendar) ? components.date : nil
        } ?? []
    }
}
  

Другой вариант — получить начало месяца для этой конкретной даты, перечислить даты после этой даты, которая соответствует первому дню недели календаря, и остановить, если результирующая дата не совпадает с месяцем этой даты:

 extension Date {
    func firstWeekdaysInMonth(using calendar: Calendar = .current) -> [Date] {
        let year = calendar.component(.year, from: self)
        let month = calendar.component(.month, from: self)
        let start = DateComponents(calendar: calendar, year: year, month: month).date!
        let matching = DateComponents(weekday: calendar.firstWeekday)
        var dates: [Date] = []
        calendar.enumerateDates(startingAfter: start, matching: matching, matchingPolicy: .strict) { date, _, stop in
            guard let date = date, calendar.component(.month, from: date) == month else {
                stop = true
                return
            }
            dates.append(date)
        }
        return dates
    }
}
  

 let dates = Date().firstWeekdaysInMonth()  // "Oct 4, 2020 at 12:00 AM", "Oct 11, 2020 at 12:00 AM", "Oct 18, 2020 at 12:00 AM", "Oct 25, 2020 at 12:00 AM"]

let august = DateComponents(calendar: .current, year: 2020, month: 8, day: 10).date!
august.firstWeekdaysInMonth()  // ["Aug 2, 2020 at 12:00 AM", "Aug 9, 2020 at 12:00 AM", "Aug 16, 2020 at 12:00 AM", "Aug 23, 2020 at 12:00 AM", "Aug 30, 2020 at 12:00 AM"]