quantity

pub.dev Dart CI codecov

Facilitates working with physical quantities such as angles, lengths, masses and temperatures.

In science and engineering it is critical to use units along with numerical values. For example, 5 meters per second is decidedly not the same speed as 5 feet per minute. Calculations must include units, implicitly or explicitly, to be correct and useful. This package provides classes for modeling quantities of specific types and their associated units as well as their use in calculations.

The International System of Units (often called 'SI' from its abbreviation in French) defines the quantity types, associated units and constants used by scientists and engineers around the world. This package models the SI base and derived quantities in its quantity_si library.

There are also many historical units, of course, that were around well before the SI came into existence. These can be found in the quantity_ext library.

The number library adds support for quantities having values of arbitrary precision and the quantity_range library adds special support for handling value ranges.

Together, these libraries give you the tools to maintain units discipline in your code and make Dart a more attractive option for many science and engineering applications by eliminating common mistakes and offering improved readability.

Quick Start

import 'package:quantity/quantity.dart';

// Construct quantities with named-parameter constructors.
final speed = Speed(metersPerSecond: 30);
final dist  = Length(m: 1500);
final time  = Time(s: 50);

// Full arithmetic with automatic type inference.
final computed = dist / time;          // returns a Speed
print(computed);                       // '30 m/s'

// Fluent extension syntax for quick one-liners.
final ang  = 270.degrees;
final ang2 = 1.1.radians;
print((ang - ang2).inDegrees);        // degrees as a plain double

// Parse a string directly into a typed Quantity.
final q = Quantity.parse('120 km/h');
print(q.runtimeType);                 // Speed
print(q.valueInUnits(Speed.metersPerSecond)); // ~33.33

// Serialize to / from JSON.
final json  = q.toJson();
final back  = Quantity.fromJson(json);

Key Features

Core

  • 75+ typed quantities (Length, Mass, Temperature, Speed, Force, …) that are easy to construct and use in arithmetic — the correct result type is inferred automatically.
  • Encourages SI discipline by isolating non-standard units in a separate extension library.
  • Relative standard uncertainty is propagated through calculations automatically.
  • Arbitrary precision via the Precise number type (as well as complex and imaginary values).
  • Official NIST constants — current CODATA values are available as typed const objects and can be refreshed with dart run bin/update_nist_constants.dart.
  • Metric prefix support on every unit (unit.milli(), unit.kilo(), …).
  • MiscQuantity for untyped quantities with unusual dimensions.
  • Mutable quantities with streams for reactive applications.
  • Duration / DateTime integration — convert between Dart time types and Time / TimeInstant seamlessly.

String Parsing (Quantity.parse)

Convert a plain string into a fully typed Quantity — ideal for reading user input, AI responses, or configuration files.

Quantity.parse('5 m')          // → Length(5 m)
Quantity.parse('500 mg')       // → Mass(0.0005 kg)
Quantity.parse('9.8 m/s^2')   // → Acceleration
Quantity.parse('10 kg*m/s^2') // → Force (10 N)
Quantity.parse('15 N·m')      // → Torque
Quantity.parse('120 km / h')  // spaces around / and ^ are fine
Quantity.parse('5m')          // no space between value and unit is fine too

Supported features:

  • SI base and derived units plus common non-SI units (ft, in, lb, mph, …)
  • All SI metric prefixes (k, M, G, m, µ, n, …)
  • Compound units with /, * and ^ (e.g. kg*m/s^2, m/s^2)
  • Liberal whitespace handling — spaces around operators are normalised automatically
  • Falls back to MiscQuantity for valid-but-unregistered dimension combinations

Unit Conversion (.to() / .valueInUnits())

final speed = Speed(metersPerSecond: 30);
print(speed.valueInUnits(Speed.kilometersPerHour)); // 108.0

final mass = Mass(kg: 1);
print(mass.valueInUnits(poundsAvoirdupois));        // ~2.205

Use Quantity.getUnitSymbols(Speed) to discover which symbol strings are accepted by Quantity.parse for a given type:

Quantity.getUnitSymbols(Speed);        // ['km/h', 'm/s', 'mph', …]
Quantity.getUnitSymbols(Acceleration); // ['m/s^2', …]

Serialization (toJson / fromJson)

Every Quantity can round-trip through JSON:

final length = Length(m: 42.0, uncert: 0.01);
final json   = length.toJson();
// {'type': 'Length', 'value': {'type': 'Double', 'value': '42.0'},
//  'dimensions': {'Length': 1}, 'uncertainty': 0.01}

final restored = Quantity.fromJson(json); // → Length(42 m)

Retrieve the JSON Schema describing the format (useful for LLM tool definitions):

final schema = Quantity.jsonSchema; // Map<String, dynamic> JSON Schema object

AI / LLM Integration

Several utilities make it straightforward to use this library as a tool for an AI assistant.

Quantity.parse — accept natural-language unit strings

LLMs frequently output values such as "120 km/h" or "9.8 m/s²". Feed them directly to Quantity.parse and get a strongly typed result.

Quantity.checkDimensionalConsistency — validate formulas

Check whether a symbolic formula is dimensionally correct before evaluating it:

final vars = {
  's': Length.lengthDimensions,
  'u': Speed.speedDimensions,
  't': Time.timeDimensions,
  'a': Acceleration.accelerationDimensions,
};

Quantity.checkDimensionalConsistency(vars, 's = u*t + 0.5*a*t^2'); // true
Quantity.checkDimensionalConsistency(vars, 's = u*t + a');          // false

Dimensions.describe — human-readable dimension strings

Dimensions.describe(Speed.speedDimensions);        // 'Length^1 / Time^1'
Dimensions.describe(Acceleration.accelerationDimensions); // 'Length^1 / Time^2'
Dimensions.describe(Dimensions());                 // 'dimensionless'

Quantity.jsonSchema — expose your tool signature to an LLM

Pass Quantity.jsonSchema directly as the JSON Schema for a function parameter so the model knows exactly how to produce a valid serialized quantity.

New Quantity Types

Type Dimensions Typical use
Token custom (dimensionless-like) LLM token counts
TokenRate Token / Time tokens per second
Pixel custom screen pixel counts
Resolution Pixel / Length DPI / PPI
PixelDensity Pixel / Area pixels per m²
Torque Energy (distinct from Energy by semantics) rotational force

All new types are fully integrated with Quantity.parse and Quantity.getUnitSymbols.

Quantity.parse('1024 tokens');  // → Token
Quantity.parse('512 tps');      // → TokenRate
Quantity.parse('1920 px');      // → Pixel
Quantity.parse('96 ppi');       // → Resolution

Fluent Extensions

Import package:quantity/quantity.dart (or package:quantity/quantity_ext.dart) to get extension getters on num for concise quantity construction:

// Construction
30.0.metersPerSecond    // Speed
9.8.metersPerSecondSquared  // Acceleration
100.kilograms           // Mass
37.celsius              // Temperature
500.milliseconds        // Time
1920.pixels             // Pixel
4096.tokens             // Token

// Reading back (in* getters)
Length(m: 1).inCentimeters          // 100.0
Time(s: 86400).inDays               // 1.0
Speed(metersPerSecond: 10).inKilometersPerHour // 36.0
Mass(kg: 0.45359237).inPounds       // ~1.0
Angle(rad: pi).inDegrees            // 180.0

Quantity Ranges

The quantity_range library provides QuantityRange<T> and a specialised AngleRange:

// Basic range
final r = QuantityRange<Length>(Length(m: 10), Length(m: 20));
print(r.span);        // 10 m
print(r.centerValue); // 15 m

// Angle range with wrap-around awareness
final arc = AngleRange.degrees(350, 30);
arc.overlaps360(AngleRange.degrees(10, 45)); // true
arc.contains360(Angle(deg: 5));              // true
arc.ranges360;      // splits into [350°,360°] ∪ [0°,30°]

// AngleRange operations
arc.deriveRange(rotate: 45.0);  // rotate the arc
arc.deriveRange(scale: 2.0);    // grow/shrink about center
arc.deriveRange(reverse: true); // flip direction
arc.angleClosestTo(Angle(deg: 180)); // nearest endpoint

TimePeriod provides analogous support for time ranges, with integration into Dart's Duration and DateTime.

Library Structure

Import Contents
package:quantity/quantity.dart Everything — recommended for most apps
package:quantity/quantity_core.dart Tree-shakeable core (no ext units/constants)
package:quantity/quantity_si.dart SI quantities and units only
package:quantity/quantity_ext.dart Non-SI units, fluent extensions, ranges, mutable
package:quantity/number.dart Number types only (Integer, Double, Precise, Complex)
package:quantity/quantity_range.dart Range classes only

Examples

import 'package:quantity/quantity.dart';

void main() {
  // ---------- Arithmetic ----------
  final v0   = Speed(metersPerSecond: 0);
  final a    = Acceleration(metersPerSecondSquared: 9.8);
  final t    = Time(s: 3.0);

  // v = v0 + a*t
  final v = v0 + a * t as Speed;
  print(v); // '29.4 m/s'

  // ---------- Parsing ----------
  final force  = Quantity.parse('10 N');
  final torque = Quantity.parse('15 N·m');
  print(force.runtimeType);  // Force
  print(torque.runtimeType); // Torque

  // ---------- Uncertainty ----------
  final measured = Length(m: 100.0, uncert: 0.02); // 2% relative uncertainty
  print(measured.relativeUncertainty);              // 0.02
  print(measured.standardUncertainty);              // Length(2 m)

  // ---------- Angle math ----------
  final heading = AngleRange.degrees(315, 45); // NW to NE, crossing North
  print(heading.contains360(Angle(deg: 0)));   // true (due North is inside)
  print(heading.contains360(Angle(deg: 180))); // false (South is outside)
}

NIST Constants

All fundamental physical constants are available as const typed quantities. They are kept in sync with the official CODATA release:

import 'package:quantity/quantity.dart';

// Universal constants
print(speedOfLightVacuum);           // Speed ~ 2.998e8 m/s
print(planckConstant);               // ~ 6.626e-34 J·s
print(elementaryCharge);             // ~ 1.602e-19 C
print(boltzmannConstant);            // ~ 1.381e-23 J/K
print(gravitationalConstant);        // ~ 6.674e-11 m³/kg/s²

// Refresh to latest NIST CODATA values:
// dart run bin/update_nist_constants.dart

Quality

  • 100% code coverage — every line of library code is exercised by the test suite.
  • Zero analyzer warningsdart analyze --fatal-infos passes cleanly.
  • Formatteddart format is enforced by CI.
  • All four pre-commit checks (formatanalyzetestverify_coverage) run automatically in GitHub Actions on every push.

Libraries

domain/acoustics
Quantity types, units and constants commonly encountered in acoustics.
domain/astronomical
Quantity types, units and constants commonly encountered in the field of Astronomy and related sciences.
domain/atomic_nuclear
Quantity types, units and constants commonly encountered in the fields of atomic, molecular, and nuclear physics.
domain/chemistry
Quantity types, units and constants commonly encountered in the field of chemistry.
domain/computing
Quantity types, units and constants commonly encountered in computing, information theory, and digital layouts.
domain/electromagnetic
Quantity types, units and constants commonly encountered in the fields dealing with
domain/fluid_dynamics
Quantity types, units and constants commonly encountered in fluid dynamics and hydraulics.
domain/radiometry
Quantity types, units and constants commonly encountered in the fields of radiometry and photometry.
domain/thermodynamic
Quantity types, units and constants commonly encountered in the field of
domain/universal
Quantity types and constants with universal application.
number
The quantity package accepts both Dart's num types and the Numbers defined by this
quantity
A superset of all the other libraries available in the quantity package.
quantity_core
Core library containing only core dimensions, units, numbers and quantity engine classes.
quantity_ext
Extends the core library with non-SI units, constants, unit synonyms to enable terse
quantity_range
Models ranges of quantities with start and end values (not necessarily increasing).
quantity_si
The core library containing the fundamental
range/angle_range
range/quantity_range
range/time_period