The NM (Numeric) data type has existed since HL7 v2.1 and represents a signed decimal number. It is the underlying type for every numeric field in v2: lab result values when OBX-2 is NM, BUI-4 / BUI-6 weight and volume on blood units, DON-5 donation duration, OBR ordering quantities, and many financial amounts. It never carries units of its own — units always live in an adjacent field.
Purpose
NM holds a single numeric value as a sequence of decimal digits with an optional leading sign and optional fractional part. The receiver is expected to parse it as a real number; precision is implicit in the textual representation, which makes NM both simple and slightly treacherous.
Format and constraints
NM is a primitive: no components, no sub-components.
- Allowed characters: digits
0–9, an optional leading+or-, and at most one.as the decimal separator. - No thousands separators (
1,234.5is invalid; send1234.5). - No scientific or exponential notation (
1.2E3is invalid). - No embedded whitespace.
- The decimal point is locale-independent and is always
., regardless of the sender's locale. - Trailing zeros after the decimal point are significant —
1.50communicates two decimal places of precision;1.5does not. - Length: historically 1..16 in v2.5 and earlier; v2.7 deprecated fixed maximum lengths in favour of conformance-profile constraints.
- An empty field is null;
0and0.0are explicit zeros and not equivalent to null.
Where it's used
NM appears as a bare field type and as a primitive component inside many composites:
- OBX-5 Observation Value when OBX-2 =
NM— a numeric result like a serum sodium. - BUI-4 Blood Unit Weight and BUI-6 Blood Unit Volume — see BUI.
- DON-5 Donation Duration and DON-30 Number of Tubes Collected — see DON.
- OBR-9 Collection Volume (CQ → NM) — quantity of specimen.
- PID-25 Birth Order — sibling order for multiple births.
- PV1-19 Visit Number numeric variants and PV1-43 Birth Order in some implementations.
- TQ1-2.1 Quantity (CQ → NM) — dose count.
- Financial amounts inside FT1, BLG, and IN1 composites (MO → NM via component access).
Version differences
- v2.1 through v2.6: NM defined with a recommended 1..16 length.
- v2.7: fixed maximum length deprecated; length now governed by conformance profile.
- v2.7.1, v2.8, v2.8.1, v2.8.2: no changes to the type. The canonical lexical form (digits, optional sign, optional
.) has been unchanged since v2.1.
Common mistakes
- Sending thousands separators (
1,234) — fails parsing on any conforming engine. - Sending scientific notation (
1.2e3) — explicitly disallowed. - Sending a comma decimal point (
1,5) — NM is always., regardless of locale. - Stripping trailing zeros during normalization —
2.0and2.00carry different precision and lab interpretation rules often care. - Conflating null and zero. An empty NM field means "not reported";
0is a measured value of zero. Collapsing them loses clinical meaning.
Examples
Minimal:
142
Decimal with explicit precision:
4.50
Negative value (e.g. base excess on a blood gas):
-2.3
Explicit positive sign:
+98.6
In context — OBX-5 carrying an NM serum sodium result:
OBX|1|NM|2951-2^Sodium [Moles/volume] in Serum or Plasma^LN||142|mmol/L^millimole per liter^UCUM|135-145|N|||F
In context — BUI-6 numeric volume paired with BUI-7 units:
BUI|1|W123426789012^^^RedCrossBB^DIN|E0336^RBC LR^HL70435|312|g^gram^UCUM|285|mL^milliliter^UCUM
Common pitfalls:
WRONG: OBX|1|NM|GLU^Glucose^L||1,250|mg/dL|...
Thousands separator is invalid in NM. Send `1250`.
RIGHT: OBX|1|NM|GLU^Glucose^L||1250|mg/dL|...
FHIR mapping
A primitive's FHIR target is dictated by the containing element. The v2-to-FHIR IG publishes:
- NM → Quantity — the canonical mapping when an adjacent units field exists (NM + CWE/CNE units →
Quantity.value+Quantity.unit/Quantity.code). - NM → positiveInt — used when the containing element is a strictly positive integer (set IDs, counts).
- NM →
decimalorinteger— the default when the FHIR target is a bare numeric primitive.
The accompanying units field on the v2 side is what decides whether the FHIR target is Quantity or a plain numeric primitive.
Engine considerations
- Parse with a locale-independent decimal parser. Java's
BigDecimal(String)or .NET'sdecimal.Parse(s, CultureInfo.InvariantCulture)are appropriate;Double.parseDoubleloses precision. - Preserve trailing zeros — store the original lexical form alongside the parsed value so that round-trip emission keeps the sender's precision.
- Distinguish null from zero throughout the model; many EHRs treat them very differently for reference-range evaluation.
- Reject thousands separators and scientific notation at ingress; auto-coercing them masks upstream encoding bugs.
- Watch for whitespace-padded values from legacy mainframes (
142) — strip outside whitespace, never inside, and log the cleanup.
How Vorro parses and produces NM
Vorro parses NM using a strict invariant-culture decimal parser and retains both the original lexical string and a BigDecimal value. Trailing zeros are preserved in the model so that lab precision is not silently widened or narrowed on egress. Empty NM fields are surfaced as a typed null distinct from a measured zero; downstream rules engines that care about reference ranges receive both signals.
On outbound, Vorro emits NM in its canonical lexical form: optional - for negatives, no thousands separators, a . decimal point, and exactly the precision carried in the source. Locale-specific formatters are never used at the wire boundary, which prevents the classic European-locale bug where 4,50 slips into a downstream field.
Related pages
- SN data type — Structured Numeric
- CQ data type — Composite Quantity with Units
- NR data type — Numeric Range
