How to Add Leading Zeros to a String or Number in C#

Turning 42 into 00042 takes one call in C#: "42".PadLeft(5, '0') for a string, or 42.ToString("D5") for an int. Both give you a five-character result with zeros in front.

In this tutorial, I’ll show every way I use to add C# leading zeros: PadLeft, the D and 00000 formats, interpolation, negative numbers, values longer than the width, and trailing zeros. I ran each snippet on .NET 10 with dotnet run.

Add Leading Zeros to a String with PadLeft

The classic case is a ZIP code column that went through Excel. Excel treats 02108 as a number, so Boston’s ZIP comes back as 2108. Here’s how I fix the column after splitting each CSV row:

// ZIP codes from a CSV that went through Excel: the leading zero is gone
string[] rows = { "Boston,MA,2108", "Newark,NJ,7102", "Beverly Hills,CA,90210" };

foreach (string row in rows)
{
    string[] cols = row.Split(',');
    string zip = cols[2].PadLeft(5, '0');
    Console.WriteLine($"{cols[0],-14} {cols[1]}  {cols[2],5} -> {zip}");
}

Console.WriteLine("123456".PadLeft(5, '0'));
Console.WriteLine("42".PadLeft(5));

Output:

Boston         MA   2108 -> 02108
Newark         NJ   7102 -> 07102
Beverly Hills  CA  90210 -> 90210
123456
   42
VS Code running ZipCodes.cs: C# PadLeft(5, '0') adds leading zeros so the ZIP code 2108 becomes 02108
PadLeft restores the leading zero on Boston and Newark ZIP codes

PadLeft(5, '0') right-aligns the text and fills the left side with zeros until it’s five characters long. Boston’s 2108 becomes 02108, Newark’s 7102 becomes 07102, and 90210 is already five characters, so it’s unchanged.

The last two lines matter. A string longer than the width comes back as-is, never cut, and PadLeft(5) without a character pads with spaces.

Keep ZIP codes and account IDs as strings. They’re labels, not quantities, and storing them as int is how the zero gets lost. If you’re going the other way, see how to convert a string to int with leading zeros in C#.

Add Leading Zeros to an Integer with ToString(“D5”) and “00000”

When the value is already an int, skip the string step and format it directly. I use this for invoice numbers like INV-00042 and six-digit check numbers:

using System.Globalization;
CultureInfo.CurrentCulture = new CultureInfo("en-US");


int invoice = 42;
int check = 1047;

Console.WriteLine(invoice.ToString("D5"));
Console.WriteLine(invoice.ToString("00000"));
Console.WriteLine($"INV-{invoice:D5}");
Console.WriteLine($"INV-{invoice:00000}");
Console.WriteLine(string.Format("Check #{0:D6}", check));
Console.WriteLine($"Check #{check.ToString().PadLeft(6, '0')}");

double amount = 7.5;
Console.WriteLine(amount.ToString("00000.00"));
try { Console.WriteLine(amount.ToString("D5")); }
catch (FormatException) { Console.WriteLine("\"D5\" on a double throws FormatException"); }

Output:

00042
00042
INV-00042
INV-00042
Check #001047
Check #001047
00007.50
"D5" on a double throws FormatException
VS Code running InvoiceNumbers.cs: C# ToString("D5"), "00000", interpolation and String.Format add leading zeros to an integer
Invoice and check numbers padded with D5, 00000 and String.Format

D5 means “decimal, at least five digits,” so 42 prints as 00042. The custom 00000 pattern gets the same result, since each 0 is a digit placeholder that’s filled with zero when empty.

These are the same format strings you’d pass to any ToString overload in C#, so they also work inside {invoice:D5}, {invoice:00000} and string.Format("{0:D6}", check).

Why Does “D” Throw a FormatException on a double?

The D specifier works on integral types only: byte, short, int, long and friends. Calling ToString("D5") on a double throws, as the last line shows.

For a double or decimal, use a custom pattern instead. "00000.00" turned 7.5 into 00007.50, padding both sides of the decimal point. The C# data types guide lists which types are integral.

How Do Leading Zeros Work with Negative Numbers?

This is where PadLeft and the number formats really split up. I ran a refund of -42 and a value that’s already wider than five digits through all three:

using System.Globalization;
CultureInfo.CurrentCulture = new CultureInfo("en-US");


int refund = -42;
int big = 123456;

Console.WriteLine(refund.ToString("D5"));
Console.WriteLine(refund.ToString("00000"));
Console.WriteLine(refund.ToString().PadLeft(5, '0'));

Console.WriteLine(big.ToString("D5"));
Console.WriteLine(big.ToString("00000"));
Console.WriteLine(big.ToString().PadLeft(5, '0'));

int width = 8;
Console.WriteLine(big.ToString($"D{width}"));
Console.WriteLine(big.ToString()[^5..]);

Output:

-00042
-00042
00-42
123456
123456
123456
00123456
23456
VS Code running NegativeAndWidth.cs: C# -42 with D5 prints -00042 while PadLeft prints 00-42
D5 and 00000 keep the minus sign in front; PadLeft puts zeros before it

D5 and 00000 both print -00042: five digits, with the sign added in front. PadLeft(5, '0') sees the three characters -42 and produces 00-42, which is wrong.

So for numbers, always use a format string, not PadLeft on ToString().

What Happens When the Number Is Longer Than the Width?

None of the three methods truncate. 123456 stays 123456 with D5, 00000 and PadLeft, because the width is a minimum, not a maximum.

You can build the width at run time with $"D{width}". If you need an exact length, cut it yourself: [^5..] keeps the last five digits, 23456. For the front instead, see how to get the first N characters of a string in C#.

Add Trailing Zeros with PadRight, StringBuilder and “F3”

Trailing zeros mean two different things, depending on whether you have text or a number:

using System.Text;
using System.Globalization;
CultureInfo.CurrentCulture = new CultureInfo("en-US");


string account = "12345";
Console.WriteLine(account.PadRight(10, '0'));

var sb = new StringBuilder(account);
sb.Append('0', 3);
Console.WriteLine(sb.ToString());

decimal price = 12.5m;
Console.WriteLine(price.ToString("F3"));
Console.WriteLine(price.ToString("0.000"));
Console.WriteLine(string.Format("{0:0.00000}", price));
Console.WriteLine($"{price:0.00##}");

Output:

1234500000
12345000
12.500
12.500
12.50000
12.50
VS Code running TrailingZeros.cs: C# PadRight adds trailing zeros to a string and F3 and 0.000 add decimal places to a number
PadRight and StringBuilder.Append for strings; F3 and 0.000 for decimal places

For a string, PadRight(10, '0') fills the right side, so 12345 becomes 1234500000. StringBuilder.Append('0', 3) adds an exact count of zeros instead of padding to a width. I compare when that’s worth it in string vs StringBuilder in C#.

For a number, don’t append characters. F3, 0.000 and {0:0.00000} set the decimal places, so 12.5 prints as 12.500. The 0.00## pattern keeps at least two decimals and up to four.

For rounding to cents, see how to show 2 decimal places in C#, and for grouping, how to format a number with commas in C#.

Which C# Leading Zeros Method Should You Use?

You haveUseResult
A string (ZIP code, ID)s.PadLeft(5, '0')02108
An intn.ToString("D5") or $"{n:D5}"00042
A negative intD5 or 00000, never PadLeft-00042
A double or decimal"00000.00"00007.50
Trailing zeros on texts.PadRight(10, '0')1234500000
Decimal placesF3 or 0.00012.500

The same idea works in other bases: X8 pads a hex string with leading zeros, and there’s a matching trick to convert an int to a binary string with leading zeros.

A few more string and number guides you might find handy:

Frequently Asked Questions

How do I add leading zeros to a string in C#?

Call value.PadLeft(totalWidth, '0'). "2108".PadLeft(5, '0') returns “02108”. If the string is already longer than the width, PadLeft returns it unchanged. See String.PadLeft on Microsoft Learn.

How do I pad an int with leading zeros in C#?

Use number.ToString("D5"), the custom format "00000", or interpolation such as $"{number:D5}". All three turn 42 into 00042. Microsoft documents both approaches in How to pad a number with leading zeros.

Why does ToString(“D5”) fail on a double?

The D format specifier supports integral types only, so a double or decimal throws FormatException. Use a custom pattern like "00000.00" instead.

How do I keep the minus sign in front of the zeros?

Format the number with D5 or 00000; -42 prints as -00042. PadLeft on the string gives 00-42, because it treats the minus sign as a regular character.

Does PadLeft truncate a string that’s too long?

No. The width is a minimum. “123456”.PadLeft(5, ‘0’) returns “123456”. Use Substring if you need an exact length.

Should I store ZIP codes as int or string?

Store them as strings. A ZIP code is a label, and converting it to int drops the leading zero, as with Boston’s 02108.