// // DateParser.swift // SodaLive // // Created by klaus on 12/19/25. // import Foundation // MARK: - 내부: 다양한 포맷 파서를 시도 enum DateParser { static func parse(_ text: String) -> Date? { for parser in parsers { if let d = parser(text) { return d } } return nil } static func relativeTimeText(fromUTC text: String, fallback: String, now: Date = Date()) -> String { guard let date = parse(text) else { return fallback } let interval = max(0, now.timeIntervalSince(date)) let calendar = Calendar.current let yearMonth = calendar.dateComponents([.year, .month], from: date, to: now) if let years = yearMonth.year, years >= 1 { return I18n.Time.yearsAgo(years) } if let months = yearMonth.month, months >= 1 { return I18n.Time.monthsAgo(months) } if interval < 60 { return I18n.Time.justNow } if interval < 3600 { return I18n.Time.minutesAgo(max(1, Int(interval / 60))) } if interval < 86_400 { return I18n.Time.hoursAgo(max(1, Int(interval / 3600))) } return I18n.Time.daysAgo(max(1, Int(interval / 86_400))) } static func chatListDateText(fromUTC text: String, fallback: String, now: Date = Date()) -> String { guard let date = parse(text) else { return fallback } let interval = max(0, now.timeIntervalSince(date)) if interval < 60 { return I18n.Time.justNow } if interval < 3600 { return I18n.Time.minutesAgo(max(1, Int(interval / 60))) } if interval < 86_400 { return I18n.Time.hoursAgo(max(1, Int(interval / 3600))) } if interval < 604_800 { return I18n.Time.daysAgo(max(1, Int(interval / 86_400))) } let calendar = Calendar.current if calendar.component(.year, from: date) == calendar.component(.year, from: now) { let formatter = DateFormatter() formatter.locale = Locale(identifier: LanguageHeaderProvider.current) formatter.timeZone = calendar.timeZone formatter.dateFormat = I18n.MainChat.monthDayDateFormat return formatter.string(from: date) } let formatter = DateFormatter() formatter.locale = Locale(identifier: "en_US_POSIX") formatter.timeZone = calendar.timeZone formatter.dateFormat = "yyyy.MM.dd" return formatter.string(from: date) } // 시도 순서: ISO8601(소수초 포함) → ISO8601 → RFC3339 유사 → 공백 구분 기본 private static let parsers: [(String) -> Date?] = [ { ISO8601.fractional.date(from: $0) }, { ISO8601.basic.date(from: $0) }, { DF.rfc3339.date(from: $0) }, { DF.isoLocalDateTime.date(from: $0) }, { DF.basic.date(from: $0) } ] private enum ISO8601 { static let fractional: ISO8601DateFormatter = { let f = ISO8601DateFormatter() f.formatOptions = [.withInternetDateTime, .withFractionalSeconds] f.timeZone = TimeZone(secondsFromGMT: 0) return f }() static let basic: ISO8601DateFormatter = { let f = ISO8601DateFormatter() f.formatOptions = [.withInternetDateTime] f.timeZone = TimeZone(secondsFromGMT: 0) return f }() } private enum DF { static let rfc3339: DateFormatter = { let f = DateFormatter() f.locale = Locale(identifier: "en_US_POSIX") f.timeZone = TimeZone(secondsFromGMT: 0) f.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" return f }() static let basic: DateFormatter = { let f = DateFormatter() f.locale = Locale(identifier: "en_US_POSIX") f.timeZone = TimeZone(secondsFromGMT: 0) f.dateFormat = "yyyy-MM-dd HH:mm:ss" return f }() static let isoLocalDateTime: DateFormatter = { let f = DateFormatter() f.locale = Locale(identifier: "en_US_POSIX") f.timeZone = TimeZone(secondsFromGMT: 0) f.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" return f }() } }