72 lines
2.8 KiB
Swift
72 lines
2.8 KiB
Swift
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
|
||
}
|
||
}
|