Lesson 20 · Format Function

The Format Function

Master every way VB 2026 formats numbers, dates, and strings — standard format specifiers (C, F, N, P, E, G), custom numeric and date patterns, String.Format, interpolated strings with specifiers, and the legacy Format() function.

Key Takeaway: In VB 2026 there are three modern ways to format values: value.ToString("format"), String.Format("{0:format}", value), and interpolated strings $"{value:format}". All three use the same format specifiers. The legacy VB6-style Format(value, "pattern") function still works but the modern approaches are preferred. For numbers, memorise: C = Currency, F = Fixed decimal, N = Number with thousands separator, P = Percentage, E = Scientific, G = General (shortest). For dates, d = short date, D = long date, t = short time, T = long time, f = full, s = sortable.

20.1 Three Ways to Format in VB 2026

ThreeWays.vb — Visual Basic 2026
' All three produce the same result: "RM 1,234.57"
' 1. ToString with format specifier (most concise)
Dim price = 1234.567
lblA.Text = price.ToString("C2")                        ' "RM 1,234.57"  (culture-dependent)

' 2. String.Format -- good for building composite strings
lblB.Text = String.Format("Total: {0:C2}", price)         ' "Total: RM 1,234.57"

' 3. Interpolated string $ -- most readable, VB 2026 preferred
lblC.Text = $"Total: {price:C2}"                         ' "Total: RM 1,234.57"

' Multiple values in one interpolated string
Dim qty = 3, unitPrice = 29.99, total = qty * unitPrice
lblReceipt.Text = $"{qty} x {unitPrice:C2} = {total:C2}"   ' "3 x RM29.99 = RM89.97"

' Legacy VB6 Format() function -- still works in VB 2026
lblD.Text = Format(price, "Currency")    ' "RM 1,234.57"
lblE.Text = Format(price, "Fixed")       ' "1234.57"
lblF.Text = Format(price, "Standard")    ' "1,234.57"
lblG.Text = Format(price, "Percent")     ' "123,456.70%"

20.2 Standard Number Format Specifiers

A format specifier is a single letter optionally followed by a precision digit. The letter sets the style; the digit sets the number of decimal places (or significant digits for G and E).

SpecifierNameExample (1234.5678)Notes
C or C2CurrencyRM 1,234.57Uses culture's currency symbol & separator. C2 = 2 decimal places.
F or F4Fixed-point1234.5678F = 2 decimal places by default. F4 = 4. No thousands separator.
N or N2Number1,234.57Like F but adds thousands separator. N0 = no decimals.
P or P1Percent123,456.78%Multiplies by 100 then adds %. Use 0.1234 to get "12.34%".
E or E3Scientific1.235E+003E3 = 3 decimal places in mantissa. E = 6 by default.
G or G4General1234.6Shortest of fixed or scientific. G4 = 4 significant digits.
D or D5Decimal (integers)01235Zero-pads integers to minimum width. D5 of 42 = "00042".
X or X8Hexadecimal4D2X = uppercase, x = lowercase. X8 zero-pads to 8 chars.
RRound-trip1234.5678Guarantees parse(format(x)) = x. Use for serialising doubles.
NumberFormats.vb — Visual Basic 2026
Dim n = 1234.5678

' Currency
n.ToString("C")       ' "RM 1,234.57"   (2 dp, culture symbol)
n.ToString("C0")      ' "RM 1,235"      (0 dp, rounded)
n.ToString("C4")      ' "RM 1,234.5678" (4 dp)

' Fixed-point
n.ToString("F")       ' "1234.57"
n.ToString("F0")      ' "1235"
n.ToString("F4")      ' "1234.5678"

' Number (with thousands separator)
n.ToString("N")       ' "1,234.57"
n.ToString("N0")      ' "1,235"

' Percent -- value is multiplied by 100 first
(0.1234).ToString("P")  ' "12.34%"
(0.1234).ToString("P1") ' "12.3%"
(0.1234).ToString("P0") ' "12%"

' Scientific
n.ToString("E")       ' "1.234568E+003"
n.ToString("E2")      ' "1.23E+003"
n.ToString("e4")      ' "1.2346e+003"   (lowercase e)

' General
n.ToString("G")       ' "1234.5678"  (shortest representation)
n.ToString("G4")      ' "1235"       (4 significant digits)
(0.000012345).ToString("G3")  ' "1.23E-05"  (switches to scientific)

' Integer formats
(42).ToString("D5")   ' "00042"  (zero-padded to 5 digits)
(255).ToString("X")   ' "FF"     (hexadecimal)
(255).ToString("X8")  ' "000000FF" (8-char hex, zero-padded)
Try It — Simulation 20.1: Number Format Explorer

Enter any number and choose a format specifier. See the VB call, the result, and a side-by-side comparison of all standard formats for the same value.

Number Format Explorer
Number:
Format specifier:

20.3 Custom Numeric Format Patterns

When the standard specifiers don't give enough control, use a custom pattern with special characters: 0 (digit or zero), # (digit or nothing), . (decimal point), , (thousands separator or scale), % (multiply by 100), E+0 (scientific), and ; (positive;negative;zero sections).

Pattern charMeaningExampleInput 1234.5
0Digit placeholder — always shows a digit (zero if absent)"00000.00""01234.50"
#Optional digit — nothing if absent"#,###.##""1,234.5"
.Decimal point"0.###""1234.5"
,Thousands separator (when between digits)"#,##0.00""1,234.50"
,, (after digits)Scale divisor by 1,000 per comma"0,,M""0M" (millionths)
%Multiply by 100 and append %"0.0%""123456.8%" (if input 1234.5)
; sectionspos;neg;zero patterns"#,##0.00;(#,##0.00);Zero"Pos / (Neg) / Zero
CustomPatterns.vb — Visual Basic 2026
Dim n = 1234.5

' 0 vs # placeholder
n.ToString("00000.00")   ' "01234.50"  -- 0 always shows digit
n.ToString("#,###.##")   ' "1,234.5"   -- # omits trailing zeros
n.ToString("#,##0.00")   ' "1,234.50"  -- standard accounting format

' Currency with RM prefix (no culture dependency)
n.ToString("'RM' #,##0.00")   ' "RM 1,234.50"

' Positive / negative / zero sections (separated by ;)
(1234.5).ToString("#,##0.00;(#,##0.00);-")    ' "1,234.50"  (positive)
(-1234.5).ToString("#,##0.00;(#,##0.00);-")   ' "(1,234.50)" (negative in parens)
(0).ToString("#,##0.00;(#,##0.00);-")         ' "-"          (zero as dash)

' Scale / k / M shorthand
(1500000).ToString("#,##0,K")    ' "1,500K"  (divide by 1,000)
(1500000).ToString("0,,M")        ' "2M"      (divide by 1,000,000)

' Phone number formatting (custom string logic)
Private Function FormatPhone(digits As String) As String
    Dim d = New String(digits.Where(Function(c) Char.IsDigit(c)).ToArray())
    If d.Length = 10 Then Return $"({d.Substring(0,3)}) {d.Substring(3,3)}-{d.Substring(6)}"
    If d.Length = 11 Then Return $"+{d(0)} ({d.Substring(1,3)}) {d.Substring(4,3)}-{d.Substring(7)}"
    Return digits     ' return as-is if unrecognised length
End Function

FormatPhone("0123456789")    ' "(012) 345-6789"
FormatPhone("60123456789")   ' "+6 (012) 345-6789"

20.4 Date and Time Formatting

Date formatting follows the same three-method pattern. Standard specifiers are single letters; custom patterns use tokens like dd, MM, yyyy, HH, mm, ss. Note that month is M/MM (capital) while minute is m/mm (lowercase).

SpecifierNameExample output
dShort date23/2/2026
DLong dateMonday, 23 February 2026
tShort time3:45 PM
TLong time3:45:22 PM
fFull (short time)Monday, 23 February 2026 3:45 PM
FFull (long time)Monday, 23 February 2026 3:45:22 PM
gGeneral (short)23/2/2026 3:45 PM
GGeneral (long)23/2/2026 3:45:22 PM
MMonth day23 February
YYear monthFebruary 2026
sSortable (ISO 8601)2026-02-23T15:45:22
uUniversal sortable2026-02-23 15:45:22Z
RRFC 1123Mon, 23 Feb 2026 15:45:22 GMT
DateFormats.vb — Visual Basic 2026
Dim dt = New DateTime(2026, 2, 23, 15, 45, 22)   ' 23 Feb 2026 15:45:22

' Standard specifiers
dt.ToString("d")   ' "23/02/2026"          short date
dt.ToString("D")   ' "Monday, 23 February 2026"  long date
dt.ToString("t")   ' "3:45 PM"             short time
dt.ToString("T")   ' "3:45:22 PM"          long time
dt.ToString("s")   ' "2026-02-23T15:45:22" ISO 8601 (sortable)
dt.ToString("g")   ' "23/02/2026 3:45 PM"  general short

' Custom patterns -- build exactly what you need
dt.ToString("dd/MM/yyyy")           ' "23/02/2026"
dt.ToString("dd-MMM-yyyy")          ' "23-Feb-2026"
dt.ToString("dddd, d MMMM yyyy")    ' "Monday, 23 February 2026"
dt.ToString("HH:mm:ss")             ' "15:45:22"   (24-hour)
dt.ToString("hh:mm tt")             ' "03:45 PM"   (12-hour)
dt.ToString("yyyy-MM-dd HH:mm")     ' "2026-02-23 15:45"   (database-friendly)
dt.ToString("d MMM yyyy 'at' h:mmtt") ' "23 Feb 2026 at 3:45PM"

' In interpolated strings
Dim now = DateTime.Now
lblTimestamp.Text = $"Saved at {now:HH:mm:ss} on {now:dd MMM yyyy}"
lblLog.Text       = $"[{now:yyyy-MM-dd HH:mm:ss.fff}] Application started"

' DateTime components -- use properties for individual parts
lblYear.Text  = now.Year.ToString()
lblMonth.Text = now.ToString("MMMM")         ' "February"
lblDay.Text   = now.ToString("dddd")          ' "Monday"
lblWeek.Text  = now.DayOfYear.ToString()        ' day number in year
Try It — Simulation 20.2: Date Format Explorer

Enter a date or use today. Choose a format specifier or type a custom pattern. See the VB code and output side by side, plus a comparison of every standard specifier.

Date Format Explorer
Date:
Format pattern:

20.5 String.Format — Alignment and Padding

String.Format supports an optional alignment component: {index,width:format}. A positive width right-aligns; a negative width left-aligns. This is essential for building aligned columns of text output.

StringFormat.vb — Visual Basic 2026
' {index,alignment:format}
' Positive alignment = right-align; Negative = left-align

' Right-align in a 10-character field
String.Format("{0,10}", "Name")     ' "      Name"  (6 spaces then "Name")
String.Format("{0,10:N2}", 1234.5)  ' "  1,234.50"  (right-aligned, 10 wide)

' Left-align
String.Format("{0,-15}", "Name")    ' "Name           " (padded right)

' Building a formatted table
Dim header = String.Format("{0,-20}{1,10}{2,10}{3,10}", "Item", "Qty", "Price", "Total")
lstReport.Items.Add(header)
lstReport.Items.Add(New String("-"c, 50))

Dim items() = {("Widget A", 5, 12.99), ("Gadget B", 2, 79.50), ("Donut C", 12, 2.50)}
For Each (name, qty, price) In items
    Dim total = qty * price
    lstReport.Items.Add(String.Format("{0,-20}{1,10}{2,10:C2}{3,10:C2}", name, qty, price, total))
Next

' Equivalent with interpolated strings ($ supports alignment too)
Dim name2 = "Widget A" : Dim qty2 = 5 : Dim price2 = 12.99
lstReport.Items.Add($"{name2,-20}{qty2,10}{price2,10:C2}{qty2*price2,10:C2}")

' PadLeft / PadRight on strings (simpler for basic padding)
"Name".PadLeft(10)          ' "      Name"
"Name".PadRight(10, "."c)   ' "Name......"
(42).ToString().PadLeft(5, "0"c)  ' "00042"
Try It — Simulation 20.3: Receipt & Report Builder

Add items to a shopping cart. The receipt is formatted entirely using String.Format with alignment, :C2 currency, and :N0 quantity columns.

Receipt Builder
Item name:
Qty:
Price (RM):

20.6 Interpolated Strings In Depth

Interpolation.vb — Visual Basic 2026
' Basic: $ prefix, {expression:format,alignment}
Dim name = "Alice" : Dim score = 92.5
$"Student: {name}, Score: {score:F1}"      ' "Student: Alice, Score: 92.5"
$"Score: {score,8:F2}"                       ' "Score:    92.50"  (right-aligned, 8 wide)

' Expressions inside braces -- any valid VB expression
Dim items = 5 : Dim unitPrice = 12.99
$"Total: {items * unitPrice:C2}"              ' "Total: RM64.95"
$"Tax (6%): {items * unitPrice * 0.06:C2}"   ' "Tax (6%): RM3.90"

' Ternary (If) inside interpolation
Dim balance = -250.0
$"Balance: {If(balance < 0, "(Overdrawn)", "")} {Math.Abs(balance):C2}"

' Calling methods inside braces
$"Hello, {name.ToUpper()}!"                  ' "Hello, ALICE!"
$"Today is {DateTime.Now:dddd, d MMMM yyyy}"  ' "Today is Monday, 23 February 2026"
$"Pi = {Math.PI:F6}"                         ' "Pi = 3.141593"

' Multi-line interpolated string (VB 2026 / C# 11 style)
Dim email = $"Dear {name},
Thank you for your order of {items} item(s).
Total charged: {items * unitPrice:C2}
Order date: {DateTime.Now:dd MMM yyyy}"

' Escape braces with {{ and }}
$"Format: {{0:C2}} produces {score:C2}"   ' "Format: {0:C2} produces RM92.50"

' Verbatim + interpolated: $@ or @$
$@"C:\Users\{name}\Documents"             ' "C:\Users\Alice\Documents" (no \\ needed)

20.7 Practical: Invoice Generator

InvoiceGenerator.vb — Visual Basic 2026
' Invoice number: INV-2026-0042
Private Function FormatInvoiceNum(year As Integer, seq As Integer) As String
    Return $"INV-{year}-{seq:D4}"    ' D4 zero-pads to 4 digits
End Function

FormatInvoiceNum(2026, 42)    ' "INV-2026-0042"
FormatInvoiceNum(2026, 1)     ' "INV-2026-0001"

' Build complete invoice as a formatted string
Private Function BuildInvoice(customer As String, subtotal As Decimal,
                                sstRate As Double) As String
    Dim sst   = Math.Round(subtotal * CDec(sstRate), 2)
    Dim total = subtotal + sst
    Dim now   = DateTime.Now

    Return $"{'─',-44}
INVOICE  {FormatInvoiceNum(now.Year, 42),30}
{'─',-44}
Date   : {now:dd MMM yyyy}
Bill To: {customer}
{'─',-44}
Subtotal  {subtotal,26:C2}
SST {sstRate:P0,-5}   {sst,26:C2}
{'═',-44}
TOTAL     {total,26:C2}
{'─',-44}"
End Function
Try It — Simulation 20.4: Format Pattern Playground

Experiment with custom numeric patterns. Type any pattern using 0, #, ,, ., %, and ; sections. See the result and the VB interpolated string call.

Format Pattern Playground
Value:
Pattern:
Try It — Simulation 20.5: Invoice Generator

Build a formatted invoice using String.Format alignment, interpolated strings, C2/P0/D4 format specifiers, and custom date patterns. Every piece of formatting is shown in the trace.

Invoice Generator
Customer name:
Invoice # (seq):
SST rate (%):

20.8 GitHub Copilot — Formatting Patterns

GitHub Copilot — Formatted Sales Report
You typed: ' Generate a formatted sales summary report to a ListBox. Include headers with String.Format alignment, currency totals with C2, date with "dd MMM yyyy", and a percentage change column.'
' Formatted sales report using String.Format alignment and number specifiers.
Private Sub GenerateSalesReport()
    lstReport.Items.Clear()

    Dim header = String.Format("{0,-20}{1,12}{2,12}{3,10}", "Product", "Sales", "Target", "Change")
    lstReport.Items.Add(header)
    lstReport.Items.Add(New String("-"c, 55))

    Dim rows = New List(Of (name As String, sales As Decimal, target As Decimal)) From {
        ("Widget A", 48200, 45000), ("Gadget B", 31500, 35000), ("Module C", 62000, 60000)
    }

    Dim grandTotal = 0D
    For Each row In rows
        Dim pct = CDbl(row.sales - row.target) / CDbl(row.target)
        Dim pctStr = $"{pct:+0.0%;-0.0%;0.0%}"
        lstReport.Items.Add(String.Format("{0,-20}{1,12:C0}{2,12:C0}{3,10}",
                                          row.name, row.sales, row.target, pctStr))
        grandTotal += row.sales
    Next

    lstReport.Items.Add(New String("="c, 55))
    lstReport.Items.Add(String.Format("{0,-20}{1,12:C0}", "TOTAL", grandTotal))
    lblDate.Text = $"Report generated: {DateTime.Now:dd MMM yyyy HH:mm}"
End Sub
GitHub Copilot — Log Formatter
You typed: ' Write a log formatter Sub that writes timestamped entries to a ListBox. Format: [yyyy-MM-dd HH:mm:ss.fff] [LEVEL] Message. Levels: INFO, WARN, ERROR.'
' Timestamped log formatter using interpolated string with date specifier.
Enum LogLevel
    INFO
    WARN
    ERROR
End Enum

Private Sub Log(message As String, Optional level As LogLevel = LogLevel.INFO)
    Dim ts    = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
    Dim entry = $"[{ts}] [{level,-5}] {message}"
    lstLog.Items.Add(entry)
    lstLog.SelectedIndex = lstLog.Items.Count - 1   ' auto-scroll

    ' Colour-code errors in red
    If level = LogLevel.ERROR Then
        lstLog.Items(lstLog.Items.Count - 1) = $"!!! {entry}"
    End If
End Sub

' Usage:
Log("Application started")
Log("Connection timeout, retrying", LogLevel.WARN)
Log("Database error: timeout after 30s", LogLevel.ERROR)
Copilot Chat Prompts for This Lesson

Try these in the Copilot Chat panel while working with formatting:

  • "Write a Function FormatFileSize(bytes As Long) As String that returns '1.23 MB', '456 KB' etc using String.Format with F2 and If..ElseIf thresholds"
  • "Create a table formatter Sub that takes a two-dimensional String array and formats it with String.Format alignment so columns line up in a ListBox"
  • "Build a Function FormatDuration(seconds As Integer) As String that returns '2h 15m 30s' or '45m 10s' or '30s' using interpolated strings"
  • "Generate a data export Sub that formats a List(Of Customer) as CSV using $\"{c.Name},{c.Total:F2},{c.Date:yyyy-MM-dd}\""

Lesson Summary

  • Three modern formatting approaches all use the same specifiers: value.ToString("C2"), String.Format("{0:C2}", value), and $"{value:C2}". Interpolated strings ($"...") are preferred in VB 2026 for readability.
  • Standard number specifiers: C currency, F fixed, N number with separator, P percent (×100 first!), E scientific, G general (shortest), D integer zero-pad, X hex. The digit after the letter controls decimal places or significant figures.
  • Custom numeric patterns use 0 (force digit), # (optional digit), , (thousands separator), . (decimal), % (×100), and three ;-separated sections for positive/negative/zero.
  • Date specifiers: d short, D long, t short time, T long time, s sortable ISO 8601. Custom patterns use dd/MM/yyyy (day/month/year) and HH:mm:ss (24-hour). Capital M = month; lowercase m = minute.
  • String.Format("{0,-20}{1,10:C2}", name, price) aligns columns: negative width = left-align, positive = right-align. Essential for building readable reports in ListBoxes.
  • Interpolated strings support full expressions {items * price:C2}, method calls {name.ToUpper()}, ternary expressions {If(x < 0, "(neg)", "")}, and verbatim paths $@"C:\Users\{name}".

Exercises

Exercise 20.1 — Number Format Dashboard

  • Build a form with a NumericUpDown for a value and radio buttons for format type
  • Display the same value in all 9 standard formats simultaneously using a ListBox
  • Add a TextBox for a custom pattern and show the result live on TextChanged
  • Include a negative/zero toggle to demonstrate the 3-section pos;neg;zero pattern
  • Copilot challenge: Ask Copilot to "add a culture selector (en-US, my-MY, de-DE) and reformat with the selected CultureInfo"

Exercise 20.2 — Date and Time Formatter

  • Build a form with a DateTimePicker and a ListBox showing all 13 standard date specifiers
  • Add a custom pattern TextBox — results update as you type
  • Show a countdown: days/hours/minutes until a user-selected future date using TimeSpan formatting
  • Display a table comparing the same date in 5 different format styles
  • Copilot challenge: Ask Copilot to "format the date in 10 different world locales using CultureInfo.GetCultureInfo()"

Exercise 20.3 — Sales Report Generator

  • Create a DataGridView with columns: Product, Units, Unit Price, Total, % of Grand Total
  • Format Unit Price and Total with C2, Units with N0, % with P1
  • Add a summary row: Grand Total formatted with C2 and bold
  • Export to a ListBox as aligned text using String.Format with column widths
  • Copilot challenge: Ask Copilot to "add a Print button that builds the report as a multiline string and sends it to a RichTextBox with monospace font"

Next: Lesson 21 — CheckBox Control

Learn to use CheckBox controls — reading the Checked property, handling CheckedChanged events, groups of checkboxes for multi-select options, and three-state checkboxes.

Continue »

Related Resources


Featured Books

Visual Basic 2022 Made Easy

Visual Basic 2022 Made Easy

by Dr. Liew Voon Kiong

Formatting functions applied throughout real-world examples including invoice, receipt, and report builders.

View on Amazon →
VB Programming With Code Examples

VB Programming With Code Examples

by Dr. Liew Voon Kiong

48 programs demonstrating currency, date, and table formatting in complete applications.

View on Amazon →