Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 months ago.
Improve this question
I ran into such a problem: from the server I receive such a figure in the string format "20760.326586753041" (example), but I want to change it so that the user's screen has such a figure 20,761.93.
How can I format it?
Tried to do like this:
func setup(coin: Coin) {
self.nameCoin.text = coin.name
self.symbolCoin.text = coin.symbol
self.priceCoin.text = String(format: "%.2f", coin.priceUsd)
}
Show 0.0 on screen
You should use a NumberFormatter
import Foundation
let coinFormatter : NumberFormatter = {
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "en-US")
return formatter
}()
let stringFromServer = "20760.326586753041"
if let value = coinFormatter.number(from: stringFromServer),
let reformattedString = coinFormatter.string(for: value) {
print(reformattedString)
}
I create a number formatter called coinFormatter that format numbers into decimals that have at most 2 decimal places. The code below that shows how you might use such a number formatter to convert the string from the server to a number, then the number back to a string with the expected format.
It also looks like you might be trying to format the number as a currency value. There are mechanisms in NumberFormatter for properly formatting currency values that you should look into as well.
P.S. As you will see in the comments below, NumberFormatter takes into account many complexities like the Locale and common radix marks used, how you want negative numbers represented, or whether the currency symbol should be written before or after the number when representing money. Please take the time to learn more about NumberFormatter and the power it offers you.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 13 days ago.
Improve this question
Can anyone tell me why this doesn’t work right with dates from the server?
I'm trying to compare dates to Now so I can see what was in the past, today and future.
func getDetails(for game: Game) -> String {
let now = Date.now
let gameDate = game.gameDate
if gameDate.compare(now) == .orderedAscending {
print(“past”)
return "past"
}
if gameDate.compare(now) == .orderedDescending {
print(“future”)
return "future"
}
if gameDate.compare(now) == .orderedSame {
print(“today”)
return "today"
}
return "none"
}
My decoder is set decoder.dateDecodingStrategy = .iso8601
All of the dates come back “past” and this is iOS 15+
Thanks for your help in advance.
There is no reason to use the compare() function for dates. Dates conform to the Comparable and Equatable protocols, which means you can use >, <, = >=, and <= to compare them directly.
That said, we don't know what your game.date value is.
I can tell you that Date objects capture the date and time with sub-millisecond precision. Any date you pass into your function is likely to be a few nanoseconds before this code runs, and so be in the past.
consider this code:
let now = Date()
var total = 1
total *= 2
let later = Date()
let equalString = (now == later) ? "equal" : "not equal"
print("The dates are \(equalString)")
if now != later {
print("Dates differ by \(later.timeIntervalSinceReferenceDate - now.timeIntervalSinceReferenceDate)")
}
That code prints "The dates are not equal" because it takes enough time to multiply 1 * 2 that the later date is a tiny fraction of a second later than now.
(On my machine it says that the later date is greater than the now date by 8.499622344970703e-05, or about 8.4 microseconds.)
Take out the math code between the two statements and sometimes you'll get it to say the dates are equal, and other times it will say they are not equal.
I use In App Purchases in an iOS app. I want to display the price in the right format depending on the user/device.
Here's my code:
let price=product.price
let numberFormatter = NumberFormatter()
numberFoxrmatter.formatterBehavior = .behavior10_4 //doesn't change anything if I remove this line
numberFormatter.numberStyle = .currency
numberFormatter.locale = product.priceLocale
let formattedPrice=numberFormatter.string(from: price)
But the currency symbol is not the good one and/or misplaced in some cases.
In my example, the price product is $19.99 or 20,99€.
Examples
From device:
product.priceLocale: en_FR#currency=EUR (fixed)
Locale.current: en_FR (current)
Output: €20,99
Should display: 20,99€
From simulator:
product.priceLocale: en_FR#currency=EUR (fixed)
Locale.current: en_US (current)
Output: $20.99
Should display: 20,99€ or $19.99
I have several users who have the same issue with other currencies where the symbol should be placed after the price, unlike the dollars format. And another user who sees $7290 instead of 7290₸ (which is quite a different price...).
I'm pretty sure it has to do with the language setting or the Locale.current. But if I change my primary language to French on my device, I have the same price "€20,99". What is weird is my Locale.current switches to en_US (current).
Any way to solve this?
Another solution I'd be happy with: display the price in dollars for everyone, whatever the user's language & currency.
Try this
let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
// localize to your grouping and decimal separator
currencyFormatter.locale = Locale.current
// We'll force unwrap with the !, if you've got defined data you may need more error checking
let priceString = currencyFormatter.string(from: 9999.99)!
print(priceString) // Displays $9,999.99 in the US locale
Example
currencyFormatter.locale = Locale(identifier: "fr_FR")
if let priceString = currencyFormatter.string(from: 9999.99) {
print(priceString) // Displays 9 999,99 € in the French locale
}
For more detail please check https://supereasyapps.com/blog/2016/2/8/how-to-use-nsnumberformatter-in-swift-to-make-currency-numbers-easy-to-read
Locale setting is key to the correct output. en_FR reads like English language and french region. This will result in formatted output for an english speaker with french price -> €10.00
Use the simulator and set region & language to french and use Locale.current. It should read fr_FR and give correct output. 10,00€
Did you try to change language and region on the simulator and does it effect priceLocale?
I am trying to get some decimal number from the user inside a UITextfield in iOS Swift. Now the user can input number in his or her local number format as per the locale Settings in iOS. I want to convert this number which is in the user's mother tongue into English number. I searched a lot in this site (stackoverflow.com) and the majority of answers are for conversion from one locale (Chinese, or Arabic or Persian) into English but I want to convert number inputted into any locale format into English. How can I do this? So in nutshell, my question is whether the number being inputted in UITextField is in Hindi, Arabic, Persian, Chinese or whatsoever format as per the locale, I want to convert it into English Number format.
you can use NumberFormatter for that.
check below example:
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
let localNumberInStr = "૨૩"
guard let str = numberFormatter.number(from: localNumberInStr) else {return}
print(str) //"23"
When you check the devices locale you know which locale the user is using.
let locale = Locale.current
Just to improve upon Dharmesh answer, here is the answer wrapped in a helper method for use throughout the code. Obviously, it assumes that while getting user input via UITextField one has considered the number set in the user's locale settings.
func convertLocaleNumberIntoEnglish(localeNumberString: String?) -> String? {
guard let ulocaleNumberString = localeNumberString else {return nil}
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
let localNumberInStr = ulocaleNumberString
guard let number = numberFormatter.number(from: localNumberInStr) else {return nil}
let str = String(format:"%f", number.doubleValue)
return str
}
Situation
I want to format a Double 23.54435678 into a String like 23.54 fps respecting the user's locale.
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
let formatted = formatter.string(from: fps as NSNumber)! + " fps"
For the localized number formatting I use DateFormatter.
Question
How should I handle the unit part? Is it valid to just append the unit to the formatted number? Is the placement of the symbol not locale dependent? How do I handle that?
Cocoa has no built-in support for the unit "frames per second", so you will have to provide the suffix yourself, e.g. using Xcode's localization system.
You still need to format the numeric value with NumberFormatter for the current locale and then insert the resulting number string into the localized format string:
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
let numberString = formatter.string(from: fps)
let formatString = NSLocalizedString("%# fps", comment: "") // provide localizations via .strings files
let fpsString = String(format: formatString, arguments: numberString)
If unit placement is locale-dependent (you will have to this find out yourself for the target locales of your app), you have to deal with this manually as well. You can leverage the localization system here by providing localizations with an adequately positioned placeholder for the numeric value, e.g. %# fps for English and x %# yz for... well, Fantasy Language.
I want to turn String precent value into Double by:
let formatter = NumberFormatter()
formatter.numberStyle = .percent
let a = formatter.number(from: "12.5%")
print(a)
It works well in playground. But when test in project under "romana"(Română) language, it prints nil. If i change 12.5% to int type percentage value like 56% it works no problem.
Any idea?
Attached the language setting page.
If i change 12.5% to int type percentage value like 56% it works no problem.
This usually means that the locale settings use a different character for decimal separator, i.e. comma , instead of dot .
Switching to 12,5% should fix this problem.
I got all the source number with . separator
If your numbers are hard-coded in the source, you should not rely on user-selected locale. Use system locale for dealing with hard-coded inputs:
formatter.locale = Locale.system
[Locale.system is] The generic locale that contains fixed “backstop” settings that provide values for otherwise undefined keys. Use the system locale when you don’t want any localizations.
Try this
let formatter = NumberFormatter()
formatter.numberStyle = .percent
formatter.locale = Locale(identifier: "EN")
let a = formatter.number(from: "12.5%")