Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store and format a quantity of days/weeks/months in Swift?

Tags:

swift

I would like to create not Date but simple quantities of time (i.e. durations) whose units are either days, weeks or months, then format them nicely as "1 day", "7 days", "3 weeks", "1 month", etc.

However both Duration and Measurement<UnitDuration> initializers do not accept these units.

// Type 'Duration' has no member 'days'
let duration: Duration = .days(7)
// Type 'UnitDuration' has no member 'days'
let measurement: Measurement<UnitDuration> = .init(value: 7, unit: .days)

I tried to extend UnitDuration but it does not allow to automatically format units to plural.

extension UnitDuration {
    static let days = UnitDuration(
        symbol: "days",
        converter: UnitConverterLinear(coefficient: 60 * 60 * 24)
    )
}

let measurement: Measurement<UnitDuration> = .init(value: 1, unit: .days)
measurement.formatted(.measurement(width: .wide, usage: .asProvided)) // "1 days" :(

The aim is to get something like this :

let onDay: Duration = .days(1)
let eightWeeks: Duration = .weeks(8)
oneDay.formatted() // "1 day"
eightWeeks.formatted() // "8 weeks"
like image 336
parapote Avatar asked Sep 19 '25 16:09

parapote


1 Answers

As Fabio says, you could use a DateComponentsFormatter:

formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.weekOfMonth]

let components = DateComponents(weekOfMonth: 13)

if let string = formatter.string(from: components) {
    print(string)
} else {
    print("Unable to convert components to a String")
}

That code outputs "13 weeks" as expected.

Edit:

You can also request multiple different units, e.g. weeks, days, hours, and minutes, and the DateComponentsFormatter will compose a description of the time interval using multiple units. Example:

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.second, .hour, .day, .weekOfMonth]

let components = DateComponents(day: 2, hour: 3, weekOfMonth: 54 )

if let string = formatter.string(from: components) {
    print(string)
} else {
    print("Unable to convert components to a String")
}

That outputs "54 weeks, 2 days, 3 hours".

DateComponentsFormatter also has a func string(from: TimeInterval) function that will take an arbitrary number of seconds and express it in terms of the units you ask for.

like image 78
Duncan C Avatar answered Sep 23 '25 11:09

Duncan C



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!