Converting Measurements in Delphi

The ConvUtils unit declares a general-purpose Convert function that you can use to convert a measurement from one set of units to another. You can perform conversions between compatible units of measurement such as feet and inches or days and weeks. Units that measure the same types of things are said to be in the same conversion family.

The units you’re converting must be in the same conversion family. The StdConvs unit defines several conversion families and measurement units within each family. In addition, you can create customized conversion families and associated units using the RegisterConversionType and RegisterConversionFamily functions.

You can use the Convert function to perform both simple and complex conversions. It includes a simple syntax and a second syntax for performing conversions between complex measurement types. You can use the Convert function to convert a measurement from one set of units to another.

The Convert function converts between units that measure the same type of thing (distance, area, time, temperature, and so on). To use Convert, you must specify the units from which to convert and to which to convert. You use the TConvType type to identify the units of measurement.

For example, this converts a temperature from degrees Fahrenheit to degrees Kelvin:

TempInKelvin := Convert(StrToFloat(Edit1.Text), tuFahrenheit, tuKelvin);

You can also use the Convert function to perform more complex conversions between the ratio of two measurement types. Examples of when you might need to use this this are when converting miles per hour to meters per minute for calculating speed or when converting gallons per minute to liters per hour for calculating flow.

For example, the following call converts miles per gallon to kilometers per liter:

nKPL := Convert(StrToFloat(Edit1.Text), duMiles, vuGallons, duKilometers, vuLiter);

The units you’re converting must be in the same conversion family (they must measure the same thing). If the units are not compatible, Convert raises an EConversionError exception. You can check whether two TConvType values are in the same conversion family by calling CompatibleConversionTypes.

If you want to perform conversions between measurement units not already defined in the StdConvs unit, you need to create a new conversion family to represent the measurement units (TConvType values). When two TConvType values are registered with the same conversion family, the Convert function can convert between measurements made using the units represented by those TConvType values.

You first need to obtain TConvFamily values by registering a conversion family using the RegisterConversionFamily function. After you get a TConvFamily value (by registering a new conversion family or using one of the global variables in the StdConvs unit), you can use the RegisterConversionType function to add the new units to the conversion family.

One example of when you could create a new conversion family and add new measurement types might be when performing conversions between long periods of time (such as months to centuries) where a loss of precision can occur. To explain this further, the cbTime family uses a day as its base unit.

The base unit is the one that is used when performing all conversions within that family. Therefore, all conversions must be done in terms of days. An inaccuracy can occur when performing conversions using units of months or larger (months, years, decades, centuries, millennia) because there is not an exact conversion between days and months, days and years, and so on.

Months have different lengths; years have correction factors for leap years, leap seconds, and so on. If you are only using units of measurement greater than or equal to months, you can create a more accurate conversion family with years as its base unit. This example creates a new conversion family called cbLongTime.

First, you need to declare variables for the identifiers. The identifiers are used in the new LongTime conversion family, and the units of measurement that are its members:

var cbLongTime: TConvFamily; ltMonths: TConvType; ltYears: TConvType; ltDecades: TConvType; ltCenturies: TConvType; ltMillennia: TConvType;

Next, register the conversion family:

cbLongTime := RegisterConversionFamily (‘Long Times’);

Although an UnregisterConversionFamily procedure is provided, you don’t need to unregister conversion families unless the unit that defines them is removed at runtime. They are automatically cleaned up when your application shuts down.

you just created. You use the RegisterConversionType function, which registers units of measurement within a specified family. You need to define the base unit which in the example is years, and the other units are defined using a factor that indicates their relation to the base unit.

So, the factor for ltMonths is 1/12 because the base unit for the LongTime family is years. You also include a description of the units to which you are converting. The code to register the measurement units is shown here:

ltMonths:=RegisterConversionType(cbLongTime,‘Months’,1/12); ltYears:=RegisterConversionType(cbLongTime,’Years’,1); ltDecades:=RegisterConversionType(cbLongTime,’Decades’,10); ltCenturies:=RegisterConversionType(cbLongTime,’Centuries’,100); ltMillennia:=RegisterConversionType(cbLongTime,’Millennia’,1000);

You can now use the newly registered units to perform conversions. The global Convert function can convert between any of the conversion types that you registered with the cbLongTime conversion family. So instead of using the following Convert call,

Convert(StrToFloat(Edit1.Text),tuMonths,tuMillennia);

you can now use this one for greater accuracy:

Convert(StrToFloat(Edit1.Text),ltMonths,ltMillennia);

For cases when the conversion is more complex, you can use a different syntax to specify a function to perform the conversion instead of using a conversion factor. For example, you can’t convert temperature values using a conversion factor, because different temperature scales have a different origins.