Travail avancé avec les dates et l'heure en Swift
Travailler avec les dates et l'heure est l'une des tâches clés dans le développement iOS/macOS. Au niveau de base, la plupart des développeurs connaissent Date, DateFormatter et Calendar. Cependant, à un niveau avancé, des scénarios complexes apparaissent : gestion des fuseaux horaires, hautes performances lors de l'analyse syntaxique de centaines de dates, affichage correct du temps relatif et traitement de formats personnalisés. Dans cet article, nous allons aborder les techniques avancées de travail avec les dates en Swift qui vous aideront à écrire un code plus fiable et plus efficace.
1. Optimisation de l'analyse syntaxique des dates : DateFormatter vs ISO8601DateFormatter
L'une des opérations les plus courantes est la conversion d'une chaîne en date. Le DateFormatter standard est pratique, mais sa création est une opération coûteuse. Si vous analysez des centaines de dates dans une boucle, chaque appel à DateFormatter() crée un nouvel objet, ce qui entraîne une baisse des performances.
Problème : Création de DateFormatter dans une boucle
// ❌ Mauvais : créer un formateur dans une bouclefor dateString in dateStrings { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" if let date = formatter.date(from: dateString) { // traitement }}Solution : Mise en cache et ISO8601DateFormatter
Pour le format ISO 8601, utilisez ISO8601DateFormatter — il est plus rapide et thread-safe. Pour les formats personnalisés, créez le formateur une seule fois et réutilisez-le.
// ✅ Bon : mettre en cache le formateurprivate let isoFormatter: ISO8601DateFormatter = { let formatter = ISO8601DateFormatter() formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] return formatter}()
// Pour les formats personnalisésprivate let customFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "dd.MM.yyyy HH:mm" formatter.locale = Locale(identifier: "ru_RU") formatter.timeZone = TimeZone(secondsFromGMT: 0) return formatter}()
func parseDates(_ strings: [String]) -> [Date] { return strings.compactMap { isoFormatter.date(from: $0) }}Important : DateFormatter n'est pas thread-safe. Si vous travaillez avec du multithreading, utilisez Thread.current ou créez un formateur séparé pour chaque thread.
2. Travail avec les fuseaux horaires et DateComponents
Le travail avancé avec les dates nécessite la prise en compte des fuseaux horaires. Date en Swift est un moment absolu dans le temps (nombre de secondes depuis le 1er janvier 2001). Toute information sur le fuseau horaire réside dans Calendar et DateFormatter.
Extraction des composants de date dans un fuseau horaire spécifique
let date = Date()let calendar = Calendar.currentlet timeZone = TimeZone(identifier: "America/New_York")!
// Obtenir les composants pour le fuseau horaire spécifiévar components = calendar.dateComponents(in: timeZone, from: date)components.hour // heure à New Yorkcomponents.day // jour à New York
// Création d'une date à partir de composants avec timeZone explicitevar newComponents = DateComponents()newComponents.year = 2024newComponents.month = 12newComponents.day = 25newComponents.hour = 10newComponents.minute = 30newComponents.timeZone = TimeZone(identifier: "Europe/Moscow")
let christmasDate = calendar.date(from: newComponents)print(christmasDate!) // 2024-12-25 07:30:00 +0000 (UTC)Comparaison de dates avec prise en compte du calendrier
Utilisez compare(_:to:toGranularity:) pour comparer avec une précision au jour, à l'heure ou à la minute :
let date1 = Date()let date2 = Date().addingTimeInterval(3600) // +1 heure
let result = calendar.compare(date1, to: date2, toGranularity: .hour)// .orderedSame, si dans la même heure// .orderedAscending, si date1 est plus tôt<