Ollie
Ollie

Reputation: 1946

NSDate crashing on simulators less than 5s on versions iOS 8.4 and 9.3

I'm having a strange bug where my application will crash on all simulators less than the iPhone 5s.

Firstly, I've tried resetting all the simulators and the crash still persists.

Code

extension NSDate {

  func firstDayOfMonth() -> NSDate {
    let cal = NSCalendar.currentCalendar()
    let comp = cal.components([.Year, .Month], fromDate: self)

    // to 12pm
    comp.hour = 12
    comp.minute = 0
    comp.second = 0

    return cal.dateFromComponents(comp)!
  }


  func lastDayOfMonth() -> NSDate {
    let cal = NSCalendar.currentCalendar()
    let comp = NSDateComponents()

    comp.month = 1
    comp.day -= 1

    // to 12pm
    comp.hour = 12
    comp.minute = 0
    comp.second = 0

    return cal.dateByAddingComponents(comp, toDate: self.firstDayOfMonth()!, options: [])!
  }
}

The Error

The final line of code in the second function:
cal.dateByAddingComponents(comp, toDate: self.firstDayOfMonth()!, options: [])! returns 5828963-12-20 00:00:00 +0000 on the devices where the crash occurs.


Reproducing the Error

I'm able to consistently reproduce the issue when running on the iPhone 4s (v8.4, v9.3) and iPhone 5 (v8.4, v9.3) however the error does not occur in the playground or on the iPhone 5s or iPhone 6/6s

Any help would be much appreciated.

Upvotes: 3

Views: 230

Answers (2)

vadian
vadian

Reputation: 285220

Please try this alternative date math

extension NSDate {

  func firstDayOfMonth() -> NSDate {

    let calendar = NSCalendar.currentCalendar()
    var startDate : NSDate?
    calendar.rangeOfUnit(.Month, startDate: &startDate, interval: nil, forDate: self)
    let components = calendar.components([.Year, .Month, .Day], fromDate: startDate!)
    components.hour = 12
    return calendar.dateFromComponents(components)!
  }

  func lastDayOfMonth() -> NSDate {

    let calendar = NSCalendar.currentCalendar()
    let dayRange = calendar.rangeOfUnit(.Day, inUnit: .Month, forDate: self)
    let dayLength = dayRange.length
    let components = calendar.components([.Year, .Month, .Day], fromDate: self)
    components.day = dayLength
    components.hour = 12
    return calendar.dateFromComponents(components)!
  }
}

Swift 3

extension Date {

    func firstDateOfMonth() -> Date {

        let calendar = Calendar.current
        var startDate = Date()
        var interval : TimeInterval = 0
        _ = calendar.dateInterval(of:.month, start: &startDate, interval: &interval, for: self)
        return startDate
    }

    func lastDateOfMonth() -> Date {

        let calendar = Calendar.current
        let dayRange = calendar.range(of:.day, in: .month, for: self)!
        let dayLength = dayRange.upperBound
        var components = calendar.dateComponents([.year, .month, .day], from: self)
        components.day = dayLength
        return calendar.date(from:components)!
    }
}

Setting the hour to 12 can be useful especially in Brasil where one of the daylight saving dates skips 0:00 to 0:59.

Upvotes: 2

Penkey Suresh
Penkey Suresh

Reputation: 5974

This could be happening because of an Integer overflow. iPhone 5s and above use 64-bit processors where as below ones use 32-bit. Do check this apple documentation regarding finding out diffrence between days using dateFromComponents..

From apple documentation...

Do not use this method for comparing second differences because it overflows NSInteger on 32-bit platforms.

Possible solution to avoid the crash

  • Try removing the seconds from your date comparison.

Upvotes: 1

Related Questions