Java: Currency to Locale Mapping Possible? - java

I have a value stored in a DB correlating to a monetary amount, say 10.0. I also have access to the Currency/CurrencyCode. How can I use NumberFormat/DecimalFormat/(other?) to format when I don't know the Locale? According to the docs it will pick a default locale which won't work with a foreign Currency.

JasonTrue is correct, but you can override the currency of the NumberFormat's locale:
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
//the user may have selected a different currency than the default for their locale
Currency currency = Currency.getInstance("GBP");
numberFormat.setCurrency(currency);
numberFormat.format(amount);

The correct behavior, generally speaking, is to format the amount in the User's preferred locale, not the currency's typical locale. On the client side, you'll have the user's preference (Locale.getDefault()); if you are doing something on the web server side, use the Accept-Language or, preferably, the page content's locale to obtain the proper a locale.
The reasoning is this:
An English-US user will understand € 10,000,000.15 but not the suitable-for-Germany equivalent, € 10.000.000,15
The currency itself doesn't contain enough information to infer a suitable locale, anyway.

What if the currency code is EUR? And, while it has taken a beating, USD is still used throughout the world. Inferring the locale from the currency code seems unreliable. Can you introduce an explicit user preference for the locale instead?
The information you are looking for is not part of the built-in Java currency database, so there is not an API for it. You could create your own table for the many cases that are unambiguous.

I would say that if your database is storing a currency value it should be hanging onto the units at the same time. It sounds like you're doing that now. Can you add the Locale to the database at the same time? Could be a decent solution.

Related

How to get list of nationalities in Java

Does someone know a way to retrieve a list of nationalities in Java ? Few precisions : I do not need a list of countries but a list of nationalities. I do not need a list of languages, but a list of nationalities. I've tried to twist Locale API, without result.
And icing on the cake, I need to display nationalities in a specific languages.For example, with Brazil, I need to display a 'brazilian' in english, a 'brésilien' in french and a 'brasilero' in spanish.
Does someone have an idea ?
Java doesn't contain a list of nationalities as far as I'm aware. The Locale class just gives a list of regions as stated in the javadoc. It would be helpful in your situation, but not for a lot.
From what i gather, you're going to have to create your own list of nationalities, and the name of the nationality in each language - not too hard.
To do the language part, internationalization will be helpful. It allows you to get the users region and set a language depending on where the user is from. It also allows formatting of numbers, text and dates.
Look at this stack overflow answer specifically for how to get the names of the nationalities in different languages. Basically, you create a different file for each language and inside the file are key-value pares. So the English file will look a bit like this:
nationality.english = English
nationality.german = German
nationality.russian = Russian
and the German file will be similar to:
nationality.english = Englisch
nationality.german = Deutsche
nationality.russian = Russisch
then depending on what language you want the nationalities displayed in, you just get the text from the language file using the key (e.g. nationality.russian).
To do the nationality part, you can create an enum that contains all the nationalities. For example:
public enum Nationalities{
ENGLISH,
GERMAN;
//And so on
}
See here if you are new to java enums.
You will probably want to add a bit more information in the enum class, such as the county and what the key for the nationality name is.
To pull it all together, you get the region of the user and set the language file for the region. Then for each listed nationality, you get the name of it from the language file.

How to get Local country from the language?

How to find country from its Locale-language ?
e.g; if I set the local language to en then I expect to get US as country.
Locale locale = new Locale("en");
locale.getCountry() // returns null
The issue is that I only have the country code such as: fr,de,en and now I just want to find the right country locale from these codes.
en is English. en_US is US English. en_GB is, I think, UK English. Presumably using en_US would do what you want. There's a list of all the supported locales here: http://www.oracle.com/technetwork/java/javase/locales-137662.html
You can't get the country from "en" because as you can see, multiple countries may share a language. Which one would you pick?
One option would be to get all avaialble locales:
Locale[] locales = Locale.getAvailableLocales();
then insert them into a HashMap and define the language as key. Now its possible to search for the country via the language key.
Apache Commons Lang has a method for that:
LocaleUtils#countriesByLanguage(String)
You can call getCountry() on each of the returned Locales to get the country code. As Eric already pointed out, for many languages there are several countries.

Currency class only one instance per currency?

From this official oracle java tutorial:
Note that the Currency class is designed so that there is never more
than one Currency instance for any given currency. Therefore, there is
no public constructor. As demonstrated in the previous code example,
you obtain a Currency instance using the getInstance methods.
What is the risk of having more than one instance of Currency for a given currency?
Thanks in advance.
Refer link Currency
Representation of a currency for a particular locale. Each currency
is identified by its ISO 4217 code, and only one instance of this
class exists per currency. As a result, instances are created
via the getInstance() methods rather than by using
a constructor.
As Java Doc says you can supersede the Java runtime currency data by creating a properties file named <JAVA_HOME>/lib/currency.properties. The contents of the properties file are key/value pairs of the ISO 3166 country codes and the ISO 4217 currency data respectively. The value part consists of three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric code, and a minor unit. Those three ISO 4217 values are separated by commas. The lines which start with '#'s are considered comment lines. For example,
Sample currency properties
JP=JPZ,999,0
will supersede the currency data for Japan.

Is it Java best practice to store dates as longs in your database?

My reason for doing so is that dates stored as date objects in whatever database tend to be written in a specific format, which may greatly differ from what you need to present to the user on the front-end. I also think it's especially helpful if your application is pulling info from different types of data stores. A good example would be the difference between a MongoDB and SQL date object.
However, I don't know whether this is recommended practice. Should I keep storing dates as longs (time in milliseconds) or as date objects?
I can't speak for it in relation to MongoDB, but in SQL database, no, it's not best practice. That doesn't mean there might not be the occasional use case, but "best practice," no.
Store them as dates, retrieve them as dates. Your best bet is to set up your database to store them as UTC (loosely, "GMT") so that the data is portable and you can use different local times as appropriate (for instance, if the database is used by geographically diverse users), and handle any conversions from UTC to local time in the application layer (e.g., via Calendar or a third-party date library).
Storing dates as numbers means your database is hard to report against, run ad-hoc queries against, etc. I made that mistake once, it's not one I'll repeat without a really good reason. :-)
It very much depends on:
What database you're using and its date/time support
Your client needs (e.g. how happy are you to bank on the idea that you'll always be using Java)
What information you're really trying to represent
Your diagnostic tools
The third point is probably the most important. Think about what the values you're trying to store really mean. Even though you're clearly not using Noda Time, hopefully my user guide page on choosing which Noda Time type to use based on your input data may help you think about this clearly.
If you're only ever using Java, and your database doesn't have terribly good support for date/time types, and you're only trying to represent an "instant in time" (rather than, say, an instant in a particular time zone, or a local date/time with an offset, or just a local date/time, or just a date...), and you're comfortable writing diagnostic tools to convert your data into more human readable forms - then storing a long is reasonable. But that's a pretty long list of "if"s.
If you want to be able to perform date manipulation in the database - e.g. asking for all values which occur on the first day of the month - then you should probably use a date/time type, being careful around time zones. (My experience is that most databases are at least shocking badly documented when it comes to their date/time types.)
In general, you should use whatever type is able to meet all your requirement and is the most natural representation for that particular environment. So in a database which has a date/time type which doesn't give you issues when you interact with it (e.g. performing arbitrary time zone conversions in an unrequested way), use that type. It will make all kinds of things easier.
The advantage of using a more "primitive" representation (e.g. a 64 bit integer) is precisely that the database won't mess around with it. You're effectively hiding the meaning of the data from the databae, with all the normal pros and cons (mostly cons) of that approach.
It depends on various aspects. When using the standard "seconds since epoch", and someone uses only integer precision, their dates are limited to the 1970-2038 year range.
But there also is some precision issue. For example, unix time ignores leap seconds. Every day is defined to have the same number of seconds. So when computing time deltas between unix time, you do get some error.
But the more important thing is that you assume all your dates to be completely known, as your representation does not have the possibility to half only half-specified dates. In reality, there is a lot of events you do not know at a second (or even ms) precision. So it is a feature if a representation allows specifing e.g. only a day precision. Ideally, you would store dates with their precision information.
Furthermore, say you are building a calendar application. There is time, but there also is local time. Quite often, you need both information available. When scheduling overlaps, you of course can do this best in a synchronized time, so longs will be good here. If you however do also want to ensure you are not scheduling events outside of 9-20 h local time, you also always need to preserve timezone information. For anything that does span more than one location, you really need to include the time zone in your date representation. Assuming that you can just convert all dates you see to your current local time is quite naive.
Note that dates in SQL can lead to odd situations. One of my favorites is the following MySQL absurdity:
SELECT * FROM Dates WHERE date IS NULL AND date IS NOT NULL;
may return records that have the date 0000-00-00 00:00:00, although this violates the popular understanding of logic.
Since this question is tagged with MongoDB: MongoDB does not store dates in String or what not, they actually store it as a long ( http://www.mongodb.org/display/DOCS/Dates ):
A BSON Date value stores the number of milliseconds since the Unix epoch (Jan 1, 1970) as a 64-bit integer. v2.0+ : this number is signed so dates before 1970 are stored as a negative numbers.
Since MongoDB has no immediate plans to utilise the complex date handling functions (like getting only year for querying etc) that SQL has within standard querying there is no real downside, it might infact reduce the size of your indexes and storage.
There is one thing to take into consideration here, the aggregation framework: http://docs.mongodb.org/manual/reference/aggregation/#date-operators there are weird and wonderful things you can only with the supported BSON date type in MongoDB, however, as to whether this matters to you depends upon your queries.
Do you see yourself as needing the aggregation frameworks functions? Or would housing the extra object overhead be a pain?
My personal opinion is that the BSON date type is such a small object that to store a document without it would be determental to the entire system and its future compatibility for no apparent reason. So, yes, I would use the BSON date type rather than a long and I would consider it good practice to do so.
I dont think its a best practice to store dates as long because, that would mean that you would not be able to do any of the date specific queries. like :
where date between
We also wont be able to get the date month of year from the table using sql queries easily.
It is better to use a single date format converter in the java layer and convert the date into that and use a single format throughout the application.
IMHO , storing dates in DB will be best if you can use Strings. Hence avoid unnecessary data going up and down to server , if you don't need all the fields in Calendar.
There is a lot of data is in Calendar and each instance of Calender is pretty heavy too.
So store it as String , with only required data and convert it back to Calendar , whenvever you need them and use them.

Sqlite convert text to decimal?

I have an Sqlitedb, with a column: amount text not null
In column amount, I store dollar values in this format: $1.01, $40.58, etc.
I'm trying to sum up the dollar values using
SELECT SUM(amount) FROM record WHERE date LIKE '"+date+"'"
However, it doesn't work, presumably because you can't add text. I know this isn't the ideal storage but how would I go about parsing the amounts so that I can add them up?
Well, as you have stated this is far from the ideal way to store the values (which should be in decimal / real format from the start), however you could do something like this:
SELECT SUM(SUBSTR(amount, 2)) FROM record WHERE date LIKE '"+date+"'"
The SUBSTR method is a text function that will take a section of the text (in this case, from a starting index). The problem here was the $ sign, which was confused the dynamic type conversion into believing you were trying to add strings together.
This should now work as SQLLite allows for dynamic typing (which in a nutshell, means that the value is used for comparison, not the container).
It's much better to store the amounts as unscaled integers, and just format them when needed for display. You get more compact storage, and easier and faster addition. Using integers avoids the risk of rounding errors in floating-point representations.
By unscaled, I mean $1.23 would be stored as the integer 123. (Use long in your Java code, and INTEGER in the SQL.)
You can format amounts for display by querying the locale for the relevant info:
// implement this any way you like!
long amount = getAmountFromDb();
// use default locale if you want
Locale locale = getLocaleFromSomewhere();
Currency currency = Currency.getInstance(locale);
NumberFormat format = NumberFormat.getCurrencyInstance(locale);
int scale = currency.getDefaultFractionDigits();
BigDecimal scaledAmount = new BigDecimal(unscaledBalance).movePointLeft(scale);
String textAmount = format.format(scaledAmount);

Categories