J'ai vu de nombreuses approches comment calculer la différence entre deux dates en termes d'un composant de date particulier, par exemple en jours, heures, mois etc. (voir cette réponse sur Stackoverflow ):
Calendar.current.dateComponents([.hour], from: fromDate, to: toDate).hour
Calendar.current.dateComponents([.day], from: fromDate, to: toDate).day
Calendar.current.dateComponents([.month], from: fromDate, to: toDate).month
Ce que je n'ai pas vu, c'est comment faire des calculs avec les objets Date
réels. Quelque chose comme
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date
let delta = toDate - fromDate
let today = Date()
if delta < 0 {
return today
} else {
return today + delta
}
}
J'ai vu le type DateInterval
tel qu'introduit dans iOS 10 mais selon la documentation
[il] ne prend pas en charge les intervalles inverses, c'est-à-dire les intervalles où la durée est inférieure à 0 et la date de fin se produit plus tôt dans le temps que la date de début.
Cela rend intrinsèquement difficile le calcul avec les dates - en particulier lorsque vous ne savez pas laquelle est la date antérieure.
Existe-t-il une approche claire et nette pour calculer directement les différences de temps entre Date
s (et les ajouter à nouveau aux instances Date
) sans calculer avec leur timeIntervalSinceReferenceDate
?
J'ai fini par créer un opérateur personnalisé pour Date
:
extension Date {
static func - (lhs: Date, rhs: Date) -> TimeInterval {
return lhs.timeIntervalSinceReferenceDate - rhs.timeIntervalSinceReferenceDate
}
}
Avec cet opérateur, je peux maintenant calculer la différence entre deux dates à un niveau plus abstrait sans me soucier de timeIntervalSinceReferenceDate
ou de la date de référence exacte - et sans perdre en précision, par exemple:
let delta = toDate - fromDate
Évidemment, je n'ai pas beaucoup changé, mais pour moi c'est beaucoup plus lisible et conséquent: Swift a le +
opérateur déjà implémenté pour un Date
et un TimeInterval
:
/// Returns a `Date` with a specified amount of time added to it. public static func + (lhs: Date, rhs: TimeInterval) -> Date
Il soutient donc déjà
Date + TimeInterval = Date
En conséquence, il devrait également soutenir
Date - Date = TimeInterval
à mon avis et c'est ce que j'ai ajouté avec la simple mise en œuvre du -
opérateur. Maintenant, je peux simplement écrire l'exemple de fonction exactement comme mentionné dans ma question:
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date
let delta = toDate - fromDate // `Date` - `Date` = `TimeInterval`
let today = Date()
if delta < 0 {
return today
} else {
return today + delta // `Date` + `TimeInterval` = `Date`
}
}
Il se pourrait très bien que cela comporte des inconvénients que je ne connais pas en ce moment et j'aimerais entendre vos réflexions à ce sujet.
Simplement toDate.timeIntervalSince(fromDate)
.
Pour réimplémenter votre fonction sans ajouter aucune extension:
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date {
let delta = toDate.timeIntervalSince(fromDate)
let today = Date()
if delta < 0 {
return today
} else {
return today.addingTimeInterval(delta)
}
}
Vous pouvez étendre avec un opérateur personnalisé et renvoyer des tuples
extension Date {
static func -(recent: Date, previous: Date) -> (month: Int?, day: Int?, hour: Int?, minute: Int?, second: Int?) {
let day = Calendar.current.dateComponents([.day], from: previous, to: recent).day
let month = Calendar.current.dateComponents([.month], from: previous, to: recent).month
let hour = Calendar.current.dateComponents([.hour], from: previous, to: recent).hour
let minute = Calendar.current.dateComponents([.minute], from: previous, to: recent).minute
let second = Calendar.current.dateComponents([.second], from: previous, to: recent).second
return (month: month, day: day, hour: hour, minute: minute, second: second)
}
}
En utilisant:
let interval = Date() - updatedDate
print(interval.day)
print(interval.month)
print(interval.hour)
Que diriez-vous de quelque chose comme…
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date {
let delta = Calendar.current.dateComponents([.second], from: fromDate, to: toDate).second!
return Calendar.current.date(byAdding: .second, value: delta, to: Date())!
}