String Formatting - Formatting Numbers, Dates, and Text in C#

Vaibhav • September 10, 2025

String formatting is about turning raw data-numbers, dates, and other values-into clear, readable text for users, logs, files, and reports. In C#, formatting is built into string interpolation, the string.Format method, and many type-specific ToString() overloads. This article covers the most useful formatting patterns for numbers, dates, currency, alignment, and custom patterns, with practical examples and best practices for everyday code.

This article builds on string interpolation and concatenation. We’ll focus on format specifiers, alignment, culture, and common formatting tasks you’ll encounter in real projects.

1) Formatting numbers - decimals, thousands, currency, percentages

Use format specifiers inside interpolation braces or with ToString() to control how numbers appear.

double price = 1234.567;
int quantity = 42;
double percent = 0.876;

string s1 = $"Price: {price:F2}";         // "Price: 1234.57" (2 decimals)
string s2 = $"Qty: {quantity:D4}";        // "Qty: 0042" (pad with zeros)
string s3 = $"Total: {price:N0}";         // "Total: 1,235" (thousands separator)
string s4 = $"Discount: {percent:P1}";    // "Discount: 87.6%" (percentage, 1 decimal)
string s5 = $"Hex: {quantity:X}";         // "Hex: 2A" (hexadecimal)
  • F2 - fixed-point, 2 decimals
  • N0 - number, no decimals, thousands separator
  • P1 - percentage, 1 decimal
  • D4 - decimal, pad to 4 digits
  • X - hexadecimal

2) Formatting dates and times - custom patterns

Dates and times can be formatted with custom patterns inside interpolation or ToString().

DateTime now = DateTime.Now;

string s1 = $"Date: {now:yyyy-MM-dd}";         // "Date: 2025-09-10"
string s2 = $"Time: {now:HH:mm:ss}";           // "Time: 15:30:45"
string s3 = $"Full: {now:dd-MMM-yyyy HH:mm}";  // "Full: 10-Sep-2025 15:30"
string s4 = $"Day: {now:dddd}";                // "Day: Wednesday"
  • yyyy - year (4 digits)
  • MM - month (2 digits)
  • dd - day (2 digits)
  • HH - hour (24-hour)
  • mm - minute
  • ss - second
  • dddd - day of week
  • MMM - abbreviated month name

3) Alignment and width - neat columns and tables

Use a comma and a number inside interpolation braces to align output. Positive numbers right-align, negative numbers left-align.

string[] names = { "Ada", "Grace", "Linus" };
int[] scores = { 95, 100, 89 };

Console.WriteLine($"{"Name",-10} {"Score",5}");
Console.WriteLine(new string('-', 16));
for (int i = 0; i < names.Length; i++)
    Console.WriteLine($"{names[i],-10} {scores[i],5}");
/*
Name        Score
----------------
Ada           95
Grace        100
Linus         89
*/
  • {expr,-10} - left-align in 10 spaces
  • {expr,5} - right-align in 5 spaces
  • Combine alignment and formatting: {score,6:F1}

4) Formatting currency and culture-sensitive values

Use C for currency, and specify culture for consistent output.

double amount = 1234.5;
string s1 = $"Amount: {amount:C}"; // "Amount: ₹1,234.50" (depends on system culture)

using System.Globalization;
string s2 = amount.ToString("C", CultureInfo.InvariantCulture); // "Amount: $1,234.50"
  • C - currency format (symbol depends on culture)
  • Use CultureInfo.InvariantCulture for logs, data files, or tests

For user-facing text, use the current culture. For machine-readable output, prefer invariant culture for consistency.

5) Formatting with string.Format - legacy but still useful

string.Format lets you use numbered placeholders and format specifiers. It’s less common now (interpolation is preferred), but you’ll see it in older code and some APIs.

int id = 42;
double value = 123.456;
string formatted = string.Format("ID={0:D4}, Value={1:F2}", id, value); // "ID=0042, Value=123.46"
  • {0:D4} - first argument, pad to 4 digits
  • {1:F2} - second argument, 2 decimals

6) Custom patterns - building your own formats

You can combine formatting patterns for custom output, such as CSV lines, logs, or reports.

string[] fields = { "Ada", "Lovelace", "Mathematician" };
string csv = string.Join(",", fields); // "Ada,Lovelace,Mathematician"

DateTime dt = DateTime.Now;
string log = $"[{dt:yyyy-MM-dd HH:mm:ss}] {csv}";
Console.WriteLine(log);
// "[2025-09-10 15:30:45] Ada,Lovelace,Mathematician"

7) Defensive formatting - handling nulls, empty values, and errors

  • Nulls: Interpolation inserts an empty string for null variables. Still, validate user input before formatting.
  • Empty strings: Use string.IsNullOrEmpty() to check before formatting.
  • Exceptions: Invalid format specifiers cause runtime errors. Test your patterns with sample data.

8) Practical mini-project: formatted invoice line

string item = "Widget";
int qty = 7;
double unitPrice = 19.99;
double total = qty * unitPrice;

string line = $"{item,-10} {qty,3} x {unitPrice,8:C2} = {total,10:C2}";
Console.WriteLine(line);
// "Widget        7 x   ₹19.99 =    ₹139.93"
  • Left-align item name, right-align quantity, format price and total as currency with 2 decimals.
  • Easy to scan, easy to audit, and ready for printing or exporting.

9) Quick reference - most useful format specifiers

  • F2 - fixed-point, 2 decimals
  • N0 - number, no decimals, thousands separator
  • P1 - percentage, 1 decimal
  • C - currency
  • D4 - decimal, pad to 4 digits
  • X - hexadecimal
  • yyyy-MM-dd - date (year-month-day)
  • HH:mm:ss - time (24-hour)
  • dd-MMM-yyyy - date (day-abbreviated month-year)

10) Checklist - formatting habits for better code

  • Use interpolation for most formatting tasks ($"...").
  • Specify format strings for numbers and dates inside braces ({expr:format}).
  • Align columns with {expr,width} for neat tables.
  • Use string.Join for lists and CSV lines.
  • Control culture for logs, exports, and tests.
  • Validate input before formatting to avoid nulls and errors.
  • Test your format patterns with sample data.

Summary

String formatting in C# lets you turn raw data into clear, professional output. Use interpolation and format specifiers for numbers, dates, currency, and alignment. Combine patterns for custom reports, logs, and exports. Control culture for consistent output, and validate input to avoid surprises. With these habits, your code will be easier to read, audit, and maintain-no matter how complex your data gets.