Last active
July 28, 2022 20:30
-
-
Save devpolant/8e2c0f6819341f326de9e9f53fbc547a to your computer and use it in GitHub Desktop.
Custom iOS NumberFormatter Wrapper
This file contains 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
// | |
// AppNumberFormatter.swift | |
// TrumpWall | |
// | |
// Created by Anton Poltoratskyi on 4/13/17. | |
// Copyright © 2017 Anton Poltoratskyi. All rights reserved. | |
// | |
import Foundation | |
private let currencySymbol = "$" | |
private let thousandSymbol = "K" | |
private let millionSymbol = "M" | |
private let billionSymbol = "B" | |
private let groupingFormat = "###,###,###,###.##" | |
private enum FormatType: Int64 { | |
case `default` = 1 | |
case thousand = 1_000 | |
case million = 1_000_000 | |
case billion = 1_000_000_000 | |
func convert(_ value: Double) -> Double { | |
return value / Double(rawValue) | |
} | |
} | |
class AppNumberFormatter { | |
static let shared = AppNumberFormatter() | |
private init() {} | |
enum Style { | |
case short // display as '1K, 2.5M, 10B' | |
case grouped // display as '10,000,000,000' | |
} | |
// MARK: - Formatters | |
private func baseNumberFormatter() -> NumberFormatter { | |
let numberFormatter = NumberFormatter() | |
numberFormatter.formatterBehavior = .default | |
numberFormatter.usesGroupingSeparator = true | |
numberFormatter.groupingSeparator = "," | |
numberFormatter.currencyGroupingSeparator = "," | |
numberFormatter.currencySymbol = currencySymbol | |
return numberFormatter | |
} | |
// MARK: Default Grouped | |
private lazy var currencyDefaultNumberFormatter: NumberFormatter = { | |
let numberFormatter = self.baseNumberFormatter() | |
numberFormatter.numberStyle = .currency | |
numberFormatter.positiveFormat = "¤\(groupingFormat)" | |
numberFormatter.negativeFormat = "-¤\(groupingFormat)" | |
return numberFormatter | |
}() | |
private lazy var defaultNumberFormatter: NumberFormatter = { | |
let numberFormatter = self.baseNumberFormatter() | |
numberFormatter.numberStyle = .decimal | |
numberFormatter.positiveFormat = "\(groupingFormat)" | |
numberFormatter.negativeFormat = "-\(groupingFormat)" | |
return numberFormatter | |
}() | |
// MARK: Thousand | |
private lazy var currencyThousandNumberFormatter: NumberFormatter = { | |
let numberFormatter = self.baseNumberFormatter() | |
numberFormatter.numberStyle = .currency | |
numberFormatter.positiveFormat = "¤\(groupingFormat)\(thousandSymbol)" | |
numberFormatter.negativeFormat = "-¤\(groupingFormat)\(thousandSymbol)" | |
return numberFormatter | |
}() | |
private lazy var thousandNumberFormatter: NumberFormatter = { | |
let numberFormatter = self.baseNumberFormatter() | |
numberFormatter.numberStyle = .decimal | |
numberFormatter.positiveFormat = "\(groupingFormat)\(thousandSymbol)" | |
numberFormatter.negativeFormat = "-\(groupingFormat)\(thousandSymbol)" | |
return numberFormatter | |
}() | |
// MARK: Million | |
private lazy var currencyMillionNumberFormatter: NumberFormatter = { | |
let numberFormatter = self.baseNumberFormatter() | |
numberFormatter.numberStyle = .currency | |
numberFormatter.positiveFormat = "¤\(groupingFormat)\(millionSymbol)" | |
numberFormatter.negativeFormat = "-¤\(groupingFormat)\(millionSymbol)" | |
return numberFormatter | |
}() | |
private lazy var millionNumberFormatter: NumberFormatter = { | |
let numberFormatter = self.baseNumberFormatter() | |
numberFormatter.numberStyle = .decimal | |
numberFormatter.positiveFormat = "\(groupingFormat)\(millionSymbol)" | |
numberFormatter.negativeFormat = "-\(groupingFormat)\(millionSymbol)" | |
return numberFormatter | |
}() | |
// MARK: Billion | |
private lazy var currencyBillionNumberFormatter: NumberFormatter = { | |
let numberFormatter = self.baseNumberFormatter() | |
numberFormatter.numberStyle = .currency | |
numberFormatter.positiveFormat = "¤\(groupingFormat)\(billionSymbol)" | |
numberFormatter.negativeFormat = "-¤\(groupingFormat)\(billionSymbol)" | |
return numberFormatter | |
}() | |
private lazy var billionNumberFormatter: NumberFormatter = { | |
let numberFormatter = self.baseNumberFormatter() | |
numberFormatter.numberStyle = .decimal | |
numberFormatter.positiveFormat = "\(groupingFormat)\(billionSymbol)" | |
numberFormatter.negativeFormat = "-\(groupingFormat)\(billionSymbol)" | |
return numberFormatter | |
}() | |
private func numberFormatter(for value: Int64, style: Style, currency: Bool) -> (formatter: NumberFormatter, convertedValue: Double) { | |
guard style == .short else { | |
let formatter = currency ? currencyDefaultNumberFormatter : defaultNumberFormatter | |
return (formatter: formatter, convertedValue: Double(value)) | |
} | |
let formatter: NumberFormatter | |
let convertedValue: Double | |
let absoluteValue = abs(value) | |
switch absoluteValue { | |
case 0..<10_000: | |
formatter = currency ? currencyDefaultNumberFormatter : defaultNumberFormatter | |
convertedValue = FormatType.default.convert(Double(value)) | |
case 10_000..<1_000_000: | |
formatter = currency ? currencyThousandNumberFormatter : thousandNumberFormatter | |
convertedValue = FormatType.thousand.convert(Double(value)) | |
case 1_000_000..<1_000_000_000: | |
formatter = currency ? currencyMillionNumberFormatter : millionNumberFormatter | |
convertedValue = FormatType.million.convert(Double(value)) | |
default: | |
formatter = currency ? currencyBillionNumberFormatter : billionNumberFormatter | |
convertedValue = FormatType.billion.convert(Double(value)) | |
} | |
return (formatter: formatter, convertedValue: convertedValue) | |
} | |
// MARK: - Public | |
func format(value: Int64, style: Style = .short, currency: Bool = true) -> String { | |
let (formatter, convertedValue) = self.numberFormatter(for: value, style: style, currency: currency) | |
let result = formatter.string(for: convertedValue) | |
return result ?? (value > 0 ? "\(currencySymbol)\(value)" : "-\(currencySymbol)\(value)") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment