42

I am working on data calendar for every current month and I should show 3 type of calculation for ( yesterday - today - tomorrow)

I am getting crash because of (index out of bound) for special case like if today date ( 31 May 2017 ) and I have array of May month if I try to continue my app and start calculation tomorrow I will have Error (because I should know its new month tomorrow)

This is my code

class ViewController: UIViewController {
    var dateComponents: DateComponents!
    var TimeToday :[String] = []
    var TimeTomorrow :[String] = []
    var TimeYesterday :[String] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        let dateDay = Date()
        let calendar = Calendar(identifier: .gregorian)
        dateComponents = calendar.dateComponents([.day, .month, .year], from: dateDay)
        done()
    }
    func done()  {
        //------ for tomorrow ------
        // month end day 31
        if (dateComponents.day! == 30){
            if(dateComponents.month! == 1 || dateComponents.month! == 4 || dateComponents.month! == 6 || dateComponents.month! == 7 || dateComponents.month! == 9 || dateComponents.month! == 11 ){
                TimeTomorrow.append("\(dateComponents.month!+1)")
            }
        // month end day 31
        }else if (dateComponents.day! == 31){
            if(dateComponents.month! == 3 || dateComponents.month! == 5 || dateComponents.month! == 8 ){
                TimeTomorrow.append("\(dateComponents.month!+1)")
            }else if(dateComponents.month! == 12){
                TimeTomorrow.append("\(dateComponents.year!+1)")
            }
         // month end day 29
        // special case for leap year i donot know how find it
        //****************************************************
            else if (dateComponents.day! == 29){
                if(dateComponents.month! == 2 || dateComponents.month! == 10  ){
                    TimeTomorrow.append("\(dateComponents.month!+1)")
                }
            }
        //------ for yesterday  ------
            if (dateComponents.month! == 12 || dateComponents.month! == 10 || dateComponents.month! == 8 || dateComponents.month! == 7 || dateComponents.month! == 5 || dateComponents.month! == 2){
                var day = dateComponents.date! - 1
                //fatal error: unexpectedly found nil while unwrapping an Optional value
                TimeYesterday.append("\(day)")
                TimeYesterday.append("30 - \(dateComponents.month! - 1)")
            }else {
                //////
            }
        }
    }
}
Pooja Gupta
  • 785
  • 10
  • 22
joshua
  • 947
  • 2
  • 8
  • 14

2 Answers2

182

You should use Calendar method date(byAdding component:) to do your calendrical calculations using noon time. Doing so you don't need to worry about those special cases:

Swift 3 or Later

extension Date {
    static var yesterday: Date { return Date().dayBefore }
    static var tomorrow:  Date { return Date().dayAfter }
    var dayBefore: Date {
        return Calendar.current.date(byAdding: .day, value: -1, to: noon)!
    }
    var dayAfter: Date {
        return Calendar.current.date(byAdding: .day, value: 1, to: noon)!
    }
    var noon: Date {
        return Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
    }
    var month: Int {
        return Calendar.current.component(.month,  from: self)
    }
    var isLastDayOfMonth: Bool {
        return dayAfter.month != month
    }
}

Date.yesterday    // "Oct 28, 2018 at 12:00 PM"
Date()            // "Oct 29, 2018 at 11:01 AM"
Date.tomorrow     // "Oct 30, 2018 at 12:00 PM"

Date.tomorrow.month   // 10
Date().isLastDayOfMonth  // false
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • Date().yesterday.month //Error how can i print month number for next month – joshua May 16 '17 at 20:07
  • Where is month coming from? – Leo Dabus May 16 '17 at 20:08
  • You can extend Date also to get the month component from any date but thats a different question – Leo Dabus May 16 '17 at 20:11
  • @A.Ali check my edit – Leo Dabus May 16 '17 at 20:12
  • yes different question ( i want to know next day is it new month to solve my problem programming ) – joshua May 16 '17 at 20:17
  • 4
    This is a great answer. Although it needs an adjust. A context of "today" or "tomorrow" is always present. So either: 1.Change the "today" and "tomorrow" variables to static 2.Change the name of the variable to something like "dayAfter" and "dayBefore" 3. Both. Keep tomorrow and today, make them static and add "dayAfter" and "dayBefore" as instance variables. I think this makes the things a bit more clear. – RawKnee Oct 29 '18 at 13:50
  • @RoniLeshes thanks. I do agree naming was kind of ambiguous. Note that the last edit to this answer was almost exactly 1 year ago. It was off just by about 1 hour. – Leo Dabus Oct 29 '18 at 14:03
  • 1
    @LeoDabus Nice lol – RawKnee Oct 31 '18 at 14:22
  • I'd argue, that `dayAfter`, `dayBefore` should be adding to `self`, not to `noon`, as I would expect `aDate.dayAfter` to return a date representing a day later than `aDate`, with the same time. also getting noon from there is simple enough: `aDate.dayAfter.noon` – vikingosegundo Apr 12 '20 at 17:48
  • @vikingosegundo this is intentional. What time would you expect when adding a day to midnight before a daylight savings transition? – Leo Dabus Apr 12 '20 at 18:03
  • I guessed it was the Brazil problem. The naming of your variables should reflect the behaviour, though. – vikingosegundo Apr 12 '20 at 18:13
  • @vikingosegundo No. This is more complex than you think. Brazil used to have daylight savings but that changed last year. BTW you should first set your date to noon then you can add a day to it. – Leo Dabus Apr 12 '20 at 18:22
  • Thanks for letting me now what I think. – vikingosegundo Apr 12 '20 at 18:24
0

I don't know if this helps you or not, but I would recommend not doing the math on NSDateComponents but rather on NSDate. Take a look at https://github.com/malcommac/SwiftDate a cocoapod for how to do things like call tomorrow on an NSDate. The cool thing about that pod is it uses Regions which helps for internationalization where the next day might start at sunset instead of mid nite.

Vader
  • 77
  • 1
  • 7