diff --git a/UnitsNet.Tests/QuantityIFormattableTests.cs b/UnitsNet.Tests/QuantityIFormattableTests.cs
index 059b5b22e2..118c83f32c 100644
--- a/UnitsNet.Tests/QuantityIFormattableTests.cs
+++ b/UnitsNet.Tests/QuantityIFormattableTests.cs
@@ -65,6 +65,36 @@ public void SFormatEqualsSignificantDigits(string sFormatString, string expected
Assert.Equal(expected, length.ToString(sFormatString, NumberFormatInfo.InvariantInfo));
}
+ ///
+ /// This verifies that the culture is correctly considered when formatting objects with an explicit culture.
+ ///
+ [Fact]
+ public void FormattingUsesSuppliedLocale()
+ {
+ Temperature t = Temperature.FromDegreesCelsius(2012.1234);
+ CultureInfo c = new CultureInfo("de-CH", false);
+ string formatted = string.Format(c, "{0:g}", t);
+ // Let's be very explicit here
+ Assert.Equal("2" + c.NumberFormat.NumberGroupSeparator + "012" + c.NumberFormat.NumberDecimalSeparator + "12 °C", formatted);
+ }
+
+ ///
+ /// This verifies that the culture is correctly considered when using
+ ///
+ [Fact]
+ public void FormatStringWorksWithSuppliedLocale()
+ {
+ Temperature t = Temperature.FromDegreesCelsius(2012.1234);
+ CultureInfo c = new CultureInfo("de-CH", false);
+
+ FormattableString f = $"{t:g}";
+ Assert.Equal("2" + c.NumberFormat.NumberGroupSeparator + "012" + c.NumberFormat.NumberDecimalSeparator + "12 °C", f.ToString(c));
+
+ // This does not work. Looks like a compiler bug to me.
+ // string f2 = $"{t:g}".ToString(c);
+ // Assert.Equal("2'012.12 °C", f2.ToString(c)); // Actual value is formatted according to CurrentUiCulture.
+ }
+
[Fact]
public void UFormatEqualsUnitToString()
{
diff --git a/UnitsNet/CustomCode/Quantities/Length.extra.cs b/UnitsNet/CustomCode/Quantities/Length.extra.cs
index c69d65fabf..622834d60e 100644
--- a/UnitsNet/CustomCode/Quantities/Length.extra.cs
+++ b/UnitsNet/CustomCode/Quantities/Length.extra.cs
@@ -59,6 +59,27 @@ public static Length ParseFeetInches([NotNull] string str, IFormatProvider? form
return result;
}
+ ///
+ /// Try to parse a string with one or two quantities of the format "<quantity> <unit>".
+ ///
+ /// String to parse. Typically in the form: {number} {unit}
+ /// Format to use when parsing number and unit. Defaults to if null.
+ /// Allowed number styles
+ /// Resulting unit quantity if successful.
+ /// True if successful, otherwise false.
+ ///
+ /// Length.Parse("5.5 m", new CultureInfo("en-US"));
+ ///
+ private static bool TryParse(string? str, IFormatProvider? provider, NumberStyles allowedNumberStyles, out Length result)
+ {
+ return QuantityParser.Default.TryParse(
+ str,
+ provider,
+ From,
+ allowedNumberStyles,
+ out result);
+ }
+
///
/// Special parsing of feet/inches strings, commonly used.
/// 2 feet 4 inches is sometimes denoted as 2′−4″, 2′ 4″, 2′4″, 2 ft 4 in.
@@ -80,7 +101,8 @@ public static bool TryParseFeetInches(string? str, out Length result, IFormatPro
str = str.Trim();
// This succeeds if only feet or inches are given, not both
- if (TryParse(str, formatProvider, out result))
+ // Do not allow thousands separator here, since it may be equal to the unit abbreviation (').
+ if (TryParse(str, formatProvider, NumberStyles.Float, out result))
return true;
var quantityParser = QuantityParser.Default;
diff --git a/UnitsNet/CustomCode/QuantityParser.cs b/UnitsNet/CustomCode/QuantityParser.cs
index a0054f5779..b190d735fd 100644
--- a/UnitsNet/CustomCode/QuantityParser.cs
+++ b/UnitsNet/CustomCode/QuantityParser.cs
@@ -69,10 +69,21 @@ internal TQuantity Parse([NotNull] string str,
return ParseWithRegex(valueString!, unitString!, fromDelegate, formatProvider);
}
+ internal bool TryParse(string? str,
+ IFormatProvider? formatProvider,
+ [NotNull] QuantityFromDelegate fromDelegate,
+ out TQuantity result)
+ where TQuantity : struct, IQuantity
+ where TUnitType : struct, Enum
+ {
+ return TryParse(str, formatProvider, fromDelegate, ParseNumberStyles, out result);
+ }
+
[SuppressMessage("ReSharper", "UseStringInterpolation")]
internal bool TryParse(string? str,
IFormatProvider? formatProvider,
[NotNull] QuantityFromDelegate fromDelegate,
+ NumberStyles allowedNumberStyles,
out TQuantity result)
where TQuantity : struct, IQuantity
where TUnitType : struct, Enum
@@ -94,21 +105,22 @@ internal bool TryParse(string? str,
if (!TryExtractValueAndUnit(regex, str, out var valueString, out var unitString))
return false;
- return TryParseWithRegex(valueString, unitString, fromDelegate, formatProvider, out result);
+ return TryParseWithRegex(valueString, unitString, fromDelegate, formatProvider, allowedNumberStyles, out result);
}
///
/// Workaround for C# not allowing to pass on 'out' param from type Length to IQuantity, even though the are compatible.
///
[SuppressMessage("ReSharper", "UseStringInterpolation")]
- internal bool TryParse([NotNull] string str,
+ internal bool TryParse(string? str,
IFormatProvider? formatProvider,
[NotNull] QuantityFromDelegate fromDelegate,
+ NumberStyles allowedNumberStyles,
out IQuantity? result)
where TQuantity : struct, IQuantity
where TUnitType : struct, Enum
{
- if (TryParse(str, formatProvider, fromDelegate, out TQuantity parsedQuantity))
+ if (TryParse(str, formatProvider, fromDelegate, allowedNumberStyles, out TQuantity parsedQuantity))
{
result = parsedQuantity;
return true;
@@ -118,6 +130,19 @@ internal bool TryParse([NotNull] string str,
return false;
}
+ ///
+ /// Workaround for C# not allowing to pass on 'out' param from type Length to IQuantity, even though the are compatible.
+ ///
+ internal bool TryParse(string? str,
+ IFormatProvider? formatProvider,
+ [NotNull] QuantityFromDelegate fromDelegate,
+ out IQuantity? result)
+ where TQuantity : struct, IQuantity
+ where TUnitType : struct, Enum
+ {
+ return TryParse(str, formatProvider, fromDelegate, ParseNumberStyles, out result);
+ }
+
internal string CreateRegexPatternForUnit(
TUnitType unit,
IFormatProvider? formatProvider,
@@ -164,13 +189,14 @@ private bool TryParseWithRegex(string? valueString,
string? unitString,
QuantityFromDelegate fromDelegate,
IFormatProvider? formatProvider,
+ NumberStyles allowedNumberStyles,
out TQuantity result)
where TQuantity : struct, IQuantity
where TUnitType : struct, Enum
{
result = default;
- if (!double.TryParse(valueString, ParseNumberStyles, formatProvider, out var value))
+ if (!double.TryParse(valueString, allowedNumberStyles, formatProvider, out var value))
return false;
if (!_unitParser.TryParse(unitString, formatProvider, out var parsedUnit))