Home > front end >  DateComponentsFormatter - same dates, different results
DateComponentsFormatter - same dates, different results

Time:05-21

Why is dateRemainingText2 giving different result from dateRemainingText?
Obviously dateRemainingText2 is wrong.

Here's my code:

import Foundation

let startDate = Calendar.current.date(from: DateComponents(year: 2022, month: 5, day: 1)) ?? .now
let endDate = Calendar.current.date(from: DateComponents(year: 2020, month: 6, day: 2)) ?? .now

let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.allowedUnits = [.year, .month, .day]
dateComponentsFormatter.unitsStyle = .full
var dateRemainingText = dateComponentsFormatter.string(from: startDate, to: endDate)! // -1 year, 10 months, 29 days
let dateComponents = Calendar.current.dateComponents([.year, .month, .day], from: startDate, to: endDate)
var dateRemainingText2 = dateComponentsFormatter.string(from: dateComponents) // -1 year, 11 months, 1 day

CodePudding user response:

DateComponentsFormatter.string(from:to:) and DateComponentsFormatter.string(from:) are different methods and so they can do different things.

From some experimentation, we can see that string(from:) outputs a string that describes the sum of all the date components in the DateComponents passed in.

This just happens to be the same as the output for string(from:to:) for most of the cases where the components are all positive.

Examples:

// 1 month   7 days
var dateComponents = DateComponents()
dateComponents.month = 1
dateComponents.day = 7
// 1 month, 7 days
print(dateComponentsFormatter.string(from: dateComponents)!)

// 7 days - 1 month
dateComponents.month = -1
dateComponents.day = 7
// -24 days
print(dateComponentsFormatter.string(from: dateComponents)!)

// 1 month - 7 days
dateComponents.month = 1
dateComponents.day = -7
// 24 days
print(dateComponentsFormatter.string(from: dateComponents)!)

// 1 month   30 days
// note that adding 1 month, it's February, and there are only 28 days
dateComponents.month = 1
dateComponents.day = 30
// 2 months, 2 days
print(dateComponentsFormatter.string(from: dateComponents)!)

// -10 months - 30 days
// note that after subtracting 10 months, it is March of the previous year, 
// which also happens to be a leap year, so February has 29 days
// Subtracting 30 days from that will bring us to January, with one day left
// which is, where the extra month and day came from
dateComponents.month = -10
dateComponents.day = -30
// -11 months, 1 day
print(dateComponentsFormatter.string(from: dateComponents)!)

// -1 year - 10 months - 30 days
// similar to above, except not a leap year
// so we have 2 days left after subtracting from a 28-day February.
dateComponents.year = -1
dateComponents.month = -10
dateComponents.day = -30
// -1 year, 11 months, 2 days
print(dateComponentsFormatter.string(from: dateComponents)!)

The DateComponents used in that last case is what Calendar.dateComponents(_:from:to:) in your code.

On the other hand, string(from:to) is the designated method to format the period between two dates.

  • Related