NSCalendar.date(from:) return wrong date

Hello everyone,

I am facing a strange behavior with NSCalendar.date(from:)


If i use the snippet below


let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
var startComponents = calendar.components([.weekday, .weekOfYear, .year, .hour, .minute, .second, .timeZone], from: currentDate)
startComponents.weekday = 2
startComponents.weekOfYear = 1

let start = calendar.date(from: startComponents)!


if currentDate is January 3rd 2018, I'm thought that start will be January 1st 2018. (weekday is supposed to be monday, the year component is set to 2018, and the WeekOfYear to 1) but start is 31 december 2018.


Monday 31 december 2018 is indeed part of W1 but for the 2019 year (not 2018)

Can someone confirm this is a bug ?


The behaviors is tested on iphone and ipad.

(of course no problem if weekOfYear is 2; start is correctly set to Januray 08th 2018

Hi,


I'm not a date/time specialist so I'm unsure if this is a correct behavior (semantically speaking, as the week starts normally on Sunday, thus the 1st week of January can be considered as starting from January 7th, but it doesn't make sense here as it is set to 2 anyway).


Calendar (and NSCalendar) have been really buggy, and they're in a category of this forum where no one cares and there seem to be no admins/devs active here anyway.

Also, technically this isn't "Calendar Events", but the Foundation framework itself.

I suggest filling a bug report, or maybe track down speakers on Calendar during the WWDC and trying DM them on SNS ...


Now, just a small suggestion (that doesn't solve your problem but can save you some headaches in the future), you should pretty much always (or as much at possible) add the .calendar to your date components. The calendar outside of these components can be buggy (or just wrong, if, for example you make a Gregorian calendar but some of your users have set their device to anything else like Buddhist, Japanese, Islamic, Hebrew, etc)

You can check something in your code, print out:

startComponents.date

You'll see it's nil.

Or try:

startComponents.isValidDate

It returns false.


Now add .calendar in it like:

var startComponents = calendar.components([.calendar, .weekday, .weekOfYear, .year, .hour, .minute, .second, .timeZone], from: currentDate)

Try the print out above, and you'll get a valid date.


Good luck.


---


Edit:

Definetly a bug, there is not even need to set the week's numbers for it to happen. I tried this and here are the results:

let calendar            = Calendar(identifier: .gregorian)
let formatter           = DateFormatter()
formatter.calendar      = calendar
formatter.dateFormat    = "yyyy/MM/dd"
let date                = formatter.date(from: "2018/01/01")!


let simpleComs          = Calendar.current.dateComponents([.calendar, .year], from: date)
let compsWeekday        = Calendar.current.dateComponents([.calendar, .year, .weekday], from: date)
let compsWeekYear       = Calendar.current.dateComponents([.calendar, .year, .weekOfYear], from: date)
let complexComps        = Calendar.current.dateComponents([.calendar, .year, .weekOfYear, .weekday], from: date)

simpleComs.date         // "Jan 1, 2018 00:00 AM"
compsWeekday.date       // "Jan 1, 2018 00:00 AM"
compsWeekYear.date      // "Jan 1, 2018 00:00 AM"
complexComps.date       // "Dec 31, 2018 00:00 AM"
NSCalendar.date(from:) return wrong date
 
 
Q