Search code examples
iosswiftuidatepicker

Unable to show "Today" instead of today's date after User selects date


I'm making a journal app where the user can edit the date time label. When the user taps on the label, it brings up a UIDatePicker. I want to make it so that when they save the Date, and if it's for "Today", then the label won't update to show today's date and will instead show the word "Today". This is something I've seen in Calendar, Journal, Fitness, and any other app that lets the user edit the entry log date.

It shows correctly when the user initially opens the view and sees the current date and time (programmatic UI):

let dateTimePicker: UIDatePicker = {
    let picker = UIDatePicker()
        picker.datePickerMode = .dateAndTime
        picker.timeZone = NSTimeZone.local
        picker.backgroundColor = UIColor.white
    return picker
}()

let dateTimeLabel: UILabel = {
    let now = Date()
    let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US")
        dateFormatter.setLocalizedDateFormatFromTemplate("h:mm")
    let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
        label.attributedText = NSAttributedString(string: "Today, " + dateFormatter.string(from: now), attributes:[.underlineStyle: NSUnderlineStyle.single.rawValue])

    return label
}()

The Date Picker opens as a popover. When the user clicks "Cancel", the date and time remains the same. When the user changes the date and/or time and clicks "Save", dateTimeLabel updates accordingly. However, if it shows "Today, ___" and the user clicks "Save", then the label updates it to the current date.

Here's what I've tried:

@objc func saveTapped() {
        let dateFormatter = DateFormatter()
            dateFormatter.locale = Locale(identifier: "en_US")

        let now = Date()
        if dateTimePicker.date == now {
            dateFormatter.setLocalizedDateFormatFromTemplate("h:mm")
            dateTimeLabel.text = "Today, " + dateFormatter.string(from: now)
        } else {
            dateFormatter.setLocalizedDateFormatFromTemplate("MMMd h:mm")
            dateTimeLabel.text = dateFormatter.string(from: dateTimePicker.date)
        }

        removePopoverView()
    }

Gif to show what it currently is doing (I want it to show "Today" instead of "Apr 17" on dateTimeLabel when user clicks "save" https://makeagif.com/i/v9mrKs


Solution

  • You can use Calendar method isDateInToday to check if a date is in same day as today:

    if Calendar.current.isDateInToday(dateTimePicker.date) {
        // your code ...
    } else if Calendar.current.isDateInYesterday(dateTimePicker.date) {
        // your code ...
    } else {
        // your code ...
    }
    

    Note that DateFormatter has a property called doesRelativeDateFormatting exactly for this purpose. You just need to set it to true and it would take care of it for you with the advantage of displaying a localized string:


    let date1 = DateComponents(calendar: .current, year: 2020, month: 4, day: 18, hour: 1).date!
    let date2 = DateComponents(calendar: .current, year: 2020, month: 4, day: 17, hour: 23).date!
    
    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .medium
    dateFormatter.timeStyle = .short
    dateFormatter.doesRelativeDateFormatting = true
    
    dateFormatter.string(for: date1)  // "Today at 1:00 AM"
    dateFormatter.string(for: date2)  // "Yesterday at 11:00 PM"