## Dates Are Hard 🗓️

 Oct '23 So I've spent the last three or four days using most of my free time to try and find an answer to this dilema I'm having. Simply put, Dates are hard. I've looked over a lot of Hudson's documentation on dates, and I've referenced Apples documentation as well. I've looked at various YouTube channels, and I've scoured Stack for help. I need to compare two dates based on a bool, with complexity. If the user is over a certian age, then the length of time between the users input date and the constant date is 24 months. If the user is under a certian age, the constant is 60 months. I need to record the exact day of the users input. This could be the fifth of the month, or the tenth, or the twenty-first. The constant date must always end at the end of the calendar month 24 or 60 months following the users input date. So: The user's certificate was issues on November 1st, 2023. The expiration of the date, if the bool is false, is November 30th, 2025 (the last calendar day of the month). In similar fashion, the bool is a variable based on the users birthdate. I'm comfortable comparing specific constant dates and variables, but I can't quite figure out how to ensure that the specific constant I'm asking for is always the last day of the month two or five years following the users input. Basically, how do I always ensure that shows the input month, at the last day of that month? Anybody have any ideas? I hate dates, and am struggling to learn this part specifically. Thanks, Andy 3 Oct '23 ``````func addTwentyFourMonths(to date: Date) -> Date? { let calendar = Calendar.current return calendar.date(byAdding: .month, value: 24, to: date) } func lastSecondOfTheMonth(from date: Date) -> Date? { var components = DateComponents() let calendar = Calendar.current // Extract the year and month from the given date guard let year = calendar.dateComponents([.year], from: date).year, let month = calendar.dateComponents([.month], from: date).month else { return nil } // Set the components to the first day of the next month components.year = year components.month = month + 1 components.day = 1 components.second = -1 // Get the date that's one second before the first second of the next month return calendar.date(from: components) }`````` 4 Oct '23 Hi `@CodingPilot`. Yes dates are hard!!! Make a new swift file (I called mine `Date-Extension.swift`) then add this ( I have put some comments so you can see what I done) ``````import Foundation extension Date { /// Calculates a date from a set date plus a number of month that are set by a set age. /// - Parameters: /// - DoB: Date of Birth. /// - criteriaAge: Number of years that need to have 60 months to 24 months (default to 18). /// - Returns: A end of the subscription month from a set date of 24 or 60 depending on criteria age. func subscriptionDate(DoB: Date, criteriaAge: Int = 18) -> Date { // Gets current calendar to be able to calculates dates let calendar = Calendar.current // initial date var date: Date? = .now // calculates a date from date of birth plus the criteria age (default of 18 years) guard let criteriaDate = calendar.date(byAdding: DateComponents(year: criteriaAge), to: DoB) else { fatalError("Unable to get criteria date from date of birth") } // if date from user input date to either 60 months or 24 months depending if date is before the criteriaDate if self < criteriaDate { date = calendar.date(byAdding: DateComponents(month: 60), to: self) } else { date = calendar.date(byAdding: DateComponents(month: 24), to: self) } // makes date non optional guard let date = date else { fatalError("Unable to calculate date") } // get the 1st day of month from the subscription date guard let startOfSubscriptionMonth = calendar.date(from: calendar.dateComponents([.month, .year], from: date)) else { fatalError("Unable to get start date from date") } // returns the last day of month of the subscription date return calendar.date(byAdding: DateComponents(month: 1, day: -1), to: startOfSubscriptionMonth)! } }`````` Made a small project to show how top use ``````struct ContentView: View { @State private var DoB = Date.now @State private var signUpDate = Date.now var body: some View { Form { DatePicker("Date of Birth", selection: \$DoB , displayedComponents: .date) DatePicker("Sign Up Date", selection: \$signUpDate, displayedComponents: .date) // default age LabeledContent("Subscription Month End") { Text(signUpDate.subscriptionDate(DoB: DoB), style: .date) } // Changed to 21 years old LabeledContent("Subscription Month End with 21 years") { Text(signUpDate.subscriptionDate(DoB: DoB, criteriaAge: 21), style: .date) } } } }`````` If you make the date of birth to be older then 18 (or 21 in second label) then you will see only 24 months added otherwise it 60 months from the Sign up date. 4
 SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.
 Oct '23 50 points to the DoubleDecker team for all the excellent comments! Nice explanations. -5 points for "inertial date". (initial? initial date?) 😜 PS: Nigel, I like adding the following code comment before extensions. It helps me navigate once my code files get long. ``````// MARK: - Date Extensions extension Date { // ------- code here --------`````` See -> Adding Code Markers 4 Oct '23 Thank you `@Obelix` for pointing out typo (now corrected). I would not add a `MARK` as it in a file called `Date-Extension.swift` however could add a MARK above the description comment if you have a lot of date extensions. ``````// MARK: - Subscription Date /// Calculates a date from a set date plus a number of month that are set by a set age /// .............`````` Because I have added the methods comment if you option+click on call site you will get the summary and the file name. 4 Oct '23 Thank you @eoinnorris and @NigelGee for the great feedback and examples. Unfortunately, in the 100 days courses it seems that dates are not covered too in depth, or I should say in depth enough for what it is I'm trying to learn. On that note, does anyone have any suggestions as to what books would cover dates the best? I'm not in a position to buy any of the bundles, but dates are going to be a pivotal part of my projects going forward and I really need to learn the better. For another roadblock I'm experiencing: After calculating the dates, I'm looking to save them in UserDefaults. There's no identifying information (no names, no addresses, no phone numbers, just the birthdate for the sake of validating checkride readiness and medical qualification) saved in the app other than the users birthdate so I'm not terribly concerned about safety. I've tried a few methods to save selections out of a date picker, but I can't get the date picker to run a function to convert the date to a string for storage to AppStorage. What am I doing wrong here? .onCommit and .onSubmit don't work here, and attempting to write it like the following yeilds an error: "Static method 'buildExpression' requires that 'Text' conform to 'TableRowContent'" ``````DatePicker("What is your birthdate?", selection: \$birthdate, displayedComponents: .date) { birthdateToString() } .accentColor(Color.teal)`````` I've also tried using didSet on the variable itself, but can't get anything to print in my console indicating that the value was set... ``````@State var birthdate: Date = Date() { didSet { birthdateToString() print("The birthdate has now been set to \(birthdateString)") } }`````` ``````func birthdateToString() { let dateFormatterString = DateFormatter() dateFormatterString.dateStyle = .short birthdateString = dateFormatterString.string(from: birthdate)`````` How do you run a function when the user selects a new date in the picker? This seems easy and I feel stupid for having to ask it. 3 Oct '23 Firstly I do not know anyone that does a book on just dates, however if you search the Forum and type "dates" you will get alot of feed back, there are alot of question (as dates are hard!). Also if you get stuck then there is always here. I tend to uses the `extension Date` to do all the date calculation as keep the call site clean. Secondly `@AppStorage` does NOT store `Date`s but you can store them in `UserDefaults`, However Paul in one of HWS+ live streams (Drink up!) has a work around. ``@AppStorage("storedDate") var storedDate = Date.now.timeIntervalSinceReferenceDate`` However this will not work in `DatePicker`, so add this ``````DatePicker("Date of Birth", selection: \$DoB , displayedComponents: .date) .onChange(of: DoB) { _, newDate in storedDate = newDate.timeIntervalSinceReferenceDate }`````` Then add `.onAppear` on `Form` to get the saved date to `DoB` property ``````.onAppear { DoB = Date(timeIntervalSinceReferenceDate: storedDate) }`````` Here the final sample project ``````struct ContentView: View { @AppStorage("storedDate") var storedDate = Date.now.timeIntervalSinceReferenceDate @State private var DoB = Date.now @State private var signUpDate = Date.now var body: some View { Form { DatePicker("Date of Birth", selection: \$DoB , displayedComponents: .date) .onChange(of: DoB) { _, newDate in storedDate = newDate.timeIntervalSinceReferenceDate } DatePicker("Sign Up Date", selection: \$signUpDate, displayedComponents: .date) // default age LabeledContent("Subscription Month End") { Text(signUpDate.subscriptionDate(DoB: DoB), style: .date) } // Changed to 21 years old LabeledContent("Subscription Month End with 21 years") { Text(signUpDate.subscriptionDate(DoB: DoB, criteriaAge: 21), style: .date) } } .onAppear { DoB = Date(timeIntervalSinceReferenceDate: storedDate) } } }`````` 3 Oct '23 @NigelGee, thank you very much for taking the time to reply, and the knowledge you've shared. I've poured through the knowledge database and looked back through several projects, but it seems like the dates aspect is sort of piecemealed through the course. I'll take a look at that live stream tomorrow, and I'll resume working on the project tomorrow as well. I have today off with my daughter, and since I travel for work, it's always important to me that I make the most of these days 😊 3 Oct '23 Dealing with date calculations can indeed be challenging, but with the right approach and libraries, you can simplify the process. It sounds like you're working with a programming language. I'll provide a high-level approach using a hypothetical programming language, but you'll need to adapt this to the specific language you're working with. 3 Nov '23 Thanks for answering :) 3

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

All interactions here are governed by our code of conduct.

You are not logged in