6.4 Creating & Applying Custom Formats with PROC FORMAT

Key Takeaways

  • PROC FORMAT creates custom value formats (VALUE), informats (INVALUE), and picture formats (PICTURE) to transform data display without altering underlying stored data values.
  • Character format names must begin with a dollar sign ($), cannot end in a period in the VALUE statement, and must not exceed 32 characters or end in a number.
  • The FMTLIB option displays a detailed catalog listing of all user-defined formats, their value ranges, and assigned labels in procedure output.
  • Custom formats can be exported to SAS datasets using CNTLOUT= and recreated from dataset control files using CNTLIN=, enabling portable format management.
  • In a FORMAT statement, a period (.) must be appended to the format name (e.g., format status $statfmt.;) to distinguish custom formats from dataset variables.
Last updated: August 2026

6.4 Creating & Applying Custom Formats with PROC FORMAT

In SAS programming, a fundamental architectural principle is the separation of stored data values from displayed formatted values. Raw data stored on disk (e.g., numeric codes 1, 2, 3 or raw dates 24103) should remain compact and un-mutated, while reports and summaries display human-readable text labels (e.g., 'North America', 'Europe', 'Asia' or '07AUG2026').

The PROC FORMAT procedure enables programmers to build custom user-defined formats, informats, and picture patterns. Formats facilitate continuous-to-categorical binning, data standardization, label mapping, and dynamic reporting without modifying the underlying dataset.

1. Fundamental Syntax & Format Types

PROC FORMAT supports three distinct user-defined structures:

  1. VALUE Statement: Maps stored data values (or value ranges) into formatted text labels for output display.
  2. INVALUE Statement: Defines informats to convert raw input strings into formatted values during data ingestion (INPUT statement or INPUT() function).
  3. PICTURE Statement: Defines custom templates for printing numeric data using digit masks (e.g., formatting 10-digit integers as phone numbers (###) ###-#### or Social Security Numbers).
PROC FORMAT <LIBRARY=libref<.catalog>> <options>;
    VALUE [$]format_name
        range-1 = 'label-1'
        range-2 = 'label-2'
        other   = 'default-label';
RUN;

2. Rules for Naming Custom Formats

Custom format names must comply with strict SAS naming rules. The Base exam frequently tests syntax errors arising from invalid format names:

RuleCharacter FormatsNumeric Formats
Prefix / Dollar SignMUST begin with a dollar sign ($).CANNOT begin with a dollar sign ($).
Maximum LengthUp to 32 characters (including $).Up to 32 characters.
Ending Semicolon/PeriodDo NOT include a period in PROC FORMAT.Do NOT include a period in PROC FORMAT.
Ending CharacterCannot end in a digit.Cannot end in a digit.
Reserved NamesCannot match built-in SAS format names (e.g., $CHAR, $HEX).Cannot match built-in SAS format names (e.g., DATE7, DOLLAR12).

Exam Tip: In PROC FORMAT, the format name must NEVER end with a period (e.g., value $genderfmt). However, when applying the format in a FORMAT statement or PUT() function, a period MUST be appended (e.g., format Gender $genderfmt.;).


3. Range Syntax & Mapping Operators in VALUE Statements

When binning numeric values or mapping strings, PROC FORMAT offers rich range specifications:

Range SyntaxMeaning / ExampleIncluded Values
Single Values / Lists1, 2, 3 = 'Low' or 'M', 'F' = 'Valid'Exact matching values
Continuous Range18 - 29 = 'Young Adult'Inclusive bounds ($18 \le x \le 29$)
Exclusive Bounds (<)18 -< 30 = '18 to 29' <br> 30 <- 50 = '31 to 50'18 -< 30 ($18 \le x < 30$)<br>30 <- 50 ($30 < x \le 50$)
Open-Ended KeywordsLOW - 17 = 'Minor' <br> 65 - HIGH = 'Senior'LOW includes all negative infinity up to 17. HIGH includes up to maximum value.
OTHER KeywordOTHER = 'Unknown / Invalid'Catches all values not explicitly covered by preceding ranges (including missing values unless handled).
/* Comprehensive PROC FORMAT example with numeric ranges and character maps */
proc format;
    /* Character format mapping */
    value $status_fmt
        'A' = 'Active'
        'I' = 'Inactive'
        'P' = 'Pending'
        other = 'Unassigned';
        
    /* Numeric range format with exclusive bounds and missing value handling */
    value age_group
        .     = 'Missing Age'
        low -< 18 = 'Under 18'
        18  -< 35 = '18 to 34'
        35  -< 65 = '35 to 64'
        65  - high = '65 and Older';
run;

4. Storing & Searching Permanent Format Catalogs (LIBRARY=, FMTSEARCH=)

By default, formats created in PROC FORMAT are stored in the temporary catalog WORK.FORMATS and vanish when the SAS session ends. To reuse formats across programs, save them to a permanent library catalog.

Creating Permanent Formats

libname myfmts 'C:\SAS_Formats';

proc format library=myfmts.company_formats;
    value $dept_fmt
        'HR' = 'Human Resources'
        'IT' = 'Information Technology'
        'FIN' = 'Finance';
run;

Accessing Permanent Formats with OPTION FMTSEARCH=

When SAS encounters a formatted variable in a DATA step or PROC step, it searches format catalogs in a specific sequence controlled by OPTIONS FMTSEARCH=:

/* Set search order: first check myfmts.company_formats, then WORK.FORMATS */
options fmtsearch=(myfmts.company_formats work);

data work.employee_report;
    set work.raw_employees;
    format Dept $dept_fmt. ;
run;

Exam Tip: WORK.FORMATS is always searched first unless explicitly included elsewhere in the FMTSEARCH= list.


5. Catalog Inspection (FMTLIB) & Control Datasets (CNTLIN= / CNTLOUT=)

Inspecting Formats with FMTLIB

The FMTLIB option prints a summary table of all format definitions contained in a catalog to the SAS procedure output, showing range start/end points, labels, and type.

proc format library=work.formats fmtlib;
run;

Creating Formats from Datasets (CNTLIN=) & Exporting (CNTLOUT=)

In large enterprise systems, lookup tables exist as database tables or SAS datasets rather than hardcoded code. PROC FORMAT can build formats dynamically from datasets using CNTLIN= or export catalogs using CNTLOUT=.

Required variables in a CNTLIN= dataset:

  • FMTNAME: Character string containing the format name (must include $ for character formats).
  • START: The starting value or range key.
  • END: The ending value or range key (optional if single value).
  • LABEL: The formatted text string to display.
  • TYPE: 'C' for character formats, 'N' for numeric formats, 'I' for informats.
/* Building a custom format dynamically from a lookup dataset */
/* Dataset work.lookup: FMTNAME='$codefmt', START='US', LABEL='United States', TYPE='C' */
proc format cntlin=work.lookup;
run;

6. Common Pitfalls & Exam Watchouts

  • Period Syntax Misplacement: Writing value $statusfmt. 'A'='Active'; inside PROC FORMAT generates a syntax error. Remove the period! Conversely, writing format Status $statusfmt; in a DATA step fails to apply the format because the trailing period is missing.
  • Format Name Ending in a Number: Defining a format named agefmt1 causes a compilation error because format names cannot end in a number.
  • Missing Format Catalog Error: Opening a dataset that references permanent formats without defining FMTSEARCH= or options nofmterror; produces ERROR: Format $DEPT_FMT not found or cannot be loaded.
Test Your Knowledge

Which of the following is a valid name for a user-defined character format created in a PROC FORMAT VALUE statement?

A
B
C
D
Test Your Knowledge

A programmer wants to create a numeric format named AGE_CAT where values from 18 up to but NOT including 30 display as 'Young Adult'. Which range syntax in PROC FORMAT correctly implements this exclusive upper bound?

A
B
C
D
Test Your Knowledge

A SAS programmer has a lookup table saved as a SAS dataset work.code_lookup containing variables FMTNAME, START, and LABEL. Which PROC FORMAT option uses this dataset to automatically construct user-defined formats without writing hardcoded VALUE statements?

A
B
C
D
Test Your Knowledge

A SAS DATA step contains the following statement to format the numeric variable Salary: format Salary dollar12.2 ; If the programmer later decides to apply a custom numeric format named SALARYFMT created via PROC FORMAT, how should the FORMAT statement be written?

A
B
C
D