c# Decimal issues - c#

Code first.
taxRateDecimal = 0.0765;
if (taxRateDecimal.ToString().Split('.').Length == 2)
{
outPut = taxRateDecimal.ToString().Split('.')[1].Substring(0, 4);
ReportParameters.Add("TaxRateAsDecimal", "." + outPut);
}
As you can see in the substring I have to hard code my length of 4.
Desired results .0765 as a string.
Here are some scenarios I have gone through.
I have a percent of 7.65.
I want to convert this to decimal, when doing so I do 7.65 / 100.
this gives me 0.0765, but I want just .0765.
If I take 0.0765 and use a split on "." and use length ect..
I actually get for the array [1] a length of 6 and a value of 076500.
Again I only want .0765 or just 0765 and I can add the dot.
Any other ideas that I have not tried?
This will eventually need to be a string since I am passing it in as a prama into SSRS.

You should be able to use a format to create the string:
var taxRateDecimal = 0.0765D;
var reportParameter = taxRateDecimal.ToString(".0000", CultureInfo.InvariantCulture);
The resulting reportParameter is .0765.
Other results for that format are:
0D -> .0000
1D -> 1.0000
1.23456D -> 1.2346
You have to use CultureInfo.InvariantCulture to be sure that the decimal separator is a dot. Otherwise the current culture (which is the default) might specify a comma as the decimal separator.

string.Format will handle this easily.
double taxRateDecimal = 1.0765;
string formattedResult = string.Format("{0:.0000}", taxRateDecimal % 1);
Console.WriteLine(formattedResult); // .0765

Related

C# string to Decimal On All style or Culture

Hi I want to find if there is any better way to parse the string to Decimal which covers various format
$1.30
£1.50
€2,50
2,50  €
2.500,00  €
I see a lot of examples using culture to convert . & ,. But in my case, I don't have anything to identify the culture.
This display field I get from the client and I need to extract the value.
I tried following (which didn't work for all scenario) but would like to know if we have any best way to handle this.
Decimal.Parse(value,NumberStyles.Currency |
NumberStyles.Number|NumberStyles.AllowThousands |
NumberStyles.AllowTrailingSign | NumberStyles.AllowCurrencySymbol)
I also tried to use Regex to remove the currency sign but unable to convert both 1.8 or 1,8 in one logic.
Well, assuming you always get a valid currency format, and it's only the culture that changes, you could guess which character is used as a decimal point and which is used as a thousands separator by checking which appears the last in the number. Then remove all the thousand separators and parse it like its culture was invariant.
The code would look like the following:
// Replace with your input
var numberString = "2.500,00 €";
// Regex to extract the number part from the string (supports thousands and decimal separators)
// Simple replace of all non numeric and non ',' '.' characters with nothing might suffice as well
// Depends on the input you receive
var regex = new Regex"^[^\\d-]*(-?(?:\\d|(?<=\\d)\\.(?=\\d{3}))+(?:,\\d+)?|-?(?:\\d|(?<=\\d),(?=\\d{3}))+(?:\\.\\d+)?)[^\\d]*$");
char decimalChar;
char thousandsChar;
// Get the numeric part from the string
var numberPart = regex.Match(numberString).Groups[1].Value;
// Try to guess which character is used for decimals and which is used for thousands
if (numberPart.LastIndexOf(',') > numberPart.LastIndexOf('.'))
{
decimalChar = ',';
thousandsChar = '.';
}
else
{
decimalChar = '.';
thousandsChar = ',';
}
// Remove thousands separators as they are not needed for parsing
numberPart = numberPart.Replace(thousandsChar.ToString(), string.Empty);
// Replace decimal separator with the one from InvariantCulture
// This makes sure the decimal parses successfully using InvariantCulture
numberPart = numberPart.Replace(decimalChar.ToString(),
CultureInfo.InvariantCulture.NumberFormat.CurrencyDecimalSeparator);
// Voilá
var result = decimal.Parse(numberPart, NumberStyles.AllowDecimalPoint | NumberStyles.Number, CultureInfo.InvariantCulture);
It does look a bit of complicated for a simple decimal parsing, but I think should do the work for all the input numbers you get or at least the most of them.
If you do this in some sort of loop, you might want to use compiled regex.
The problem here is that in one case . means decimal point but in other it is a thousnads separator. And then you have , as decimal separator. Clearly, it is impossible for the parser to "guess" what is meant, so the only thing you can do is to decide on some rules on how to handle which case.
If you have control over the UI the best approach would be to validate user input and just reject any value that can't be parsed with an explanation on which format is expected.
If you have no control over the UI, the second best option would be to check for some "rules" and then devise which culture is appropriate for that given input and try to run it through decimal.TryParse for that given culture.
For the given input you have, you could have the following rules:
input.StartsWith("$") -> en-US
input.StartsWith("£") -> en-GB
input.StartsWith("€") || input.EndsWith("€") -> de-DE
These could reasonably handle all cases.
In code:
static void Main(string[] args)
{
string[] inputs =
{
"$1.30",
"£1.50",
"€2,50",
"2,50 €",
"2.500,00 €"
};
for (int i = 0; i < inputs.Length; i++)
{
Console.Write((i + 1).ToString() + ". ");
if (decimal.TryParse(inputs[i], NumberStyles.Currency,
GetAppropriateCulture(inputs[i]), out var parsed))
{
Console.WriteLine(parsed);
}
else
{
Console.WriteLine("Can't parse");
}
}
}
private static CultureInfo GetAppropriateCulture(string input)
{
if (input.StartsWith("$"))
return CultureInfo.CreateSpecificCulture("en-US");
if (input.StartsWith("£"))
return CultureInfo.CreateSpecificCulture("en-GB");
if (input.StartsWith("€") || input.EndsWith("€"))
return CultureInfo.CreateSpecificCulture("de-DE");
return CultureInfo.InvariantCulture;
}
Output:
1.30
1.50
2.50
2.50
2500.00
The only way you could do that is just strip string from symbols and change . and , to decimal separator. Something like:
public decimal UniversalConvertDecimal(string str)
{
char currentDecimalSeparator = Convert.ToChar(Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator);
str = str.Replace('.', currentDecimalSeparator);
str = str.Replace(',', currentDecimalSeparator);
StringBuilder builder = new StringBuilder(str.Length);
foreach(var ch in str)
{
if(Char.IsDigit(ch) || ch == currentDecimalSeparator)
builder.Add(ch);
}
string s = builder.ToString();
return Convert.ToDecimal(s);
}
First you have to get current decimal separator from your system.
Then you have to replace . and , with current decimal separator.
Next, you will have to strip the string from any other char than a digit or decimal separator. At the end you can be sure that Convert.ToDecimal is going to work. But I don't know if it is something you want to achieve.
If you need some mechanism to save currency to database, there is a far simpler solution. Just convert this currency to least currency part. For example instead of $1, save 100 cents.
So if you have $1.99, just multiply it by 100 and you will get: 199 cents. And this integer can be saved to db.

Round to 4 Decimal places not working?

Doing this:
double dblRateEvalResult = -0.52;
string strNewResult = dblRateEvalResult.ToString("000.####").TrimStart('-');
I want:
000.5200
I get:
000.52
What am I doing wrong?
You need 0 custom specifier instead of #
string str = dblRateEvalResult.ToString("000.0000").TrimStart('-');
(In your code you are trying to assign string to a double value, I guess this is a typo)
See: The "0" custom format specifier - Custom Numeric Format Strings
If the value that is being formatted has a digit in the position where
the zero appears in the format string, that digit is copied to the
result string; otherwise, a zero appears in the result string.

How do I trim the "0." after I do modulo 1 on a double variable

Hello everyone as the title say I want to trim the "0." after I do modulo 1 on a double variable
Example:
double Number;
Number = Convert.ToDouble(Console.ReadLine()); //12.777
test = Number % 1; //0.777
I want my output to be: 777
only using math with no
string trims and so...
Thank you all !!
and in c# please
That is just a formatting on the ToString. Take a look at all your options here
How about
.ToString(".###");
Without using any string functions!
while(Math.Round(Number-(int)Number,1)!=1)
{
Number=Number/0.1;
if(Number-(int)Number==0)break;//To cover edge case like 0.1 or 0.9
}
NOTE: Number should be of double type!
If I take your question literally, then you do not want the decimal point either, so .ToString(".###") will not get you what you want, unless you remove the first character (which is string manipulation, and you said you don't want that either).
If you want 777 in a numeric variable (not a string), then you can multiply your result by 1000, though I don't know if you'll always have exactly 3 digits after the decimal or not.
The easiest way really is just to use string manipulation. ToString the result without any formatting, then get the substring starting after the decimal. For example:
var x = (.777d).ToString();
var result = x.SubString(x.IndexOf('.') + 1);
You are certainly looking for this:-
.ToString(".###");
As correctly pointed by Marc in comments you should have everything to be in a string, because if you output that 0.777 as it really is stored internally, you'd get 8 random bytes.
Something like this:-
var num = (.777d).ToString();
var result = num.SubString(num.IndexOf('.') + 1);
The most generic way to do this would be:
using System.Globalization;
var provider = NumberFormatInfo.InvariantInfo;
var output = test.ToString(".###", provider)
.Replace(provider.NumberDecimalSeparator, String.Empty);
You can also set the NumberDecimalSeparator on a custom NumberFormatInfo, but if you set it to empty it will throw the exception "Decimal separator cannot be the empty string."

String Format for Thousand separators

Is there a way using String Formatter I can achieve the following:
$52,152 to $52.1
I have a series of values that are all thousands and I will like to display them in the above format.
Thanks
This works for $52.2, using the , number scaling specifier:
string.Format("{0:$0,.0}", 52152);
If you really want 52.1, you’ll probably have to do it “manually”; sorry. All custom formatting strings seem to round.
In your case the non-formatted versions of your 2 numbers are inherently different
52152 != 52.1
A better solution might be to send the correct numbers to the UI but if not, you can use the , scaling specifier - http://msdn.microsoft.com/en-us/library/0c899ak8.aspx#SpecifierTh
void Main()
{
decimal x = 52152M;
var a = string.Format("{0:C}", x); //Current Format in Local Culture
Console.WriteLine(a); //Prints €52,152.00
var b = string.Format("${0:00000}", x); //Custom Format, no decimals
Console.WriteLine(b);//Prints $52152
var c = string.Format("${0:###,###,###}", x); //Custom Format, no decimals + 1000 seperators
Console.WriteLine(c);//Prints $52,152
var d = string.Format("${0:###,###,.0}", x); //Custom Format, 1 decimal place, 1000 seperators to support values over 1 million
Console.WriteLine(d);//Prints $52.2
}
Something like this?
string input = "$52,152";
var number = long.Parse(input, NumberStyles.Currency);
string result = (number / 100L / 10m).ToString("C1");
Explanation. First division is an integer division that truncates. Second division is a System.Decimal division.
This assumes a culture (for example new CultureInfo("en-US")) where the currency sign is "$" and the thousands separator is ",".

ToDecimal from string not returning expected result

I have the following value 48.81, it comes as a string from the database, I need to convert it to decimal, I'm using:
Dim Seconds As Decimal = Convert.ToDecimal((Coordinate.Substring(4, 5)), CultureInfo.InvariantCulture)
I'm receiving 4881D and I need 48,81
Any ideas? I thought CultureInfo.InvariantCulture was going to help me with that
EDIT
The coordinate value is 675900.244.
I'm "spliting" it like this:
Dim Degress As Integer = Coordinate.Substring(0, 2),
Dim Minutes As Integer = Coordinate.Substring(2, 2),
Dim Seconds As Decimal = Convert.ToDecimal((Coordinate.Substring(4, 5)), CultureInfo.InvariantCulture),
Dim Position As Enumerations.EnumCoordinatesPosition = Coordinate.Substring(9, 1)
EDIT
EDIT
EDIT
This is the value of the coordinate in the database
The problem lies in the variable databaseCoordinate, which contains comma instead of dot. InvariantCulture uses comma to separate groups of digits and dot as a decimal symbol. To see this execute the following code:
//outputs '.'
Console.WriteLine(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator);
//outputs ','
Console.WriteLine(CultureInfo.InvariantCulture.NumberFormat.NumberGroupSeparator);
What you can do about it:
Replace comma with dot before parsing - all your code then will work as expected.
Specify decimal separator for Convert.ToDecimal method like this:
decimal Seconds = Convert.ToDecimal((Coordinate.Substring(4, 5)), new NumberFormatInfo { NumberDecimalSeparator = "," });
Write update script DB for all DB entries with coordinates to use dot as a decimal symbol.
Example - this code gives the results you are expecting:
string Coordinate = "100948.811"; //Note the dot instead of comma
int Degress = Convert.ToInt32(Coordinate.Substring(0, 2)); //10
int Minutes = Convert.ToInt32(Coordinate.Substring(2, 2)); //9
decimal Seconds = Convert.ToDecimal((Coordinate.Substring(4, 5)), CultureInfo.InvariantCulture); //48.81
There is a problem related to the value received from database; and also a problem with your approach.
First, if you expect a decimal value, then store it as a decimal in the database.
And secondly, you are trying to parse a string which shall have at least 9 chars. what you have is only 5 chars.
(Coordinate.Substring(4, 5)) here you are declaring that you are expecting at least 9 chars; what you have is only 5 chars.

Categories

Resources