- Revamp whole DB to Display flow - Filter Pipeline, arbitrary filtering and sorting - Binary tree arrays for faster lookup & manipulation - DB: introducing custom functions - DB scheme: split req into heap & cache - cache written by GlassVPN only - heap written by Main App only - Introducing DB separation: DBCore, DBCommon, DBAppOnly - Introducing DB data sources: TestDataSource, GroupedDomainDataSource, RecordingsDB, DomainFilter - Background sync: Move entries from cache to heap and notify all observers - GlassVPN: Binary tree filter lookup - GlassVPN: Reusing prepared statement
75 lines
2.2 KiB
Swift
75 lines
2.2 KiB
Swift
import Foundation
|
|
|
|
private let dateTimeFormat = DateFormatter(withFormat: "yyyy-MM-dd HH:mm:ss")
|
|
|
|
extension DateFormatter {
|
|
convenience init(withFormat: String) {
|
|
self.init()
|
|
dateFormat = withFormat
|
|
}
|
|
}
|
|
|
|
extension Timestamp {
|
|
/// Time string with format `yyyy-MM-dd HH:mm:ss`
|
|
func asDateTime() -> String {
|
|
dateTimeFormat.string(from: Date.init(timeIntervalSince1970: Double(self)))
|
|
}
|
|
|
|
/// Convert `Timestamp` to `Date`
|
|
func toDate() -> Date {
|
|
Date(timeIntervalSince1970: Double(self))
|
|
}
|
|
|
|
/// Current time as `Timestamp` (second accuracy)
|
|
static func now() -> Timestamp {
|
|
Timestamp(Date().timeIntervalSince1970)
|
|
}
|
|
|
|
/// Create `Timestamp` with `now() - minutes * 60`
|
|
static func past(minutes: Int) -> Timestamp {
|
|
now() - Timestamp(minutes * 60)
|
|
}
|
|
}
|
|
|
|
extension Timer {
|
|
/// Recurring timer maintains a strong reference to `target`.
|
|
@discardableResult static func repeating(_ interval: TimeInterval, call selector: Selector, on target: Any, userInfo: Any? = nil) -> Timer {
|
|
Timer.scheduledTimer(timeInterval: interval, target: target, selector: selector,
|
|
userInfo: userInfo, repeats: true)
|
|
}
|
|
}
|
|
|
|
struct TimeFormat {
|
|
/// Time string with format `HH:mm`
|
|
static func from(_ duration: Timestamp) -> String {
|
|
String(format: "%02d:%02d", duration / 60, duration % 60)
|
|
}
|
|
|
|
/// Duration string with format `HH:mm` or `HH:mm.sss`
|
|
static func from(_ duration: TimeInterval, millis: Bool = false) -> String {
|
|
let t = Int(duration)
|
|
if millis {
|
|
let mil = Int(duration * 1000) % 1000
|
|
return String(format: "%02d:%02d.%03d", t / 60, t % 60, mil)
|
|
}
|
|
return String(format: "%02d:%02d", t / 60, t % 60)
|
|
}
|
|
|
|
/// Duration string with format `HH:mm` or `HH:mm.sss` since reference date
|
|
static func since(_ date: Date, millis: Bool = false) -> String {
|
|
from(Date().timeIntervalSince(date), millis: millis)
|
|
}
|
|
|
|
/// Formatted duration string, e.g., `20 min` or `7 days`
|
|
/// - Parameters:
|
|
/// - minutes: Duration in minutes
|
|
/// - style: Default: `.short`
|
|
static func short(minutes: Int, style: DateComponentsFormatter.UnitsStyle = .short) -> String? {
|
|
let dcf = DateComponentsFormatter()
|
|
dcf.maximumUnitCount = 1
|
|
dcf.allowedUnits = [.day, .hour, .minute]
|
|
dcf.unitsStyle = style
|
|
return dcf.string(from: DateComponents(minute: minutes))
|
|
}
|
|
}
|