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.
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);- 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
Precisenumber type (as well as complex and imaginary values). - Official NIST constants — current CODATA values are available as typed
constobjects and can be refreshed withdart run bin/update_nist_constants.dart. - Metric prefix support on every unit (
unit.milli(),unit.kilo(), …). MiscQuantityfor untyped quantities with unusual dimensions.- Mutable quantities with streams for reactive applications.
Duration/DateTimeintegration — convert between Dart time types andTime/TimeInstantseamlessly.
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 tooSupported 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
MiscQuantityfor valid-but-unregistered dimension combinations
final speed = Speed(metersPerSecond: 30);
print(speed.valueInUnits(Speed.kilometersPerHour)); // 108.0
final mass = Mass(kg: 1);
print(mass.valueInUnits(poundsAvoirdupois)); // ~2.205Use 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', …]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 objectSeveral utilities make it straightforward to use this library as a tool for an AI assistant.
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.
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'); // falseDimensions.describe(Speed.speedDimensions); // 'Length^1 / Time^1'
Dimensions.describe(Acceleration.accelerationDimensions); // 'Length^1 / Time^2'
Dimensions.describe(Dimensions()); // 'dimensionless'Pass Quantity.jsonSchema directly as the JSON Schema for a function parameter so the model
knows exactly how to produce a valid serialized quantity.
| 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'); // → ResolutionImport 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.0The 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 endpointTimePeriod provides analogous support for time ranges, with integration into Dart's
Duration and DateTime.
| 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 |
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)
}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- 100% code coverage — every line of library code is exercised by the test suite.
- Zero analyzer warnings —
dart analyze --fatal-infospasses cleanly. - Formatted —
dart formatis enforced by CI. - All four pre-commit checks (
format→analyze→test→verify_coverage) run automatically in GitHub Actions on every push.