-
-
Notifications
You must be signed in to change notification settings - Fork 771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot format date when a time component value is zero and allowedComponents does not contains lower time components (ie. cannot print "today") #370
Comments
Something along these lines: /// Print a colloquial representation of the difference between two dates.
/// For example "1 year ago", "just now", "3s" etc.
///
/// - parameter fDate: date a
/// - parameter tDate: date b
///
/// - throws: throw `.DifferentCalendar` if dates are expressed in a different calendar, `.MissingRsrcBundle` if
/// required localized string are missing from the SwiftDate bundle
///
/// - returns: a colloquial string representing the difference between two dates
public func colloquial(from fDate: DateInRegion, to tDate: DateInRegion) throws -> (colloquial: String, time: String?) {
guard fDate.region.calendar == tDate.region.calendar else {
throw DateError.DifferentCalendar
}
let cal = fDate.region.calendar
let cmp = cal.dateComponents(self.allowedComponents, from: fDate.absoluteDate, to: tDate.absoluteDate)
let allComponents: [(Calendar.Component, Int?)] = [
(.year, cmp.year), (.month, cmp.month), (.weekOfYear, cmp.weekOfYear), (.day, cmp.day),
(.hour, cmp.hour), (.minute, cmp.minute), (.second, cmp.second)
]
let allowedComponents = allComponents
.flatMap({ (unit, value) in value != nil ? (unit, value!) : nil })
.filter({ (unit, _) in self.allowedComponents.contains(unit) })
if let leastGranularAllowedNonZeroComponent = allowedComponents.first(where: { _, value in value != 0 }) {
let (unit, value) = (leastGranularAllowedNonZeroComponent.0, leastGranularAllowedNonZeroComponent.1)
let position: PositionInTime = fDate > tDate ? .future : .past
let colloquialDate = try self.localized(unit: unit, withValue: value, position: position, args: abs(value))
let colloquialTime = try self.colloquial_time(forUnit: unit, withValue: value, date: fDate)
return (colloquialDate, colloquialTime)
} else if let leastGranularAllowedComponent = allowedComponents.first {
let unit = leastGranularAllowedComponent.0
let (position, value): (PositionInTime, Int)
if fDate.isIn(date: tDate, granularity: unit) {
(position, value) = (.now, 0)
} else {
(position, value) = fDate > tDate ? (.future, 1) : (.past, -1)
}
let colloquialDate = try self.localized(unit: unit, withValue: value, position: position, args: abs(value))
let colloquialTime = try self.colloquial_time(forUnit: unit, withValue: value, date: fDate)
return (colloquialDate, colloquialTime)
} else {
throw DateError.FailedToCalculate
}
}
/// Return the colloquial representation of a value for a particular calendar component
///
/// - parameter unit: unit of calendar component
/// - parameter value: the value associated with the unit
/// - parameter asFuture: `true` if value referred to a future, `false` if it's a past event
/// - parameter args: variadic arguments to append
///
/// - throws: throw `.MissingRsrcBundle` if required localized string are missing from the SwiftDate bundle
///
/// - returns: localized colloquial string with passed unit of time
private func localized(unit: Calendar.Component, withValue value: Int, position: PositionInTime, args: CVarArg...) throws -> String {
guard let bundle = self.localizedResourceBundle() else {
throw DateError.MissingRsrcBundle
}
let identifier: String
if unit == .second || (unit == .minute && abs(value) < 5 && self.useImminentInterval) {
identifier = "colloquial_now"
} else {
let positionKey = position.localizationKey
let unitStr = self.localized(unit: unit, value: value, position: position)
identifier = "colloquial_\(positionKey)_\(unitStr)"
}
let localized_date = withVaList(args) { (pointer: CVaListPointer) -> String in
let localized = NSLocalizedString(identifier, tableName: "SwiftDate", bundle: bundle, value: "", comment: "")
return NSString(format: localized, arguments: pointer) as String
}
return localized_date
}
enum PositionInTime: Int {
case past, now, future
var localizationKey: String {
switch self {
case .past: return "p"
case .now: return "n"
case .future: return "f"
}
}
} And, of course, localization files will have to be modified:
This feature has a lot of edge cases, and I have probably broke some of them. It would be nice to look at the requirements, are they specified somewhere? |
Thank you for your report.
|
Previous versions of SwiftDate allowed formatting date as "yesterday", "today", "tomorrow". However, at some point during the development of version 4.0 date formatting underwent significant changes and as a result it is no longer possible to format the date as "today" if it is in today. At least the localized string is missing (for example, in https://github.com/malcommac/SwiftDate/blob/master/Sources/SwiftDate/SwiftDate.bundle/en-US.lproj/SwiftDate.strings).
A possible solution would be to format the date as "just now", "today", "this week", "this month" etc. depending on the
allowedComponents
property of the formatter instead of just formatting it as "just now".The text was updated successfully, but these errors were encountered: