Problem with adding month value to date in Swift

104 Views Asked by At

I've got a problem. I'm getting start date of current year with function below:

func startOfYear() -> Date {
    var calendar = Calendar(identifier: .iso8601)
    let timezone = TimeZone(secondsFromGMT: 0)!
    calendar.timeZone = timezone
    return calendar.dateComponents([.calendar, .year], from: self).date!
}

My goal is to iterate through this date to extract data for every single month. I use this function to add value to .month to get start date of every month of year:

func getNextMonths(using calendar: Calendar = .iso8601, monthAmount: Int) -> Date {
    calendar.date(byAdding: .month, value: monthAmount, to: self.startOfYear())!
}

When I iterate through this fuction and print dates I receive this:

func getMonth() {
    for number in 0...12 {
        print("month \(number): \(Date().getNextMonths(monthAmount: number))")
    }
}

output:

month 0: 2022-01-01 00:00:00 +0000
month 1: 2022-02-01 00:00:00 +0000
month 2: 2022-03-01 00:00:00 +0000
month 3: 2022-03-31 23:00:00 +0000
month 4: 2022-04-30 23:00:00 +0000
month 5: 2022-05-31 23:00:00 +0000
month 6: 2022-06-30 23:00:00 +0000
month 7: 2022-07-31 23:00:00 +0000
month 8: 2022-08-31 23:00:00 +0000
month 9: 2022-09-30 23:00:00 +0000
month 10: 2022-11-01 00:00:00 +0000
month 11: 2022-12-01 00:00:00 +0000
month 12: 2023-01-01 00:00:00 +0000

As you can see there is a problem starting with 2022-03-31 - it supposed to return 2022-04-01 but I don't really know what I'm doing wrong and why I can't achieve this.

EDIT

I've changed fuction getNextMonths to check if it's daylight saving time and it's working now, thanks to [Joakim Danielson][1] for help. It's silly solution but it works:

func getNextMonths(using calendar: Calendar = .iso8601, monthAmount: Int) -> Date {
    if monthAmount == 0 || monthAmount == 1 || monthAmount == 2 || monthAmount == 10 || monthAmount == 11 || monthAmount == 12 {
        return calendar.date(byAdding: .month, value: monthAmount, to: self.startOfYear())!
    } else {
        var dateComponents = DateComponents()
        dateComponents.month = monthAmount
        dateComponents.hour = 1
        return calendar.date(byAdding: dateComponents, to: self.startOfYear())!
    }
}
1

There are 1 best solutions below

1
Mohammad On

Hey I copied your code as an extension to Date and I got some errors, after some search I finally can run it and it gives me the beginning of each month, here's my changes hope it helps!

extension  Date{
    func startOfYear() -> Date {
        var calendar = Calendar(identifier: .iso8601)
        let timezone = TimeZone(secondsFromGMT: 0)!
    
        calendar.timeZone = timezone
    
        return calendar.dateComponents([.calendar, .year], from: self).date!
    }
    
    func getNextMonths(using calendar: Calendar, monthAmount: Int) -> Date {
        calendar.date(byAdding: .month, value: monthAmount, to: self.startOfYear())!
    }
    
    func getMonth() {
        for number in 0...12 {
            print("month \(number): \(Date().getNextMonths(using: Calendar.current, monthAmount: number))")
        }
    }

}

Then I made a Date object like this

let d = Date()

print(d.getMonth())

Output (In Indian numbers, but it should be the same) enter image description here