Reputation: 4292
I would like to store a time of day in a simple way. For the purposes of my app, I only care about a specific time of day, like 2:30pm or 1:10am.
Using a DateComponentsFormatter
I can get really close.
import Foundation
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.allowedUnits = [
.hour,
.minute
]
// Use the configured formatter to generate the string.
let timeAmount = 9000.0
let outputString = formatter.string(from: timeAmount)
let desiredString = "2:30 pm"import Foundation
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.allowedUnits = [
.hour,
.minute
]
// Use the configured formatter to generate the string.
let timeAmount = 9000.0
let outputString = formatter.string(from: timeAmount) // yields "2:30"
let desiredString = "2:30 pm"
Now, it seems that the formatter is really just saying "two hours and thirty minutes," so maybe I am barking up the wrong tree here. Does DateComponentsFormatter
support my use case?
Upvotes: 0
Views: 1527
Reputation: 437552
The DateComponentsFormatter
is for expressing the amount of time between two dates. DateFormatter
is for formatting dates or times. Use DateFormatter
.
If your intent is to display a time in the UI, use DateFormatter
, but
dateFormat
, but rather use timeStyle
;locale
;timeZone
;E.g. to show the current time in the UI:
let date = Date()
let formatter = DateFormatter()
formatter.timeStyle = .short
let string = formatter.string(from: date)
By the way, this will format time strings as preferred by the user (e.g. AM/PM for some of us, but in other locales, users may prefer 24 hour clock representation). When displaying information in the UI, we should always honor the user’s preferences.
If you’re trying to convert your 9,000 seconds to 2:30am:
let startOfDay = Calendar.current.startOfDay(for: Date())
let date = startOfDay.addingTimeInterval(9000)
let formatter = DateFormatter()
formatter.timeStyle = .short
let string = formatter.string(from: date) // 2:30 AM
Clearly, if you happen to be on a date where you are shifting to or from daylight savings, your result may vary.
Upvotes: 2
Reputation: 271555
From the documentation:
An
DateComponentsFormatter
object takes quantities of time and formats them as a user-readable string.
The point is that a DateComponentsFormatter
operates on quantities of time (e.g. 2 hours and 10 minutes), whereas you want a point in time. These are very different things. Trying to use DateComponentsFormatter
to produce a time of day could work if you try hard enough, it's just that you are misusing/abusing it.
It seems like you are storing the times of day as the number of seconds since midnight. To format this with DateComponentsFormatter
, you would need to do a lot of checks and calculations with the stored number:
Plus, the am/pm is not localisable. There also might be some cultures in the world where they use a different format to display quantities of time from times of day (I don't know!), which will cause this approach to break down completely.
DateFormatter
should be used to format times of day. Just add the stored time to the UNIX epoch time (or any other midnight) and format with the UTC timezone:
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "hh:mm a"
// or you can replace the above 2 lines with something more localised:
// formatter.timeStyle = .short
formatter.timeZone = TimeZone(identifier: "UTC")
let output = formatter.string(from: Date(timeIntervalSince1970: storedTime))
Upvotes: 2