Search code examples
swiftdateformatter

doesRelativeDateFormatting not working for future date in swift


   /// A date formatter for displaying the complete relative date plus the time plus day, no seconds.
///
/// Examples: Today at 2:07 PM; Yesterday at 2:07 PM; Monday, Oct 7, 2018 at 5:05 AM
///
static let relativeFullDateShortFormatterWithDay: DateFormatter = {
    let formatter = DateFormatter()
    formatter.timeStyle = .short
    formatter.dateStyle = .medium
    formatter.doesRelativeDateFormatting = true
    formatter.timeZone = TimeZone.current
    formatter.locale = Locale.autoupdatingCurrent
    return formatter
}()

From the server, I m receiving the expiry date. If the expiry date is of today, I want to show Today and if the expiry date is within week, I want to show weekday name. I m setting doesRelativeDateFormatting to true for this. From the server I m getting expiry date of Sep 4 which is on Friday. When I convert Date to a string using relativeFullDateShortFormatterWithDay it is returning Sep 4, 2020 instead of Friday. is there any more setting i need to set in formatter? For past dates, this is working fine.


Solution

  • Given the formatter in the question and a special weekday formatter

    let weekDayFormatter = DateFormatter()
    weekDayFormatter.dateFormat = "EEEE HH:mm" 
    

    (if the locale is always the same the format could be changed to "EEEE 'at' HH:mm" for English)

    We can then use a function that formats a date by first checking if the fist formatter returns something like "Today" and then returns that and otherwise checks if the given date is within the next week and then returns a weekday

    func format(date: Date) -> String {
        formatter.doesRelativeDateFormatting = true
        let relative = formatter.string(from: date)
        formatter.doesRelativeDateFormatting = false
        let absolute = formatter.string(from: date)
    
        if relative != absolute {
            return relative
        }
    
        let calendar = Calendar.current
        let startDate = calendar.startOfDay(for: Date())
        guard let endDate = calendar.date(byAdding: .day, value: 7, to: startDate) else {
            return formatter.string(from: date)
        }
    
        if date > startDate && date < endDate {
            return weekDayFormatter.string(from: date)
        } else {
            return formatter.string(from: date)
        }
    }
    

    Example

    print(format(date: Date(timeIntervalSinceNow: 60 * 60 * 24 * 1)))
    print(format(date: Date(timeIntervalSinceNow: 60 * 60 * 24 * 4)))
    print(format(date: Date(timeIntervalSinceNow: 60 * 60 * 24 * 12)))
    

    Tomorrow at 17:07
    Saturday 17:07
    13 Sep 2020 at 17:07