0

I'm looking to String.Format or ToString() a decimal to get just the fraction part. '123.56m => "56"

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Grudzinski
  • 41
  • 3
  • Does this answer your question? [How do I display a decimal value to 2 decimal places?](https://stackoverflow.com/questions/164926/how-do-i-display-a-decimal-value-to-2-decimal-places) – T1Space Oct 10 '22 at 11:09
  • 2
    @T1Space Why do _you_ think it does answer the question? – ProgrammingLlama Oct 10 '22 at 11:09
  • 2
    There isn't any Numeric Custom Format specifier for only the fractional part, but if you do some arithmetic first you can extract it _then_ format it. – Dai Oct 10 '22 at 11:09
  • @T1Space Unfortunately not. It will not remove the whole part of the value – Grudzinski Oct 10 '22 at 11:16

2 Answers2

5
  • Unfortunately there isn't any Numeric Custom Format specifier for only the fractional part, but if you do some arithmetic first you can extract it then format it...
    • ...and you'll need a .Substring call too.
  • Also, be sure to use CultureInfo.InvariantCulture, otherwise per-user language/culture/region settings will mean possibly different default formatting and radix-point (decimal-point) chars will be used, but using CultureInfo.InvariantCulture means the radix-point will always be an ASCII dot '.' char.
  • I did try an approach using IFormatProvider and ICustomFormatter, unfortunately Decimal.ToString(IFormatProvider) requires provider.GetFormat to return a NumberFormatInfo value and doesn't support using ICustomFormatter.
    • Though IFormatProvider and ICustomFormatter will work if used with String.Format, but that's not in your question.

  • Using Math.Abs() to convert negative numbers to positive numbers (otherwise there's a leading - sign char which would complicate the .Substring call-site).
  • Using ".############################" as the format-string corresponds to the maximum number of decimal places in a Decimal value (i.e. 28 digits).
    • The leading . part is necessary.
  • When the fractionalPart is 0 then there are no digits to render and .ToString( format: "#.########", provider: CultureInfo.InvariantCulture ) will return "" (which will cause .Substring( startIndex: 1 ) to throw an exception, so we can skip that with a ternary expression).
Decimal dec            = 123.45M;
Decimal fractionalPart = Math.Abs( dec - Decimal.Truncate( dec ) );

String formatted       = fractionalPart.ToString( CultureInfo.InvariantCulture, ".############################" );

if( formatted.StartsWith( '.' ) ) formatted = formatted.Substring( startIndex: 1 );

Console.WriteLine( "{0} --> \"{1}\"", dec, formatted ); // "123.45 --> 45"

You can simplify it down to 2 lines:

Decimal fractionalPart = Math.Abs( value - Decimal.Truncate( value ) );
return ( fractionalPart == 0 ) ? String.Empty : fractionalPart.ToString( format: ".############################", provider: CultureInfo.InvariantCulture ).Substring( startIndex: 1 );

Examples:

static String FmtOnlyFractional( Decimal value )
{
    Decimal fractionalPart = Math.Abs( value - Decimal.Truncate( value ) );
    return ( fractionalPart == 0 ) ? String.Empty : fractionalPart.ToString( format: ".############################", provider: CultureInfo.InvariantCulture ).Substring( startIndex: 1 );
}

FmtOnlyFractional(    0.0M        ); => ""
FmtOnlyFractional(    1.0M        ); => ""
FmtOnlyFractional(    1.1M        ); => "1"
FmtOnlyFractional4(   1.0010000M  ); => "001"
FmtOnlyFractional(    0.00000001M ); => "00000001"
FmtOnlyFractional(  123.00000001M ); => "00000001"
FmtOnlyFractional( -123.00000001M ); => "00000001"
FmtOnlyFractional(   -0.00000001M ); => "00000001"
FmtOnlyFractional(   -1.0000000M  ); => ""
FmtOnlyFractional(   -1.0000001M  ); => "000001"
FmtOnlyFractional(   -1.1000001M  ); => "100001"
Dai
  • 141,631
  • 28
  • 261
  • 374
1

Another approach assuming you have up to 2 digits fraction

decimal value = 123.56m;
string result = (value % 1 * 100).ToString("F0"); //"56"

string Split() approach

decimal value = 123.56m;
char separator = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator.First();
string result = value.ToString("F2").Split(separator ).Last();
fubo
  • 44,811
  • 17
  • 103
  • 137
  • 1
    You can get the decimal digits count as from https://stackoverflow.com/questions/13477689/find-number-of-decimal-places-in-decimal-value-regardless-of-culture then multiply per Math.Pow(10, digitscount). – Steve Oct 10 '22 at 11:29