A PHP 8.4+ framework-agnostic package for converting between 2,216 units of measurement based on UN/CEFACT Recommendation 20, Recommendation 21 (package types), and the GS1 unit conversion model.
Uses arbitrary-precision math (bcmath) with the GS1 multiplier + offset formula to handle both linear conversions (mass, length, volume, etc.) and non-linear ones (temperature).
- PHP 8.4+
- ext-bcmath
composer require kolaybi/unit-converteruse KolayBi\UnitConverter\Converter;
use KolayBi\UnitConverter\Units\Mass;
use KolayBi\UnitConverter\Units\Temperature;
// Using enum cases
$result = Converter::convert(10)->from(Mass::Kilogram)->to(Mass::Pound);
echo $result->round(2); // "22.05"
// Using UN/CEFACT codes
$result = Converter::convert(1)->from('KGM')->to('LBR');
echo $result->toFloat(); // 2.20462262...
// Using symbols
$result = Converter::convert(100)->from('°C')->to('°F');
echo $result->round(1); // "212.0"
// Using labels
$result = Converter::convert(1)->from('kilogram')->to('gram');
echo $result->value; // "1000.00000000000000000000"
// Default value is 1 — handy for conversion factors
$result = Converter::convert()->from(Mass::Kilogram)->to(Mass::Pound);
echo $result->round(6); // "2.204623"Entry point. Accepts any numeric value. Defaults to 1, useful for looking up conversion factors.
Set the source unit. Accepts an enum case, UN/CEFACT code, symbol, or label.
Convert to the target unit and return the result.
Resolve a unit by UN/CEFACT code, symbol, or label. Returns the Unit enum case.
$unit = Converter::unit('kg');
$unit->code(); // 'KGM'
$unit->symbol(); // 'kg'
$unit->label(); // 'kilogram'Convert to all other units in the same category. Returns an array keyed by UN/CEFACT code.
$result->value; // Full-precision string
$result->toFloat(); // PHP float
$result->round(2); // "22.05"
$result->format(2, ',', '.'); // "1.234,57"
(string) $result; // Same as ->value
$result->from; // Source Unit enum
$result->to; // Target Unit enum58 categories covering 2,216 units (780 convertible + 1,436 non-convertible):
| Category | Units | Category | Units |
|---|---|---|---|
| Absorbed Dose | 4 | Kinematic Viscosity | 7 |
| Absorbed Dose Rate | 11 | Length | 34 |
| Acceleration | 11 | Luminous Intensity | 3 |
| Amount of Substance | 4 | Magnetic Flux | 3 |
| Angle | 9 | Magnetic Flux Density | 6 |
| Angular Impulse | 3 | Magnetic Vector Potential | 3 |
| Angular Velocity | 4 | Mass | 34 |
| Area | 20 | Memory Capacity | 15 |
| Capacitance | 7 | Molar Concentration | 5 |
| Charge | 13 | Molar Mass | 2 |
| Conductance | 7 | Molar Thermodynamic Energy | 2 |
| Counting | 14 | Molar Volume | 4 |
| Current | 9 | Package Type ⊘ | 406 |
| Data Rate | 12 | Packaging ⊘ | 52 |
| Density | 28 | Power | 44 |
| Dimensionless Concentration | 24 | Pressure | 42 |
| Dynamic Viscosity | 19 | Radioactivity | 9 |
| Effective Dose | 4 | Resistance | 8 |
| Effective Dose Rate | 13 | Signal Rate | 3 |
| Energy | 34 | Specific Volume | 7 |
| Energy Density | 7 | Speed | 23 |
| Exposure | 2 | Temperature | 4 |
| Flow Rate | 93 | Textile Density | 3 |
| Force | 15 | Time | 18 |
| Frequency | 10 | Torque | 16 |
| Illuminance | 6 | Trade ⊘ | 978 |
| Impulse | 6 | Voltage | 6 |
| Inductance | 6 | Volume | 66 |
| Irradiance | 14 | Wavenumber | 4 |
⊘ = non-convertible (code resolution only)
406 package types from UNECE Recommendation 21 (Rev. 12) are available via the PackageType enum.
Per Rec 20 guidance, each 2-character Rec 21 code is prefixed with X to form a 3-character unit-of-measure code (reserved range X00–XZZ). The native Rec 21 code is also available as an alias.
use KolayBi\UnitConverter\Converter;
use KolayBi\UnitConverter\Units\PackageType;
// Using X-prefixed code
$unit = Converter::unit('XBG'); // PackageType::Bag
$unit->code(); // 'XBG'
$unit->rec21Code(); // 'BG'
$unit->label(); // 'bag'
// Using label
$unit = Converter::unit('aerosol'); // PackageType::Aerosol (code: XAE)
// Using enum case directly
$unit = PackageType::DrumSteel; // code: X1AResolution priority: When a Rec 21 native code conflicts with a Rec 20 code (23 shared codes like
BG,DR,TU), Rec 20 takes priority. Use the X-prefixed code to explicitly target the Rec 21 entry.
Units can be resolved by:
- Enum case:
Mass::Kilogram - UN/CEFACT code:
'KGM'(case-sensitive) - Symbol:
'kg'(case-insensitive) - Label:
'kilogram'(case-insensitive)
// All equivalent
Converter::convert(1)->from(Mass::Kilogram)->to(Mass::Pound);
Converter::convert(1)->from('KGM')->to('LBR');
Converter::convert(1)->from('kg')->to('lb');
Converter::convert(1)->from('kilogram')->to('pound');use KolayBi\UnitConverter\Exceptions\IncompatibleUnitsException;
use KolayBi\UnitConverter\Exceptions\NonConvertibleUnitException;
use KolayBi\UnitConverter\Exceptions\UnitNotFoundException;
// Incompatible categories
Converter::convert(1)->from(Mass::Kilogram)->to(Temperature::Celsius);
// throws IncompatibleUnitsException
// Non-convertible units (packaging)
Converter::convert(1)->from(Packaging::Box)->to(Packaging::Bag);
// throws NonConvertibleUnitException
// Unknown unit string
Converter::convert(1)->from('not_a_real_unit')->to('abc');
// throws UnitNotFoundExceptionAll convertible units use the GS1 multiplier + offset model relative to a base unit per category:
base_value = input_value × multiplier + offset
output_value = (base_value - target_offset) ÷ target_multiplier
For most categories (mass, length, volume, etc.), the offset is 0, making it a simple ratio. Temperature uses non-zero offsets to handle Celsius (offset 273.15) and Fahrenheit (multiplier 5/9, offset 255.37).
All math uses bcmath with a scale of 20 decimal places.
The convertible unit enums are generated from the GS1 datatable:
php bin/generate-enums.php [path-to-json]composer install
vendor/bin/phpunit # Run tests
vendor/bin/phpstan analyse # Static analysis (level 9)
vendor/bin/pint # Code stylePlease see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please see License File for more information.