I'm using a FSCalendar to display events on dates. I'm in Spain (GMT+1 timezone) and I want to show 5 events that will happen in SPAIN, so I will present them to you first in GMT+1 timezone:
march 1, 00:00 - day 1a
march 1, 11:16 - day 1b
march 1, 19:48 - day 1c
march 2, 00:00 - day 2a
march 3, 00:00 - day 3a
These events stored in UTC in a database, so they are stored with GMT+0, so one hour less in all of them. They are stored as this:
february 28, 23:00 - day 1a
march 1, 10:16 - day 1b
march 1, 18:48 - day 1c
march 1, 23:00 - day 2a
march 2, 23:00 - day 3a
OK, now, I need that when the FSCalendar is displayed, the dates must be displayed not in UTC, but in the device timezone, GMT+1, so the dates must be the first I wrote, and not the second. But when I open the FScalendar, all is wrong.
If I click in march 1, the selected date label prints february 28, and the list of events prints this:
february 28, 23:00 - day 1a
If I click on march 2, the selected date label prints march 1, and the list of events prints this:
march 1, 10:16 - day 1b
march 1, 10:48 - day 1c
march 1, 23:00 - day 2a
If I click in march 3, the selected date label prints march 2, and the list of events prints this:
march 2, 23:00 - day 3a
I know how to solve the selected date label issue, I just need to transform calendarView.selectedDate
into local timezone before displaying it in the label, but I don't know how to solve the other issues of the dates being displayed in wrong days and with UTC timezone instead of local GMT+1 timezone. I searched how to deal with timezones and FSCalendar and supposedly it's automatic and I don't have to do anything. So I don't know how to solve this. These are the important parts of my code:
Setting up the calendar
calendarView = FSCalendar()
calendarView.dataSource = self
calendarView.delegate = self
calendarView.select(Date())
Checking which dates of the calendar have events to mark them with events on FSCalendar
for index in 0..<collection.count {
if let date = collection.date(field: dateField)?.dateAt(.startOfDay), datesWithEvents[date] == nil {
datesWithEvents[date] = events(for: date)
}
}
Getting all the events for a date
private func events(for date: Date) -> [Int] {
var events: [Int] = []
for index in 0..<collection.count {
if let rowDate = collection.date(field: dateField), date.compare(.isSameDay(rowDate)) {
events.append(index)
}
}
return events
}
Getting dates from my database (collection)
func date(field: String) -> Date? {
if let item = currentRow, fieldTypes[field] == .date {
if let timeInterval = item[columnIndex] as? Int64 {
return Date(timeIntervalSince1970: Double(timeInterval))
}
}
return nil
}
Well, finally solved it after transforming to localDate() all the dates of the database before adding them to the FSCalendar, and also, transforming to localDate() every date returned by the FSCalendar delegates/listeners before using them to display events of each day etc... Then, the events are correctly placed in their days.
I used this extension to transform dates into local timezone dates:
public extension Date {
func localDate() -> Date {
let timeZoneOffset = Double(TimeZone.current.secondsFromGMT(for: self))
guard let localDate = Calendar.current.date(byAdding: .second, value: Int(timeZoneOffset), to: self) else {return Date()}
return localDate
}
}