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 } }