The NumberFormatInfo class includes several properties related to currency, e.g. CurrencySymbol. This means that one can easily format and display objects as currency using standard format strings. Parsing is also supported.
My question is, why is currency supported out of the box and not other units of measure? I would like to do the same thing with length, mass, time etc.
Would it be easy to add this functionality myself? Some structures/classes would be required of course, as one would need to know what the current unit of measure for that object is.
It is just my opinion, but I think the reason why developers of .NET decided to do it in exactly way you mentioned is because of currency's huge range of variations. What I mean : no matter you are developer in US or in Russia or in China, there is the international standards for length, square, etc. measurement (International System of Units). Also it is the same about coordinate system, see the class Point, X.Y.(Z) is everywhere. However, it is not true about the currency. In USA official currency is dollar, in my country (Kazakhstan) it is "tenge".
Related
Is there any possibility to force a parameter tpye to accept only a given format and not only in runtime?
What I mean, for instance I have a method:
public void AcceptTest(double version)
{
}
This method will accept 1.0 but 1.00, 1.0067 and so on.
How can I solve to accept only x.y and nothing else but without check it from code by String.Format or something else.
So I don't even give the possibility to write an unacceptable format in the code editor also.
Thank you!
Your goal is not quite clear, and depending on it any number of answer are possible. Including several that read "you are on a poor track" and "that is impossible".
You can not with Double. Double is defined as a number with a high possibility for decimal places. Every number from it's range is viable, both at compile and runtime.
You could round it automatically, wich might be considered poor behavior.
You could check if the "input" is the same as the "input rounded to the 1st decimal digit" (to see if the other party did the rounding for your).
Note that float imprecision will still result in ending up with wierd decimal places. This is a inherent part of floating point numbers:
https://www.youtube.com/watch?v=PZRI1IfStY0
Some implementations of decimal allow you to specify how many digits after comma to allow. But the .NET one is not among them. At least it avoids the decimal imprecision by lowering the value range.
You could just store as (unsigned) integer. Setting the comma during output would become a display side thing. Maybe make your own structure for this so you can provide your own ToString().
Hop that helps, but calrification would be nessesary. In particular your goal and intention. or the specific problem that makes such a limitation nessesary.
I need to perform some calculations on times of days in 24 hours formatting in an application using schedules. For example, 17h + 12h = 5h. I tried to create my own Time struct and wrap around TimeSpan or DateTime. It's working ok but I'm getting stuck with the formatting to be done in ToString.
Indeed, I of course want my struct to be able to work under any culture. At first I was thinking of delegating the formatting to a DateTime struct and skip all custom formatting that are not strictly time-related. I can't delegate this task to a TimeSpan because it doesn't handle AM/PM used in some cultures for example. For example, in my Time struct I wrote:
public string Format(string format, IFormatProvider provider)
{
return TimeFormat.Format(this, format, DateTimeFormatInfo.GetInstance(provider), provider);
}
// ...
internal class TimeFormat
{
internal string Format(Time time, string format, DateTimeFormatInfo dtfi, IFormatProvider provider)
{
DateTime dt = new DateTime(DateTime.MinValue, 1, 1, time.Hours, time.Minutes, time.Seconds, time.Milliseconds);
/* Here I am checking what the 'format' string is made of
and filter-out anything that is not strictly-time related. */
return dt.Format(format, provider);
}
}
I had a look at how the ToString method of the DateTime struct is implemented into mscorlib. And waow... So many stuffs to take into account. I wanted to more or less rewrite what was in it but keeping only what is time-related but everything's mixed up in this and not easy to understand. And I noticed some definitely not straightforward stuffs to handle also such as Hebrew formatting etc. It would take me way more time than I was expecting to rewrite all this! Especially I don't want to do it without understanding clearly what I'm doing.
So to sum up:
How can I create an "all cultures compliant" formatting of time of the day?
One level above, am I handling the problem correctly using wrappers of DateTime or TimeSpan? I can't use directly a TimeSpan: It's working with negative times (I'm using modulos to have times strictly between 0 and 23:59:59.999), it doesn't handle AM/PM in some cultures, it uses Days. For me, a 'time of the day' is different from a 'span of time'.
I don't need to handle time zone or DST, nor leap second as I am in a calendar agnostic context but I want to be able to handle localized formatting of time of the day. (using 'H' (or any Hebrew, Chinese, Tamil or Russian character) instead of ':' or AM/PM instead for 24-hour format for example).
Any hint or help pointing me to some libraries or tutorials will be helpful!
I had a look at this post before asking this question and took a look at this library also but it looks too complex regarding what I want to achieve.
(I realize this is a plug for my own project, but hopefully folks will see it's entirely relevant :)
Any hint or help pointing me to some libraries or tutorials will be helpful!
I'm the main developer for the Noda Time library, which should do most of what you want. See the user guide for initial information - and feel free to ask more questions either here or on the mailing list.
The type you want is LocalTime.
And yes, you're right about both DateTime and TimeSpan being inappropriate here, and also that the formatting/parsing is complicated :)
In Noda Time you can use the ToString methods as with the normal BCL types, and there are currently static Parse/TryParse/ParseExact/TryParseExact methods - but those may well vanish this evening :) Instead, you should use a LocalTimePattern: define the pattern once (per format and culture), and then use it for both formatting and parsing.
In terms of formatting and parsing, you need to be very clear about what you need. Noda Time piggy-backs onto the BCL for things like what the AM/PM designators are, etc. The fact that you're only dealing with time-of-day makes it much simpler as there aren't month/day names (and different calendars) to worry about. You can use the t pattern for "short" and T for "long" for a particular culture - or specify a custom pattern. Custom patterns are generally more useful for machine-to-machine communication; standard ones are more useful for user-oriented formatting.
(Currently you have to "know" that the t and T patterns exist - although they're documented in the user guide, of course. At some point I'll create methods to make this simpler...)
I want to change CultureInfo of double or the string.
For example I get double value from the code in format like 3015.0
I don't know in what unit is this but I need value in the meters and these are not in the meters because I am on the altitude of cca.100m
I have tried: double.Parse(test, new System.Globalization.CultureInfo("hr-HR"));
and double.Parse(test, new System.Globalization.CultureInfo());
but nothing is a right format what I need.
Any idea what I can do? This is windows form C# application if this is important. Framework 4.0
EDIT:
As you can see on this LINK I had a similar problem before and it was solved with culture info. Problem is that on picture 1 are the values that I get and on the picture 2 are the real values that I need to get ( when I say real I mean in the right format) I think that problem is in the culture somewhere as on my previously question I had problem with decimal values).
This is not related to Culture info.
Looks like you are getting a measurement in feet while you are expecting it to be in meters. In fact, 100 meters = 328.08399 feet and your measurements might be in 10 feets i.e 3015.0 = 301.5 feet (some GPS receivers do not support floats or doubles and therefore return only integers multiplied by 10 to have one decimal accuracy)
If you are using a cheap GPS receiver than this is expected as the accuracy is not that great (this would explain why you are getting 3015.0 instead of 3280)
I hope this helps.
Your problem has nothing to do with CultureInfo but with unit conversion. Probably you will have to do a unit convertion. Are you sure that the number is not 301.5? This would probably mean that the altitue is given in feet.
double altitudeMeters = 0.3048 * altitudeFeet;
The setting of the current culture will not convert units for you. It only affects the formatting of numbers (for example, some cultures use a comma instead of a period for the decimal point). You'll have to do the units conversion yourself.
double.Parse will simply convert the string into a number. It doesn't do unit conversions. The different culture information is for when there is a decimal comma (e.g. French) etc.
You will have to build some logic into your application to convert the number from what looks like feet to meters. If you can be sure that the data is always going to be in the "wrong" format then a simple feet to meters (1 foot = 0.3048 meters) conversion will work. Given that this is a GPS device you might be able to assume this.
If the numbers can be in any format then you will need to analyse the number and if it's outside the sensible range convert it. However, this will fail if someone enters "100". Is this metres or feet?
To ensure you get the right units you will either have to have the user select the units on a separate control or include the units in the input string. If you do the latter then you'll need to get into parsing the string to see if it contains a units string, stripping it off, parsing the number and the string and then doing the conversion.
Altitude comes from $GPGGA string which indicates the units being used. What does the $GPGGA string look like?
see http://aprs.gids.nl/nmea/#gga
if you look at the raw data in the string you will know if you are collecting the right numbers and their units
Alex
What is the best data type to use for money in C#?
As it is described at decimal as:
The decimal keyword indicates a 128-bit data type. Compared to
floating-point types, the decimal type has more precision and a
smaller range, which makes it appropriate for financial and monetary
calculations.
You can use a decimal as follows:
decimal myMoney = 300.5m;
System.Decimal
The Decimal value type represents decimal numbers ranging from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,950,335. The Decimal value type is appropriate for financial calculations requiring large numbers of significant integral and fractional digits and no round-off errors. The Decimal type does not eliminate the need for rounding. Rather, it minimizes errors due to rounding.
I'd like to point to this excellent answer by zneak on why double shouldn't be used.
Use the Money pattern from Patterns of Enterprise Application Architecture. specify amount as decimal and the currency as an enum.
Decimal. If you choose double you're leaving yourself open to rounding errors
decimal has a smaller range, but greater precision - so you don't lose all those pennies over time!
Full details here:
http://msdn.microsoft.com/en-us/library/364x0z75.aspx
Agree with the Money pattern: Handling currencies is just too cumbersome when you use decimals.
If you create a Currency-class, you can then put all the logic relating to money there, including a correct ToString()-method, more control of parsing values and better control of divisions.
Also, with a Currency class, there is no chance of unintentionally mixing money up with other data.
Another option (especially if you're rolling you own class) is to use an int or a int64, and designate the lower four digits (or possibly even 2) as "right of the decimal point". So "on the edges" you'll need some "* 10000" on the way in and some "/ 10000" on the way out. This is the storage mechanism used by Microsoft's SQL Server, see http://msdn.microsoft.com/en-au/library/ms179882.aspx
The nicity of this is that all your summation can be done using (fast) integer arithmetic.
Most applications I've worked with use decimal to represent money. This is based on the assumption that the application will never be concerned with more than one currency.
This assumption may be based on another assumption, that the application will never be used in other countries with different currencies. I've seen cases where that proved to be false.
Now that assumption is being challenged in a new way: New currencies such as Bitcoin are becoming more common, and they aren't specific to any country. It's not unrealistic that an application used in just one country may still need to support multiple currencies.
Some people will say that creating or even using a type just for money is "gold plating," or adding extra complexity beyond the known requirements. I strongly disagree. The more ubiquitous a concept is within your domain, the more important it is to make a reasonable effort to use the correct abstraction up front. If you want to see complexity, try working in an application that used to use decimal and now there's an additional Currency property next to every decimal property.
If you use the wrong abstraction up front, replacing it later will be a hundred times more work. That means potentially introducing defects into existing code, and the best part is that those defects will likely involve amounts of money, transactions with money, or just anything with money.
And it's not that difficult to use something other than decimal. Google "nuget money type" and you'll see that numerous developers have created such abstractions (including me.) It's easy. It's as easy as using DateTime instead of storing a date in a string.
Create your own class. This seems odd, but a .Net type is inadequate to cover different currencies.
One of the fun parts of multi-cultural programming is number formats.
Americans use 10,000.50
Germans use 10.000,50
French use 10 000,50
My first approach would be to take the string, parse it backwards until I encounter a separator and use this as my decimal separator. There is an obvious flaw with that: 10.000 would be interpreted as 10.
Another approach: if the string contains 2 different non-numeric characters, use the last one as the decimal separator and discard the others. If I only have one, check if it occurs more than once and discards it if it does. If it only appears once, check if it has 3 digits after it. If yes, discard it, otherwise, use it as decimal separator.
The obvious "best solution" would be to detect the User's culture or Browser, but that does not work if you have a Frenchman using an en-US Windows/Browser.
Does the .net Framework contain some mythical black magic floating point parser that is better than Double.(Try)Parse() in trying to auto-detect the number format?
I think the best you can do in this case is to take their input and then show them what you think they meant. If they disagree, show them the format you're expecting and get them to enter it again.
I don't know the ASP.NET side of the problem but .NET has a pretty powerful class: System.Globalization.CultureInfo. You can use the following code to parse a string containing a double value:
double d = double.Parse("100.20", CultureInfo.CurrentCulture);
// -- OR --
double d = double.Parse("100.20", CultureInfo.CurrentUICulture);
If ASP.NET somehow (i.e. using HTTP Request headers) passes current user's CultureInfo to either CultureInfo.CurrentCulture or CultureInfo.CurrentUICulture, these will work fine.
You can't please everyone. If I enter ten as 10.000, and someone enters ten thousand as 10.000, you cannot handle that without some knowledge of the culture of the input. Detect the culture somehow (browser, system setting - what is the use case? ASP? Internal app, or open to the world?), or provide an example of the expected formatting, and use the most lenient parser you can. Probably something like:
double d = Double.Parse("5,000.00", NumberStyles.Any, CultureInfo.InvariantCulture);
The difference between 12.345 in French and English is a factor of 1000. If you supply an expected range where max < 1000*min, you can easily guess.
Take for example the height of a person (including babies and children) in mm.
By using a range of 200-3000, an input of 1.800 or 1,800 can unambiguously be interpreted as 1 meter and 80 centimeters, whereas an input of 912.300 or 912,300 can unambiguously be interpreted as 91 centimeters and 2.3 millimeters.