问题描述
我需要在图表的xAxis上显示当月/第一周的一天。谁能帮我这个忙吗? 我如何获得本月所有周的第一天。
解决方法
您可以使用以下组件创建一个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年10月的第一周从9月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个元素。
,您可以获取当前日期的.yearForWeekOfYear,获取该日期的monthOfYear范围,并返回该月同一月的所有日期:
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
} ?? []
}
}
另一种选择是获取该特定日期的月初,该日期之后的enumerateDates与日历的第一个工作日匹配,如果结果日期不在该日期的同一个月,则停止该事件:
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,"Oct 18,"Oct 25,2020 at 12:00 AM"]
let august = DateComponents(calendar: .current,year: 2020,month: 8,day: 10).date!
august.firstWeekdaysInMonth() // ["Aug 2,"Aug 9,"Aug 16,"Aug 23,"Aug 30,2020 at 12:00 AM"]