Duncan C
Duncan C

Reputation: 131408

Have I found a bug in DateComponentsFormatter?

In answering this question on how to create a "xxx <largest_time_units> ago" string based on comparing two dates, I wrote out a complete solution to the problem.

It involves using a DateComponentsFormatter with maximumUnitCount set to 1 and unitsStyle set to .full. Here is the code to create the DateComponentsFormatter:

 var timeFormatter:DateComponentsFormatter = {
    let temp = DateComponentsFormatter()
    temp.allowedUnits = [.year, .month, .weekOfMonth, .day, .hour, .minute, .second]
    temp.maximumUnitCount = 1
    temp.unitsStyle = .full
    return temp
}()

Then I wrote a function that uses the DateComponentsFormatter to output "xxx units ago" strings:

//Use our DateComponentsFormatter to generate a string showing "n <units> ago" where units is the largest units of the difference
//Between the now date and the specified date in te past
func timefromDateToNow(_ pastDate: Date) -> String {
    if let output = timeFormatter.string(from: pastDate, to: now) {
        return output + " ago"
    } else {
        return "error"
    }
}

I calculate dates in the past with code like this:

let value = Double.random(in: min ... max)
let past = now.addingTimeInterval(value)

Strangely, for certain values of value, I'm getting the string "0 months ago". The value I was able to capture was -408754.0, which is about 4 days, 17 hours.

Why would calling timeFormatter.string(from: Date(timeIntervalSinceNow: -408754.0), to: Date()) return a string of 0 months? It should display a result of "4 days"!

Upvotes: 3

Views: 360

Answers (1)

Rob
Rob

Reputation: 437432

If you want a reference to how far long ago, consider RelativeDateTimeFormatter, e.g.

let formatter = RelativeDateTimeFormatter()
formatter.dateTimeStyle = .named
formatter.unitsStyle = .spellOut
formatter.formattingContext = .beginningOfSentence

let date = Date()

let longTimeAgo = date.addingTimeInterval(-10_000_000)
print(formatter.localizedString(for: longTimeAgo, relativeTo: date)) // Three months ago

let veryLongTimeAgo = date.addingTimeInterval(-100_000_000)
print(formatter.localizedString(for: veryLongTimeAgo, relativeTo: date)) // Three years ago

Upvotes: 1

Related Questions