Group Group Group Group Group Group Group Group Group

Chapter 12 Challenge 2

Challenge 2: A more advanced advance()
Here is a naïve way of writing advance() for the SimpleDate structure you saw earlier in the chapter:

   let months = ["January", "February", "March",
             "April", "May", "June",
             "July", "August", "September",
             "October", "November", "December"]

struct SimpleDate {
 var month: String
 var day: Int

 mutating func advance() {
   day += 1
 }
}

var date = SimpleDate(month: "December", day: 31)
date.advance()
date.month // December; should be January!
date.day // 32; should be 1!

What happens when the function should go from the end of one month to the start of the next?
Rewrite advance() to account for advancing from December 31st to January 1st.

let months = ["January", "February", "March",
              "April", "May", "June",
              "July", "August", "September",
              "October", "November", "December"]

struct SimpleDate {
    var month: String
    var day: Int {
        didSet {
            switch month {
            case "January":
                if day > 31 {
                    month = "February"
                    day = 1
                }
                
            case "February":
                if day > 28{ // dont have year to calculate leap
                    month = "March"
                    day = 1
                }
                
            case "March":
                if day > 31{
                    month = "April"
                    day = 1
                }
                
            case "April":
                if day > 30{
                    month = "May"
                    day = 1
                }
                
            case "May":
                if day > 31{
                    month = "June"
                    day = 1
                }
                
            case "June":
                if day > 30{
                    month = "July"
                    day = 1
                }
                
            case "July":
                if day > 31{
                    month = "August"
                    day = 1
                }
                
            case "August":
                if day > 31{
                    month = "September"
                    day = 1
                    
                }
                
            case "September":
                if day > 30{
                    month = "October"
                    day = 1
                }
                
            case "October":
                if day > 31{
                    month = "November"
                    day = 1
                }
                
            case "November":
                if day > 30{
                    month = "December"
                    day = 1
                }
                
            case "December":
                if day > 31{
                    month = "January"
                    day = 1
                }
            default:
                return
            }
        }
    }
    
    mutating func advance() {
        day += 1
    }
    
}

Even though problem is solved but I don’t like the way I solved it. Is there way to condense the code some way ?

thanks

Thanks for sharing.

Let me just start off which is hopefully the obvious, you should never use a hand rolled date class in production code unless you “know what you are doing.” If you think you do, you probably don’t. I don’t anyway. See https://yourcalendricalfallacyis.com

If you are using dates and times a lot in your project you might want to check out: https://github.com/davedelong/time

If you just want to use Foundation I would do it like this:

import Foundation
let someDate = Date()
let updated = Calendar(identifier: .gregorian).date(byAdding: DateComponents(day: 1), to: someDate)

Now, back to your question,

You might make your month array something like this:

[("January", 31, "February"), ("February", 28, "March"), 
  ("March", 31, "April"), ... ]

Then you could mechanistically use months[index].0 for the current month, months[index].1 for how many days, and months[index].2. The idea is to separate the code and the data. It obviously doesn’t work for leap years in this case. There are more advanced techniques you could use to get around that but then you might want to go back to using Date! :smile: