Vincenzo
Vincenzo

Reputation: 6358

date components are not matching with expected when populating tableview Swift 4

I'm struggling to understand why when I read from append dates .dayand .weekdayare not matching expected ones. In one function dates()I get actual date, get first day of the month, get a days range for month, and in a loop I append all the dates for that month to datesArray. at print the array is correct, starts at date 1 and ends at date 28 ( current month ). Then in cellForRowAt in CalendarTableViewController I assign the date to the row. Get components from the date. Then I compose cellLabel.text with the components.day+ dayNamesArray[components.weekday]. Results are wrong: the cells are off by one day starting at day 2(instead of 1) and ending at day 1(instead of 28), as day name is wrong. Where to check for what's offsetting the results? Many thanks as usual.

Here are the two functions:

func dates() {
        datesArray.removeAll()

        // Set calendar and date
        let calendar = Calendar.current
        let date = Date()

        // Get range of days in month
        let range = calendar.range(of: .day, in: .month, for: date)! // Range(1..<32)

        // Get first day of month
        var firstDayComponents = calendar.dateComponents([.year, .month, .day, .weekday], from: date)
        self.displayedMonth = firstDayComponents.month!
        self.monthCounter = self.displayedMonth - 1
        firstDayComponents.day = range.lowerBound
        let firstDay = calendar.date(from: firstDayComponents)!
        var dayToAppend: Date = calendar.date(byAdding: DateComponents(day: 1), to: firstDay)!
        for date in 1...range.count {

            datesArray.append(dayToAppend)
            dayToAppend = calendar.date(byAdding: DateComponents(day: 1), to: dayToAppend)!
        }

        self.actualMonthLabel.text = self.monthsArray[self.monthCounter]
        print("dateArray is: \(datesArray)") // array is correct

    }

and in TableView :

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "calendarCell", for: indexPath) as!CalendarTableViewCell

        // Configure the cell...

        let date = datesArray[indexPath.row]
        print(date)

        let calendar = Calendar.current
        let components = calendar.dateComponents([.year, .month, .day, .weekday], from: date)
        print("month is: \(String(describing: components.month))")     // correct
        print("day is: \(String(describing: components.day))")         // +1
        print("weekdayIs: \(String(describing: components.weekday))")  // +1
        cell.dayLabel.text = "\(String(describing: components.day!))" + " " + "\(dayNamesArray[components.weekday! - 1])"
        if indexPath.row == self.actualDay - 1 && self.actualMonth == self.displayedMonth {
            cell.dayLabel.backgroundColor = UIColor.red.withAlphaComponent(0.3)
        }

        return cell
    }

Upvotes: 0

Views: 275

Answers (2)

kchopda
kchopda

Reputation: 342

Try to set calendar timezone as UTC and try same. Hope it will work for you.

Upvotes: 0

JanMensch
JanMensch

Reputation: 2435

Look closely at the marked lines your code:

let firstDay = calendar.date(from: firstDayComponents)!
var dayToAppend: Date = calendar.date(byAdding: DateComponents(day: 1), to: firstDay)! // <<--!!!
for date in 1...range.count {
    datesArray.append(dayToAppend) // <--!!!
    dayToAppend = calendar.date(byAdding: DateComponents(day: 1), to: dayToAppend)!
}

You first get the firstDay of the month. Then you add 1 day (so dayToAppend is the 2nd of the month) and THEN you add dayToAppend to your array. So your array starts with the second day of the month. Not with the first. So the solution would be:

let firstDay = calendar.date(from: firstDayComponents)!
var dayToAppend: Date = firstDay // <-- only line changed
for date in 1...range.count {
    datesArray.append(dayToAppend)
    dayToAppend = calendar.date(byAdding: DateComponents(day: 1), to: dayToAppend)!
}

The reason why you thought that everyting was good: you probably didn't take into account time zones. For example when I print out the date object for 1st February it looks like this: 2019-01-31 23:00:00 +0000. I live in GMT+1. The Date object says 23:00 GMT. This means it's 24:00 / 00:00 GMT+1. Which is the next day.

Always read printed Date objects carefully. :)

Upvotes: 0

Related Questions