PONGo_ios/MongoTimestamp.swift
2026-05-31 14:11:29 +02:00

52 lines
2.2 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
/// Parses and renders MCMS timestamps. MCMS emits UTC timestamps with a literal
/// space (e.g. `2026-05-04 21:51:57.394127`), so `ISO8601DateFormatter` will not
/// parse them. Try microsecond precision first, then seconds (field guide
/// §3.7 / §8.5). The `en_US_POSIX` locale forces stable parse rules regardless
/// of the device's 12/24-hour setting.
enum MongoTimestamp {
private static let withMicroseconds = parser("yyyy-MM-dd HH:mm:ss.SSSSSS")
private static let seconds = parser("yyyy-MM-dd HH:mm:ss")
private static func parser(_ format: String) -> DateFormatter {
let f = DateFormatter()
f.locale = Locale(identifier: "en_US_POSIX")
f.timeZone = TimeZone(identifier: "UTC")
f.dateFormat = format
return f
}
static func date(from string: String) -> Date? {
withMicroseconds.date(from: string) ?? seconds.date(from: string)
}
/// Human duration between two MCMS timestamps e.g. uptime computed as
/// (device state `Time` `Online Time`), so it uses the device's own clock
/// rather than the phone's. Returns nil if either is unparseable or end < start.
static func duration(from startString: String?, to endString: String?) -> String? {
guard let startString, let start = date(from: startString),
let endString, let end = date(from: endString) else { return nil }
let total = Int(end.timeIntervalSince(start))
guard total >= 0 else { return nil }
let days = total / 86400, hours = (total % 86400) / 3600, mins = (total % 3600) / 60
if days > 0 { return "\(days)d \(hours)h" }
if hours > 0 { return "\(hours)h \(mins)m" }
return "\(mins)m"
}
private static let display: DateFormatter = {
let f = DateFormatter()
f.dateStyle = .medium
f.timeStyle = .short
return f
}()
/// Render a raw MCMS timestamp in the device's locale/zone, falling back to
/// the original string if it doesn't parse.
static func displayString(_ string: String?) -> String? {
guard let string else { return nil }
guard let date = date(from: string) else { return string }
return display.string(from: date)
}
}