Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calendar.date(bySetting: .day, value: 1, of: Date()) wrongly always adding one month

Tags:

swift

calendar

I want to get two dates, the first and last day of current month. Pretty simple. But date(bySetting: Calendar.Component, value: Int, of: Date) are not working properly.

Look this piece of code:

When Date() prints 2019-04-18 14:11:36 UTC

let calendar = Calendar.current

let firstDayDate = calendar.date(bySetting: .day, value: 1, to: Date())! //2019-05-01 03:00:00 UTC  

let firsDayNextMonth = calendar.date(byAdding: .month, value: 1, to: firstDayDate)! //2019-06-01 03:00:00 UTC   
let lastDayMonthDate = calendar.date(bySetting: .day, value: -1, to: firsDayNextMonth)! //2019-05-31 03:00:00 UTC   

Look at firstDayDate value, day value are setted to 1, but get added 1 to month value.

Please tell me if i forgot something, but for me it looks like a bug

Obs: I now i can do that using DateComponent, but if it's a bug, i want to file a bug to apple.

Edit1: I'm not asking how to get the first and last day of current month. I know how to do that using other methods, but how i explain ahead, i think there's a bug in date(byAdding: Calendar.Component, value: Int, to: Date) method or if i'm not using that properly.

like image 956
Romulo BM Avatar asked Apr 18 '19 14:04

Romulo BM


1 Answers

Well, since i got that this issue it's not necessarily a real bug on method, but it's the way they are setting the component, searching the first forward, and not really setting, on my perception the method name, description and documentation don't reflect the real feature of the method:

They use a example:

So for the “set to Thursday” example, find the Thursday in the Week in which the given date resides (which could be a forwards or backwards move, and not necessarily the nearest Thursday).

But they recommend to use other method to get more control of the behavior:

For more control over the exact behavior, use nextDate(after:matching:matchingPolicy:behavior:direction:).

So, here is the implementation using this recommended method:

let componentDay = DateComponents(day: 1)
let calendar = Calendar.current

let firstDayDate = calendar.nextDate(after: Date(), matching: componentDay, matchingPolicy: .previousTimePreservingSmallerComponents, direction: .backward)!


let firsDayNextMonth = calendar.date(byAdding: .month, value: 1, to: firstDayDate)!
let lastDayMonthDate = calendar.date(byAdding: .day, value: -1, to: firsDayNextMonth)!
like image 99
Romulo BM Avatar answered Oct 23 '22 20:10

Romulo BM