diff --git a/Common/UnitDefinitions/Temperature.json b/Common/UnitDefinitions/Temperature.json index 4bbf2a513e..732b744b3e 100644 --- a/Common/UnitDefinitions/Temperature.json +++ b/Common/UnitDefinitions/Temperature.json @@ -2,7 +2,6 @@ "Name": "Temperature", "BaseUnit": "Kelvin", "XmlDoc": "A temperature is a numerical measure of hot or cold. Its measurement is by detection of heat radiation or particle velocity or kinetic energy, or by the bulk behavior of a thermometric material. It may be calibrated in any of various temperature scales, Celsius, Fahrenheit, Kelvin, etc. The fundamental physical definition of temperature is provided by thermodynamics.", - "GenerateArithmetic": false, "BaseDimensions": { "Θ": 1 }, @@ -104,4 +103,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/UnitsNet.Tests/CustomCode/TemperatureDeltaTests.cs b/UnitsNet.Tests/CustomCode/TemperatureDeltaTests.cs index a4f51502d4..76e516ed47 100644 --- a/UnitsNet.Tests/CustomCode/TemperatureDeltaTests.cs +++ b/UnitsNet.Tests/CustomCode/TemperatureDeltaTests.cs @@ -1,9 +1,9 @@ //------------------------------------------------------------------------------ // // This code was generated (once) by \generate-code.bat, but will not be -// regenerated when it already exists. The purpose of creating this file is to make +// regenerated when it already exists. The purpose of creating this file is to make // it easier to remember to implement all the unit conversion test cases. -// +// // Whenever a new unit is added to this unit class and \generate-code.bat is run, // the base test class will get a new abstract property and cause a compile error // in this derived class, reminding the developer to implement the test case @@ -19,17 +19,17 @@ // Copyright (c) 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). // https://github.com/angularsen/UnitsNet -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -38,6 +38,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using System.Globalization; +using UnitsNet.Units; using Xunit; namespace UnitsNet.Tests.CustomCode @@ -59,5 +61,24 @@ public void TemperatureDeltaTimesSpecificEntropyEqualsSpecificEnergy() SpecificEnergy specificEnergy = SpecificEntropy.FromJoulesPerKilogramKelvin(10) * TemperatureDelta.FromKelvins(6); Assert.Equal(specificEnergy, SpecificEnergy.FromJoulesPerKilogram(60)); } + + [Theory] + [InlineData(TemperatureUnit.DegreeCelsius, 30, 20, "10 ∆°C")] + [InlineData(TemperatureUnit.DegreeCelsius, 20, 30, "-10 ∆°C")] + [InlineData(TemperatureUnit.DegreeFahrenheit, 30, 20, "10 ∆°F")] + [InlineData(TemperatureUnit.DegreeFahrenheit, 20, 30, "-10 ∆°F")] + [InlineData(TemperatureUnit.Kelvin, 30, 20, "10 ∆K")] + [InlineData(TemperatureUnit.Kelvin, 20, 30, "-10 ∆K")] + public void FromTemperatures_ReturnsDeltaOfTheTwoTemperaturesInLeftUnit(TemperatureUnit unit, int value, int otherValue, string expected) + { + Temperature temperature = Temperature.From(value, unit); + Temperature otherTemperature = Temperature.From(otherValue, unit); + + // Act + var delta = TemperatureDelta.FromTemperatures(temperature, otherTemperature); + + // Assert + Assert.Equal(expected, delta.ToString(CultureInfo.InvariantCulture, "{0:0} {1}")); + } } } diff --git a/UnitsNet.Tests/CustomCode/TemperatureTests.cs b/UnitsNet.Tests/CustomCode/TemperatureTests.cs index 0aa5f9d234..a923721e86 100644 --- a/UnitsNet.Tests/CustomCode/TemperatureTests.cs +++ b/UnitsNet.Tests/CustomCode/TemperatureTests.cs @@ -1,16 +1,16 @@ // Copyright (c) 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). // https://github.com/angularsen/UnitsNet -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -45,46 +45,6 @@ public class TemperatureTests : TemperatureTestsBase protected override double KelvinsInOneKelvin => 1; - [SuppressMessage("ReSharper", "ImpureMethodCallOnReadonlyValueField", - Justification = "R# incorrectly identifies method as impure, due to internal method calls.")] - [Theory] - [InlineData(TemperatureUnit.DegreeCelsius, 10, 1, "10 °C")] - [InlineData(TemperatureUnit.DegreeCelsius, 10, 5, "2 °C")] - [InlineData(TemperatureUnit.DegreeCelsius, 10, -10, "-1 °C")] - [InlineData(TemperatureUnit.DegreeFahrenheit, 10, 1, "10 °F")] - [InlineData(TemperatureUnit.DegreeFahrenheit, 10, 5, "2 °F")] - [InlineData(TemperatureUnit.DegreeFahrenheit, 10, -10, "-1 °F")] - public void DividedByTemperatureDeltaEqualsTemperature(TemperatureUnit unit, int temperatureVal, int divisor, string expected) - { - Temperature temperature = Temperature.From(temperatureVal, unit); - - // Act - Temperature resultTemp = temperature.Divide(divisor, unit); - - string actual = resultTemp.ToUnit(unit).ToString(CultureInfo.InvariantCulture, "{0:0} {1}"); - Assert.Equal(expected, actual); - } - - [SuppressMessage("ReSharper", "ImpureMethodCallOnReadonlyValueField", - Justification = "R# incorrectly identifies method as impure, due to internal method calls.")] - [Theory] - [InlineData(TemperatureUnit.DegreeCelsius, 10, 0, "0 °C")] - [InlineData(TemperatureUnit.DegreeCelsius, 10, 5, "50 °C")] - [InlineData(TemperatureUnit.DegreeCelsius, 10, -5, "-50 °C")] - [InlineData(TemperatureUnit.DegreeFahrenheit, 10, 0, "0 °F")] - [InlineData(TemperatureUnit.DegreeFahrenheit, 10, 5, "50 °F")] - [InlineData(TemperatureUnit.DegreeFahrenheit, 10, -5, "-50 °F")] - public void MultiplyByTemperatureDeltaEqualsTemperature(TemperatureUnit unit, int temperatureVal, int factor, string expected) - { - Temperature temperature = Temperature.From(temperatureVal, unit); - - // Act - Temperature resultTemp = temperature.Multiply(factor, unit); - - string actual = resultTemp.ToUnit(unit).ToString(CultureInfo.InvariantCulture, "{0:0} {1}"); - Assert.Equal(expected, actual); - } - [Theory] [InlineData(TemperatureUnit.DegreeCelsius, -10, 0, "-10 °C")] [InlineData(TemperatureUnit.DegreeCelsius, -10, 10, "0 °C")] @@ -141,5 +101,24 @@ public void TemperaturePlusTemperatureDeltaEqualsTemperature(TemperatureUnit uni string actual = resultTemp.ToUnit(unit).ToString(CultureInfo.InvariantCulture, "{0:0} {1}"); Assert.Equal(expected, actual); } + + [Theory] + [InlineData(TemperatureUnit.DegreeCelsius, 30, 20, "10 ∆°C")] + [InlineData(TemperatureUnit.DegreeCelsius, 20, 30, "-10 ∆°C")] + [InlineData(TemperatureUnit.DegreeFahrenheit, 30, 20, "10 ∆°F")] + [InlineData(TemperatureUnit.DegreeFahrenheit, 20, 30, "-10 ∆°F")] + [InlineData(TemperatureUnit.Kelvin, 30, 20, "10 ∆K")] + [InlineData(TemperatureUnit.Kelvin, 20, 30, "-10 ∆K")] + public void ToDelta_ReturnsDeltaOfTwoTemperaturesInSameUnit(TemperatureUnit unit, int value, int otherValue, string expected) + { + Temperature temperature = Temperature.From(value, unit); + Temperature otherTemperature = Temperature.From(otherValue, unit); + + // Act + var delta = temperature.ToDelta(otherTemperature); + + // Assert + Assert.Equal(expected, delta.ToString(CultureInfo.InvariantCulture, "{0:0} {1}")); + } } } diff --git a/UnitsNet/CustomCode/Quantities/Temperature.extra.cs b/UnitsNet/CustomCode/Quantities/Temperature.extra.cs index fed00fd718..41b866d4e1 100644 --- a/UnitsNet/CustomCode/Quantities/Temperature.extra.cs +++ b/UnitsNet/CustomCode/Quantities/Temperature.extra.cs @@ -1,16 +1,16 @@ // Copyright (c) 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). // https://github.com/angularsen/UnitsNet -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -36,7 +36,7 @@ public partial struct Temperature // Windows Runtime Component does not allow operator overloads: https://msdn.microsoft.com/en-us/library/br230301.aspx #if !WINDOWS_UWP /// - /// Add a and a . + /// Add a to a . /// /// Due to temperature units having different scales, the arithmetic must be performed on the same scale. /// The new temperature. @@ -46,7 +46,7 @@ public partial struct Temperature } /// - /// Add a and a . + /// Add a to a . /// /// Due to temperature units having different scales, the arithmetic must be performed on the same scale. /// The new temperature. @@ -56,7 +56,7 @@ public partial struct Temperature } /// - /// Subtract a by a . + /// Subtract a from a . /// /// Due to temperature units having different scales, the arithmetic must be performed on the same scale. /// The new temperature. @@ -66,49 +66,15 @@ public partial struct Temperature } /// - /// Subtract a by a . + /// Subtract two temperatures to get a in this temperature's unit, which you can later convert to any temperature unit. + /// This is useful since Celsius, Fahrenheit and Kelvins don't share a common zero point on the scale and normal subtraction + /// would operate on Kelvins and likely give an unexpected result. + /// Example: + /// double deltaCelsius = celsius30.ToDelta(celsius20).DegreesCelsius; // 10 C + /// double wrongDeltaCelsius = (celsius30 - celsius20).DegreesCelsius; // 303.15 K - 293.15 K = 10 K = -263.15 degrees Celsius /// - /// Due to temperature units having different scales, the arithmetic must be performed on the same scale. - /// The delta temperature (difference). - public static TemperatureDelta operator -(Temperature left, Temperature right) - { - return new TemperatureDelta(left.Kelvins - right.Kelvins, TemperatureDeltaUnit.Kelvin); - } + /// A temperature delta. + public TemperatureDelta ToDelta(Temperature other) => TemperatureDelta.FromTemperatures(this, other); #endif - - /// - /// Multiply temperature with a in a given . - /// - /// - /// Due to different temperature units having different zero points, we cannot simply - /// multiply or divide a temperature by a factor. We must first convert to the desired unit, then perform the - /// calculation. - /// - /// Factor to multiply by. - /// Unit to perform multiplication in. - /// The resulting . - public Temperature Multiply(double factor, TemperatureUnit unit) - { - double resultInUnit = As(unit) * factor; - return From(resultInUnit, unit); - } - - - /// - /// Divide temperature by a in a given . - /// - /// - /// Due to different temperature units having different zero points, we cannot simply - /// multiply or divide a temperature by a factor. We must first convert to the desired unit, then perform the - /// calculation. - /// - /// Factor to multiply by. - /// Unit to perform multiplication in. - /// The resulting . - public Temperature Divide(double divisor, TemperatureUnit unit) - { - double resultInUnit = As(unit) / divisor; - return From(resultInUnit, unit); - } } } diff --git a/UnitsNet/CustomCode/Quantities/TemperatureDelta.extra.cs b/UnitsNet/CustomCode/Quantities/TemperatureDelta.extra.cs index 4ec7201483..b1b4c9c4d1 100644 --- a/UnitsNet/CustomCode/Quantities/TemperatureDelta.extra.cs +++ b/UnitsNet/CustomCode/Quantities/TemperatureDelta.extra.cs @@ -20,6 +20,10 @@ // THE SOFTWARE. // ReSharper disable once CheckNamespace + +using System; +using UnitsNet.Units; + namespace UnitsNet { // Windows Runtime Component has constraints on public types: https://msdn.microsoft.com/en-us/library/br230301.aspx#Declaring types in Windows Runtime Components @@ -47,6 +51,32 @@ public partial struct TemperatureDelta { return specificEntropy * temperatureDelta; } + + /// + /// Subtract two temperatures to get a in 's unit, which you can later convert to any temperature unit. + /// This is useful since Celsius, Fahrenheit and Kelvins don't share a common zero point on the scale and normal subtraction + /// would operate on Kelvins and likely give an unexpected result. + /// Example: + /// double deltaCelsius = TemperatureDelta.FromTemperatures(celsius30, celsius20).DegreesCelsius; // 10 C + /// double wrongDeltaCelsius = (celsius30 - celsius20).DegreesCelsius; // 303.15 K - 293.15 K = 10 K = -263.15 degrees Celsius + /// + /// A temperature delta. + public static TemperatureDelta FromTemperatures(Temperature left, Temperature right) + { + TemperatureDeltaUnit deltaUnit = ToDeltaUnit(left.Unit); + return new TemperatureDelta(left.Value - right.As(left.Unit), deltaUnit); + } + + /// + /// Converts a temperature unit to a temperature delta unit. + /// They share the exact same unit names, but are of different enum types and have slightly different semantic meaning. + /// + /// Temperature unit. + /// Equivalent temperature delta unit. + public static TemperatureDeltaUnit ToDeltaUnit(TemperatureUnit temperatureUnit) + { + return (TemperatureDeltaUnit)Enum.Parse(typeof(TemperatureDeltaUnit), temperatureUnit.ToString()); + } #endif } }