This commit is contained in:
2026-08-12 07:06:01 +07:00
parent 1025658518
commit 9bc96dbc2d
39 changed files with 1682 additions and 658 deletions
+71
View File
@@ -0,0 +1,71 @@
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
}
}