将原始答案更新为使用Span。
public static string FormatDateTime(DateTime dateTime)
{
return string.Create(21, dateTime, (chars, dt) =>
{
Write2Chars(chars, 0, dt.Day);
chars[2] = '.';
Write2Chars(chars, 3, dt.Month);
chars[5] = '.';
Write2Chars(chars, 6, dt.Year % 100);
chars[8] = ' ';
Write2Chars(chars, 9, dt.Hour);
chars[11] = ' ';
Write2Chars(chars, 12, dt.Minute);
chars[14] = ' ';
Write2Chars(chars, 15, dt.Second);
chars[17] = ' ';
Write2Chars(chars, 18, dt.Millisecond / 10);
chars[20] = Digit(dt.Millisecond % 10);
});
}
private static void Write2Chars(in Span<char> chars, int offset, int value)
{
chars[offset] = Digit(value / 10);
chars[offset + 1] = Digit(value % 10);
}
private static char Digit(int value)
{
return (char)(value + '0');
}
基准测试结果
BenchmarkDotNet=v0.13.1, OS=ubuntu 20.04
Intel Xeon W-1290P CPU 3.70GHz, 1 CPU, 20 logical and 10 physical cores
.NET SDK=6.0.202
[Host] : .NET 6.0.4 (6.0.422.16404), X64 RyuJIT
DefaultJob : .NET 6.0.4 (6.0.422.16404), X64 RyuJIT
| Method | Mean | Error | StdDev | Gen 0 | Allocated |
|-------------------------- |----------:|---------:|---------:|-------:|----------:|
| DateTime_Format | 225.35 ns | 1.211 ns | 1.011 ns | 0.0060 | 64 B |
| Custom_Formatter_Original | 43.00 ns | 0.188 ns | 0.147 ns | 0.0130 | 136 B |
| Custom_Formatter_Updated | 37.15 ns | 0.140 ns | 0.117 ns | 0.0061 | 64 B |
基准测试
using System.Globalization;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace Benchmark
{
[MemoryDiagnoser]
public class DateTimeToString
{
private const string DateTimeFormat = "dd.MM.yy HH:mm:ss:fff";
private readonly DateTime _now;
public DateTimeToString()
{
_now = DateTime.UtcNow;
}
[Benchmark]
public string DateTime_Format() => _now.ToString(DateTimeFormat, CultureInfo.InvariantCulture);
[Benchmark]
public string Custom_Formatter_Original()
{
return DateTimeWriterHelper.FormatDateTimeOriginal(_now);
}
[Benchmark]
public string Custom_Formatter_Updated()
{
return DateTimeWriterHelper.FormatDateTimeUpdated(_now);
}
}
public class Program
{
public static void Main(string[] args)
{
var summary = BenchmarkRunner.Run(typeof(Program).Assembly);
Console.Write(summary);
}
}
static class DateTimeWriterHelper
{
public static string FormatDateTimeOriginal(DateTime dt)
{
char[] chars = new char[21];
Write2Chars(chars, 0, dt.Day);
chars[2] = '.';
Write2Chars(chars, 3, dt.Month);
chars[5] = '.';
Write2Chars(chars, 6, dt.Year % 100);
chars[8] = ' ';
Write2Chars(chars, 9, dt.Hour);
chars[11] = ' ';
Write2Chars(chars, 12, dt.Minute);
chars[14] = ' ';
Write2Chars(chars, 15, dt.Second);
chars[17] = ' ';
Write2Chars(chars, 18, dt.Millisecond / 10);
chars[20] = Digit(dt.Millisecond % 10);
return new string(chars);
}
public static string FormatDateTimeUpdated(DateTime dateTime)
{
return string.Create(21, dateTime, (chars, dt) =>
{
Write2Chars(chars, 0, dt.Day);
chars[2] = '.';
Write2Chars(chars, 3, dt.Month);
chars[5] = '.';
Write2Chars(chars, 6, dt.Year % 100);
chars[8] = ' ';
Write2Chars(chars, 9, dt.Hour);
chars[11] = ' ';
Write2Chars(chars, 12, dt.Minute);
chars[14] = ' ';
Write2Chars(chars, 15, dt.Second);
chars[17] = ' ';
Write2Chars(chars, 18, dt.Millisecond / 10);
chars[20] = Digit(dt.Millisecond % 10);
});
}
private static void Write2Chars(in Span<char> chars, int offset, int value)
{
chars[offset] = Digit(value / 10);
chars[offset + 1] = Digit(value % 10);
}
private static char Digit(int value)
{
return (char)(value + '0');
}
}
}