83 lines
2.7 KiB
Swift
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
|
|
}
|
|
}
|
|
}
|