public static unsafe void Format(StringBuffer formatter, TimeSpan timeSpan, StringView format) { const int tempCharsLength = 7; var tempChars = stackalloc char[tempCharsLength]; formatter.EnsureCapacity(20); if (timeSpan.Ticks < 0) { formatter.Append('-'); timeSpan = new TimeSpan(-timeSpan.Ticks); } var(days, hours, minutes, seconds, ticks) = timeSpan; switch (ParseTimeSpanFormat(format)) { case TimeSpanFormat.Constant: if (days > 0) { formatter.Append(days, StringView.Empty); formatter.Append('.'); } AppendNumber(formatter, hours, 2, tempChars, tempCharsLength); formatter.Append(':'); AppendNumber(formatter, minutes, 2, tempChars, tempCharsLength); formatter.Append(':'); AppendNumber(formatter, seconds, 2, tempChars, tempCharsLength); if (ticks != 0) { formatter.Append('.'); AppendNumber(formatter, ticks, 7, tempChars, tempCharsLength); } break; case TimeSpanFormat.GeneralShort: if (days > 0) { formatter.Append(days, StringView.Empty); formatter.Append(':'); } formatter.Append(hours, StringView.Empty); formatter.Append(':'); AppendNumber(formatter, minutes, 2, tempChars, tempCharsLength); formatter.Append(':'); AppendNumber(formatter, seconds, 2, tempChars, tempCharsLength); if (ticks != 0) { formatter.Append('.'); AppendNumber(formatter, ticks, 7, tempChars, tempCharsLength); formatter.TrimEnd('0'); } break; case TimeSpanFormat.GeneralLong: formatter.Append(days, StringView.Empty); formatter.Append(':'); AppendNumber(formatter, hours, 2, tempChars, tempCharsLength); formatter.Append(':'); AppendNumber(formatter, minutes, 2, tempChars, tempCharsLength); formatter.Append(':'); AppendNumber(formatter, seconds, 2, tempChars, tempCharsLength); formatter.Append('.'); AppendNumber(formatter, ticks, 7, tempChars, tempCharsLength); break; } }
static void NumberToString(StringBuffer formatter, ref Number number, char format, int maxDigits, CachedCulture culture, bool isDecimal = false) { // ANDing with 0xFFDF has the effect of uppercasing the character switch (format & 0xFFDF) { case 'C': { var cultureData = culture.CurrencyData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatCurrency( buffer, ref number, maxDigits, cultureData, number.Sign > 0 ? culture.CurrencyNegativePattern : culture.CurrencyPositivePattern, culture.CurrencySymbol ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'F': { var cultureData = culture.FixedData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = buffer; if (number.Sign > 0) { AppendString(&ptr, cultureData.NegativeSign); } ptr = FormatFixed(ptr, ref number, maxDigits, cultureData); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'N': { var cultureData = culture.NumberData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatNumber( buffer, ref number, maxDigits, number.Sign > 0 ? culture.NumberNegativePattern : culture.NumberPositivePattern, cultureData ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'E': { var cultureData = culture.ScientificData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); maxDigits++; RoundNumber(ref number, maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = buffer; if (number.Sign > 0) { AppendString(&ptr, cultureData.NegativeSign); } ptr = FormatScientific( ptr, ref number, maxDigits, format, // TODO: fix casing cultureData.DecimalSeparator, culture.PositiveSign, culture.NegativeSign ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'P': { number.Scale += 2; var cultureData = culture.PercentData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatPercent( buffer, ref number, maxDigits, cultureData, number.Sign > 0 ? culture.PercentNegativePattern : culture.PercentPositivePattern, culture.PercentSymbol ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'G': { var enableRounding = true; if (maxDigits < 1) { if (isDecimal && maxDigits == -1) { // if we're formatting a decimal, default to 29 digits precision // only for G formatting without a precision specifier maxDigits = DecimalPrecision; enableRounding = false; } else { maxDigits = number.Precision; } } var bufferSize = maxDigits + culture.DecimalBufferSize; var buffer = stackalloc char[bufferSize]; var ptr = buffer; // round for G formatting only if a precision is given // we need to handle the minus zero case also if (enableRounding) { RoundNumber(ref number, maxDigits); } else if (isDecimal && number.Digits[0] == 0) { number.Sign = 0; } if (number.Sign > 0) { AppendString(&ptr, culture.NegativeSign); } ptr = FormatGeneral( ptr, ref number, maxDigits, (char)(format - ('G' - 'E')), culture.NumberData.DecimalSeparator, culture.PositiveSign, culture.NegativeSign, !enableRounding ); formatter.Append(buffer, (int)(ptr - buffer)); break; } default: throw new FormatException(string.Format(SR.UnknownFormatSpecifier, format)); } }
static void NumberToCustomFormatString(StringBuffer formatter, ref Number number, StringView specifier, CachedCulture culture) { }