From 80e859dd970262be05fb2ce3fcc77e7bc5c8a988 Mon Sep 17 00:00:00 2001 From: Dan Moseley <6385855+danmoseley@users.noreply.github.com> Date: Sat, 13 Jun 2026 18:21:26 -0600 Subject: [PATCH] Add fast path for DateTime.ToString("G", InvariantCulture) Mirrors the existing single-char fast paths for 'o', 'r', 's', 'u' and the null/empty-format invariant fast path that ToString(InvariantCulture) already uses, routing through TryFormatInvariantG instead of FormatCustomized. Output is byte-identical to the existing pattern-based path ("MM/dd/yyyy HH:mm:ss", 19 chars). ~5.5x faster (41.58 ns -> 7.54 ns median). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../System/Globalization/DateTimeFormat.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs index 452d5d86f3157a..13b6ceb1e35da2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs @@ -1007,6 +1007,22 @@ internal static unsafe string Format(DateTime dateTime, string? format, IFormatP format = dtfi.FullDateTimePattern; break; + // For invariant DateTime ToString("G"), the expanded pattern is + // "MM/dd/yyyy HH:mm:ss" which is exactly what TryFormatInvariantG + // produces in the NullOffset case. Take the same fast path that + // ToString(InvariantCulture) (null format) already uses. + case 'G': + dtfi = DateTimeFormatInfo.GetInstance(provider); + if (offset.Ticks == NullOffset && ReferenceEquals(dtfi, DateTimeFormatInfo.InvariantInfo)) + { + str = string.FastAllocateString(FormatInvariantGMinLength); + TryFormatInvariantG(dateTime, offset, new Span(ref str.GetRawStringData(), str.Length), out charsWritten); + Debug.Assert(charsWritten == FormatInvariantGMinLength); + return str; + } + format = dtfi.GeneralLongTimePattern; + break; + // All other standard formats default: dtfi = DateTimeFormatInfo.GetInstance(provider); @@ -1098,6 +1114,19 @@ internal static bool TryFormat(DateTime dateTime, Span destination format = dtfi.FullDateTimePattern; break; + // For invariant DateTime ToString("G"), the expanded pattern is + // "MM/dd/yyyy HH:mm:ss" which is exactly what TryFormatInvariantG + // produces in the NullOffset case. Take the same fast path that + // ToString(InvariantCulture) (null format) already uses. + case 'G': + dtfi = DateTimeFormatInfo.GetInstance(provider); + if (offset.Ticks == NullOffset && ReferenceEquals(dtfi, DateTimeFormatInfo.InvariantInfo)) + { + return TryFormatInvariantG(dateTime, offset, destination, out charsWritten); + } + format = dtfi.GeneralLongTimePattern; + break; + // All other standard formats default: dtfi = DateTimeFormatInfo.GetInstance(provider);