I am trapped in a Calendar/TimeZone/DateComponents/Date hell and my mind is spinning.
I am creating a diary app and I want it to work worldwide (with a iso8601 calendar).
I am trying to create a calendar view on iOS similar to the macOS calendar so that my user can navigate their diary entries (notice the 7x6 grid for each month):
To get the 1st of the month I can do something like the following:
func firstOfMonth(month: Int, year: Int) -> Date {
let calendar = Calendar(identifier: .iso8601)
var firstOfMonthComponents = DateComponents()
// firstOfMonthComponents.timeZone = TimeZone(identifier: "UTC") // <- fixes daylight savings time
firstOfMonthComponents.calendar = calendar
firstOfMonthComponents.year = year
firstOfMonthComponents.month = month
firstOfMonthComponents.day = 01
return firstOfMonthComponents.date!
}
(1...12).forEach {
print(firstOfMonth(month: $0, year: 2018))
/*
Gives:
2018-01-01 00:00:00 +0000
2018-02-01 00:00:00 +0000
2018-03-01 00:00:00 +0000
2018-03-31 23:00:00 +0000
2018-04-30 23:00:00 +0000
2018-05-31 23:00:00 +0000
2018-06-30 23:00:00 +0000
2018-07-31 23:00:00 +0000
2018-08-31 23:00:00 +0000
2018-09-30 23:00:00 +0000
2018-11-01 00:00:00 +0000
2018-12-01 00:00:00 +0000
*/
}
There's an immediate issue here with daylight savings time. That issue can be "fixed" by uncommenting the commented line and forcing the date to be calculated in UTC. I feel as though by forcing it to UTC the dates become invalid when viewing the calendar view in different time zones.
The real question is though: How do I get the first Monday in the week containing the 1st of the month? For example, how do I get Monday 29th February, or Monday 26th April? (see the macOS screenshot). To get the end of the month, do I just add on 42 days from the start? Or is that naive?
Edit
Thanks to the current answers, but we're still stuck.
The following works, until you take daylight savings time into account:
from Get first Monday in Calendar month


No comments:
Post a Comment