- 应用图标改用与 Web favicon 同源的扁平标记,金色 SIM 卡体加三格递增信号,29pt 下仍可读 - 标签统一为胶囊形状,提高深色主题下的描边权重,避免标签在暗色下消失 - 消息卡片与详情分区卡片收紧行距,单屏信息密度明显提升 - 详情头部指标精简为 4 行,数据模块改为单条读数 - 批量选择勾选框移出名称区域,工具栏控件统一为等高 34pt - 分组编辑器改为点选即生效,移除说明文字与常驻禁用按钮
85 lines
3.2 KiB
Swift
85 lines
3.2 KiB
Swift
import Foundation
|
|
|
|
/// 上游返回的时间戳格式并不统一(`yyyy-MM-dd HH:mm:ss`、ISO8601、秒/毫秒时间戳都出现过),
|
|
/// 列表里需要一个稳定的短读法,解析不出来时原样回退,避免出现"--"这种假结论。
|
|
public enum TimestampText {
|
|
private static let parsers: [DateFormatter] = {
|
|
let patterns = [
|
|
"yyyy-MM-dd HH:mm:ss",
|
|
"yyyy-MM-dd'T'HH:mm:ss",
|
|
"yyyy-MM-dd HH:mm",
|
|
"yyyy/MM/dd HH:mm:ss",
|
|
"yyyy-MM-dd",
|
|
]
|
|
return patterns.map { pattern in
|
|
let formatter = DateFormatter()
|
|
formatter.locale = Locale(identifier: "en_US_POSIX")
|
|
formatter.calendar = Calendar(identifier: .gregorian)
|
|
formatter.timeZone = .current
|
|
formatter.dateFormat = pattern
|
|
return formatter
|
|
}
|
|
}()
|
|
|
|
private static let utcParser: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.locale = Locale(identifier: "en_US_POSIX")
|
|
formatter.calendar = Calendar(identifier: .gregorian)
|
|
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
|
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
|
|
return formatter
|
|
}()
|
|
|
|
private static let timeFormat: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.locale = Locale(identifier: "zh_CN")
|
|
formatter.dateFormat = "HH:mm"
|
|
return formatter
|
|
}()
|
|
|
|
private static let monthDayFormat: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.locale = Locale(identifier: "zh_CN")
|
|
formatter.dateFormat = "MM-dd HH:mm"
|
|
return formatter
|
|
}()
|
|
|
|
private static let fullFormat: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.locale = Locale(identifier: "zh_CN")
|
|
formatter.dateFormat = "yyyy-MM-dd"
|
|
return formatter
|
|
}()
|
|
|
|
public static func date(from raw: String) -> Date? {
|
|
let text = raw.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard text.isEmpty == false else { return nil }
|
|
if let number = Double(text), text.allSatisfy({ $0.isNumber }) {
|
|
// 13 位是毫秒,10 位是秒。
|
|
return Date(timeIntervalSince1970: text.count > 11 ? number / 1000 : number)
|
|
}
|
|
let head = text.hasSuffix("Z") ? String(text.dropLast()) : text
|
|
for parser in parsers {
|
|
if let parsed = parser.date(from: head) {
|
|
return text.hasSuffix("Z") ? utcParser.date(from: head) ?? parsed : parsed
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
/// 今天只看时分,今年看月日,跨年才写全年份。
|
|
public static func short(_ raw: String, now: Date = Date()) -> String {
|
|
guard let parsed = date(from: raw) else {
|
|
return raw.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
}
|
|
let calendar = Calendar.current
|
|
if calendar.isDate(parsed, inSameDayAs: now) {
|
|
return timeFormat.string(from: parsed)
|
|
}
|
|
if calendar.isDate(parsed, equalTo: now, toGranularity: .year) {
|
|
return monthDayFormat.string(from: parsed)
|
|
}
|
|
return fullFormat.string(from: parsed)
|
|
}
|
|
}
|