UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Day 28 - I can create a Date that never existed

Forums > 100 Days of SwiftUI

@geoff  

I was fascinated to learn about the "missing" days in September 1752 on Day 26, and now on Day 28 I'm comfortable enough with DateComponents to mess around wth specific days.

So of course I had to try and create one of those days in 1752. I put this into a playground:

import SwiftUI

var components = DateComponents()
components.hour = 7
components.minute = 0
components.year = 1752
components.month = 9
components.day = 10
var d = Calendar.current.date(from: components) ?? Date.now

print(d.formatted())

And got the following result:

9/10/1752, 7:00 AM

Shocking! I was totally expecting today, right now.

So I'm fully on board with using Date and all the related stuff. (I highly doubt that September 1752 is going to figure strongly in my apps.) But my question (apart from "what gives?") is what are the actual cases when I might get a nil? I've been trying for a few minutes to break it but date(from: components) happily gives me something each time.

Thanks, Geoff (@SwiftLearner3, currently Day 28)

2      

DateComponents have a lot of element eg. nanoseconds, era, etc and which are all optional. The complier need to make sure that they is aleast one to make the date(from: components) but will not know which so need to be unwrapped. If you want to try not to any components then make the date(from: components) and see the result.

2      

@geoff  

Empty date components produces 1/1/1 12:00 AM as the result. Still no nil.

2      

I just tried to create this small project to see if it would break the code by allowing me to enter non-number text values as the date components. But it still doesn't fail to create a date and default to Date.now. It just defaults to 1/1/1 12:00 as it did in your example, even if I enter values like "Cat", "Dog", "House", etc.

import SwiftUI

struct ContentView: View {
  @State private var date = Date.now
  @State private var components = DateComponents()
  @State private var hourInput = ""
  @State private var minuteInput = ""
  @State private var yearInput = ""
  @State private var monthInput = ""
  @State private var dayInput = ""

  var body: some View {
    Text(date.formatted())
      .font(.title.bold())

    Form {
      TextField("Hour", text: $hourInput)
      TextField("Minute", text: $minuteInput)
      TextField("Year", text: $yearInput)
      TextField("Month", text: $monthInput)
      TextField("Day", text: $dayInput)
    }

    Button("Create Date") {
      date = createDate()
    }
    .padding()
    .background(.blue)
    .foregroundColor(.white)
    .clipShape(Capsule())
  }

  func createDate() -> Date {
    components.hour = Int(hourInput)
    components.minute = Int(minuteInput)
    components.year = Int(yearInput)
    components.month = Int(monthInput)
    components.day = Int(dayInput)

    return Calendar.current.date(from: components) ?? Date.now
  }
}

So yeah, I'm not sure why date(from components:) has an optional Date? as a return type when it never seems to return nil.

2      

On second thought, my example tries to convert each String to Int before passing it into date(from components:), which would result in nil.

So, it would be no different from setting all of the component property values equal to nil in your example.

2      

@geoff  

Even passing in all nils results in a non-nil Date coming back.

I like your code, I modified it a little bit to remove the conversion from String to Int:

import SwiftUI

struct ContentView: View {
    @State private var date = Date.now
    @State private var components = DateComponents()
    @State private var hourInput: Int?
    @State private var minuteInput: Int?
    @State private var yearInput: Int?
    @State private var monthInput: Int?
    @State private var dayInput: Int?

    var body: some View {
        Text(date.formatted())
            .font(.title.bold())

        Form {
            TextField("Hour", value: $hourInput, format: .number)
            TextField("Minute", value: $minuteInput, format: .number)
            TextField("Year", value: $yearInput, format: .number)
            TextField("Month", value: $monthInput, format: .number)
            TextField("Day", value: $dayInput, format: .number)
        }

        Button("Create Date") {
            date = createDate()
        }
        .padding()
        .background(.blue)
        .foregroundColor(.white)
        .clipShape(Capsule())
    }

    func createDate() -> Date {
        components.hour = hourInput
        components.minute = minuteInput
        components.year = yearInput
        components.month = monthInput
        components.day = dayInput

        return Calendar.current.date(from: components) ?? Date.now
    }
}

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.