Files
rapira-market-widget/Shared/MarketFormatting.swift
T
2026-08-12 07:06:01 +07:00

72 lines
2.8 KiB
Swift
Raw 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
/// Форматирование рыночных значений.
///
/// `NumberFormatter`/`DateFormatter` дороги в создании, поэтому все экземпляры
/// кэшируются (чтение форматтеров потокобезопасно начиная с macOS 10.9).
enum MarketFormatting {
// MARK: - Публичное API
/// Цена с точностью, зависящей от порядка величины:
/// «70 324,00», «90,0800», «0,338200».
static func price(_ value: Double) -> String {
priceFormatter(for: value).string(from: NSNumber(value: value))
?? String(format: "%.2f", value)
}
/// Абсолютное изменение со знаком: «+1 676,00».
static func signedAmount(_ value: Double) -> String {
let formatter = abs(value) >= 100 ? signedTwoDigits : signedFourDigits
return formatter.string(from: NSNumber(value: value))
?? String(format: "%+.2f", value)
}
/// Доля проценты: 0.0234 «2.34%» или «+2.34%».
static func percent(_ share: Double, signed: Bool) -> String {
String(format: signed ? "%+.2f%%" : "%.2f%%", share * 100)
}
/// Метка обновления: «27 октября 17:10» или «17:10».
static func updated(_ date: Date, withDate: Bool) -> String {
(withDate ? dateTime : timeOnly).string(from: date)
}
// MARK: - Кэш форматтеров
private static let priceTwoDigits = decimal(maxFraction: 2)
private static let priceFourDigits = decimal(maxFraction: 4)
private static let priceSixDigits = decimal(maxFraction: 6)
private static let signedTwoDigits = decimal(maxFraction: 2, signed: true)
private static let signedFourDigits = decimal(maxFraction: 4, signed: true)
private static func priceFormatter(for value: Double) -> NumberFormatter {
switch abs(value) {
case 1000...: priceTwoDigits
case 1...: priceFourDigits
default: priceSixDigits
}
}
private static func decimal(maxFraction: Int, signed: Bool = false) -> NumberFormatter {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = maxFraction
if signed {
formatter.positivePrefix = formatter.plusSign
}
return formatter
}
private static let dateTime = dateFormatter("d MMMM HH:mm")
private static let timeOnly = dateFormatter("HH:mm")
private static func dateFormatter(_ format: String) -> DateFormatter {
let formatter = DateFormatter()
formatter.locale = .current
formatter.dateFormat = format
return formatter
}
}