It appears that your goal is to format a date into a time string showing hours and minutes. But if at the top of the hour (0 minutes), just show the hour.
The basic approach would be to use DateComponents to look at the minute value of the date. Then based on whether it is zero or not, format the date accordingly.
Ideally you could use DateFormatter setLocalizedDateFormatFromTemplate passing in either h:mm or just h or maybe either H:mm or just H. But running some tests with different locales resulted in the wrong localized time format in many cases.
The working solution I found was to set timeStyle to .short and then look at the resulting dateFormat value. When minutes is 0, remove the :mm (or similar) from dateFormat.
Here's some working code:
func shortFormat(date: Date, locale: Locale = Locale.current) -> String {
// Setup the formatter for localized short time style
let formatter = DateFormatter()
formatter.locale = locale
formatter.dateStyle = .none
formatter.timeStyle = .short
// If the date's time is at 0 minutes, remove the minutes from the format
let mins = Calendar.current.component(.minute, from: date)
if mins == 0 {
// Some locales use mm and some use m
// Locales use a colon, period, or other character
// The RE '\Wm{1,2}' means a non-word character followed by 1 or 2 m characters.
if let format = formatter.dateFormat, format.range(of: "\\Wm{1,2}", options: .regularExpression) != nil {
formatter.dateFormat = format.replacingOccurrences(of: "\\Wm{1,2}", with: "", options: .regularExpression)
}
}
return formatter.string(from: date)
}
Here's some test code:
print(shortFormat(date: date))
print(shortFormat(date: date, locale: Locale(identifier: "de_DE")))
print(shortFormat(date: date, locale: Locale(identifier: "fr_FR")))
print(shortFormat(date: date, locale: Locale(identifier: "es_CL")))
Sample output:
3:54 PM
15:54
15:54
3:54 p. m.
And here's some that ensures 0 minutes:
let now = Date()
var comps = Calendar.current.dateComponents([.calendar, .era, .year, .month, .day, .hour, .second], from: now)
let date = Calendar.current.date(from: comps)!
print(shortFormat(date: date))
print(shortFormat(date: date, locale: Locale(identifier: "de_DE")))
print(shortFormat(date: date, locale: Locale(identifier: "fr_FR")))
print(shortFormat(date: date, locale: Locale(identifier: "es_CL")))
Sample output:
3 PM
15
15
3 p. m.
Note that the output in locales that use 24-hour time may be confusing when minutes is 0. You may wish to consider your approach.
.replacingOccurrences(of: ":00(\\s)(\([Calendar.current.amSymbol, Calendar.current.pmSymbol].joined(separator: "|")))", with: "$1$2", options: .regularExpression)? But I don't think there is a guarantee that the minutes will be put there...DateComponentsFormatterfor this task.