Created
December 5, 2025 12:15
-
-
Save esnssr/b1a21175add1d179855b9ba47bdb2228 to your computer and use it in GitHub Desktop.
FormatStyle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public extension FormatStyle where Self == TimeFormatStyle<FloatingPointFormatStyle<Double>> { | |
| static var time: TimeFormatStyle<FloatingPointFormatStyle<Double>> { | |
| TimeFormatStyle(baseStyle: .number, countDirection: nil, formatter: .timeFormatter) | |
| } | |
| static func time(formatter: DateComponentsFormatter) -> TimeFormatStyle<FloatingPointFormatStyle<Double>> { | |
| TimeFormatStyle(baseStyle: .number, countDirection: nil, formatter: formatter) | |
| } | |
| static func time( | |
| countDirection: Self.CountDirection, | |
| formatter: DateComponentsFormatter = .timeFormatter.zeroFormattingBehavior(.pad) | |
| ) -> TimeFormatStyle<FloatingPointFormatStyle<Double>> { | |
| TimeFormatStyle(baseStyle: .number, countDirection: countDirection, formatter: formatter) | |
| } | |
| } | |
| public struct TimeFormatStyle<BaseStyle: FormatStyle>: FormatStyle, Codable where BaseStyle.FormatInput: BinaryFloatingPoint, | |
| BaseStyle.FormatInput: Codable, | |
| BaseStyle.FormatInput: Hashable, | |
| BaseStyle.FormatOutput == String, | |
| BaseStyle: Codable { | |
| public enum CountDirection: Codable { | |
| case forward | |
| case backward | |
| } | |
| let base: BaseStyle | |
| let countDirection: CountDirection? | |
| let formatter: DateComponentsFormatter | |
| init(baseStyle: BaseStyle, countDirection: CountDirection?, formatter: DateComponentsFormatter) { | |
| self.base = baseStyle | |
| self.countDirection = countDirection | |
| self.formatter = formatter | |
| } | |
| // MARK: - Codable Implementation | |
| private enum CodingKeys: String, CodingKey { | |
| case base | |
| case countDirection | |
| } | |
| public init(from decoder: Decoder) throws { | |
| let container = try decoder.container(keyedBy: CodingKeys.self) | |
| let base = try container.decode(BaseStyle.self, forKey: .base) | |
| let countDirection = try container.decodeIfPresent(CountDirection.self, forKey: .countDirection) | |
| self.init( | |
| baseStyle: base, | |
| countDirection: countDirection, | |
| formatter: .timeFormatter | |
| ) | |
| } | |
| public func encode(to encoder: Encoder) throws { | |
| var container = encoder.container(keyedBy: CodingKeys.self) | |
| try container.encode(base, forKey: .base) | |
| try container.encodeIfPresent(countDirection, forKey: .countDirection) | |
| // ignore encoding formatter | |
| } | |
| public func format(_ value: Double) -> String { | |
| var formattedValue = formatter.string(from: value) ?? fallbackFormat(value) | |
| if let countDirection { | |
| formattedValue = countDirection == .forward ? formattedValue : "-" + formattedValue | |
| } | |
| return formattedValue | |
| } | |
| public func locale(_ locale: Locale) -> TimeFormatStyle { | |
| TimeFormatStyle(baseStyle: base.locale(locale), countDirection: countDirection, formatter: formatter) | |
| } | |
| private func fallbackFormat(_ value: Double) -> String { | |
| let hours = value / 3600 | |
| let minutes = value.truncatingRemainder(dividingBy: 3600) / 60 | |
| let seconds = value.truncatingRemainder(dividingBy: 60) | |
| return String(format: "%d:%02d:%02d", hours, minutes, seconds) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment