TheNoiseClock/TheNoiseClock/Shared/Extensions/Date+Extensions.swift
Matt Bruce d2c6a09e47 more refactoring by codex
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
2026-02-08 10:48:39 -06:00

83 lines
2.7 KiB
Swift

//
// Date+Extensions.swift
// TheNoiseClock
//
// Created by Matt Bruce on 9/7/25.
//
import Foundation
extension Date {
private static let formatterCacheKeyPrefix = "TheNoiseClock.DateFormatter."
/// Format date for display in overlay with custom format
/// - Parameter format: Date format string (e.g., "d MMM yyyy")
/// - Returns: Formatted date string
func formattedForOverlay(format: String = "d MMM yyyy") -> String {
let formatter = Self.cachedFormatter(for: format)
return formatter.string(from: self)
}
private static func cachedFormatter(for format: String) -> DateFormatter {
let cacheKey = formatterCacheKeyPrefix + format
let threadDictionary = Thread.current.threadDictionary
if let cached = threadDictionary[cacheKey] as? DateFormatter {
return cached
}
let formatter = DateFormatter()
formatter.dateFormat = format
formatter.locale = .autoupdatingCurrent
formatter.calendar = .autoupdatingCurrent
threadDictionary[cacheKey] = formatter
return formatter
}
/// Get available date format options with their display names
/// - Returns: Array of (displayName, formatString) tuples
static func availableDateFormats() -> [(String, String)] {
let today = Date()
let formatStrings = [
"d MMMM EEE",
"MMMM d, EEE",
"EEE, MMM d",
"d MMM yyyy",
"MM/dd/yyyy",
"dd/MM/yyyy",
"yyyy-MM-dd",
"MMM d",
"MMMM d",
"EEEE, MMM d"
]
return formatStrings.map { formatString in
let example = today.formattedForOverlay(format: formatString)
return (example, formatString)
}
}
/// Get next occurrence of this time
/// - Returns: Next occurrence of this time, or today if time hasn't passed
func nextOccurrence() -> Date {
let calendar = Calendar.current
let now = Date()
let today = calendar.startOfDay(for: now)
let timeComponents = calendar.dateComponents([.hour, .minute], from: self)
guard let todayWithTime = calendar.date(byAdding: timeComponents, to: today) else {
return now
}
if todayWithTime > now {
return todayWithTime
} else {
// Time has passed today, return tomorrow
guard let tomorrow = calendar.date(byAdding: .day, value: 1, to: today),
let tomorrowWithTime = calendar.date(byAdding: timeComponents, to: tomorrow) else {
return now
}
return tomorrowWithTime
}
}
}