From 8d69b5ddcc3065cb284a040dda516280a382ac14 Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Tue, 25 Oct 2016 17:58:09 -0700 Subject: [PATCH 1/8] Adding lower allocating DateTime.ToString('o') --- .../System/Globalization/DateTimeFormat.cs | 80 ++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs index 228e5f56a205..9418fdd7ff63 100644 --- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs +++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs @@ -957,12 +957,88 @@ internal static String Format(DateTime dateTime, String format, DateTimeFormatIn } if (format.Length == 1) { + switch (format) { + case "o": + case "O": + // Fast track for round trip format without going through a format string. + return RoundTripFormat(ref dateTime); + } + format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset); - } + } return (FormatCustomized(dateTime, format, dtfi, offset)); } - + + internal static string RoundTripFormat(ref DateTime dateTime) + { + StringBuilder result = StringBuilderCache.Acquire(); + Append(result, dateTime.Year, 4); + result.Append('-'); + + Append(result, dateTime.Month, 2); + result.Append('-'); + + Append(result, dateTime.Day, 2); + result.Append('T'); + + Append(result, dateTime.Hour, 2); + result.Append(':'); + + Append(result, dateTime.Minute, 2); + result.Append(':'); + + Append(result, dateTime.Second, 2); + result.Append('.'); + + long fraction = dateTime.Ticks % TimeSpan.TicksPerSecond; + + Append(result, fraction, 7); + + switch (dateTime.Kind) + { + case DateTimeKind.Local: + { + TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(dateTime); + + if (offset >= TimeSpan.Zero) + { + result.Append('+'); + } + else + { + result.Append('-'); + offset = offset.Negate(); + } + + Append(result, offset.Hours, 2); + result.Append(':'); + Append(result, offset.Minutes, 2); + } + break; + + case DateTimeKind.Utc: + result.Append('Z'); + break; + + default: + break; + } + + return StringBuilderCache.GetStringAndRelease(result); + } + + internal static void Append(StringBuilder builder, long val, int digit) + { + if (digit > 1) + { + Append(builder, val / 10, digit - 1); + } + + builder.Append((char)('0' + (val % 10))); + } + + internal static String[] GetAllDateTimes(DateTime dateTime, char format, DateTimeFormatInfo dtfi) { Contract.Requires(dtfi != null); From 132e5d1e706831b3cf0d3c60f2460197c392a730 Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Tue, 25 Oct 2016 18:08:21 -0700 Subject: [PATCH 2/8] removing unreachable switch cases --- src/mscorlib/src/System/Globalization/DateTimeFormat.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs index 9418fdd7ff63..59b16020abe1 100644 --- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs +++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs @@ -807,10 +807,6 @@ internal static String GetRealFormat(String format, DateTimeFormatInfo dtfi) case 'M': // Month/Day Date realFormat = dtfi.MonthDayPattern; break; - case 'o': - case 'O': - realFormat = RoundtripFormat; - break; case 'r': case 'R': // RFC 1123 Standard realFormat = dtfi.RFC1123Pattern; @@ -848,10 +844,6 @@ internal static String GetRealFormat(String format, DateTimeFormatInfo dtfi) // private static String ExpandPredefinedFormat(String format, ref DateTime dateTime, ref DateTimeFormatInfo dtfi, ref TimeSpan offset) { switch (format[0]) { - case 'o': - case 'O': // Round trip format - dtfi = DateTimeFormatInfo.InvariantInfo; - break; case 'r': case 'R': // RFC 1123 Standard if (offset != NullOffset) { From f49c5d1f71668f702ca84c20d0514f6cf5e8effa Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Wed, 26 Oct 2016 15:43:41 -0700 Subject: [PATCH 3/8] more cleanup --- src/mscorlib/src/System/Globalization/DateTimeFormat.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs index 59b16020abe1..f41a13b22b94 100644 --- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs +++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs @@ -949,9 +949,9 @@ internal static String Format(DateTime dateTime, String format, DateTimeFormatIn } if (format.Length == 1) { - switch (format) { - case "o": - case "O": + switch (format[0]) { + case 'o': + case 'O': // Fast track for round trip format without going through a format string. return RoundTripFormat(ref dateTime); } From 262c07a35f0fba2056f48f6ac1e2eabc1deab50b Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Thu, 27 Oct 2016 14:14:15 -0700 Subject: [PATCH 4/8] updates based on review feedback --- .../System/Globalization/DateTimeFormat.cs | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs index f41a13b22b94..2190d7538d8f 100644 --- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs +++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs @@ -807,6 +807,10 @@ internal static String GetRealFormat(String format, DateTimeFormatInfo dtfi) case 'M': // Month/Day Date realFormat = dtfi.MonthDayPattern; break; + case 'o': + case 'O': + realFormat = RoundtripFormat; + break; case 'r': case 'R': // RFC 1123 Standard realFormat = dtfi.RFC1123Pattern; @@ -844,6 +848,10 @@ internal static String GetRealFormat(String format, DateTimeFormatInfo dtfi) // private static String ExpandPredefinedFormat(String format, ref DateTime dateTime, ref DateTimeFormatInfo dtfi, ref TimeSpan offset) { switch (format[0]) { + case 'o': + case 'O': // Round trip format + dtfi = DateTimeFormatInfo.InvariantInfo; + break; case 'r': case 'R': // RFC 1123 Standard if (offset != NullOffset) { @@ -949,11 +957,8 @@ internal static String Format(DateTime dateTime, String format, DateTimeFormatIn } if (format.Length == 1) { - switch (format[0]) { - case 'o': - case 'O': - // Fast track for round trip format without going through a format string. - return RoundTripFormat(ref dateTime); + if (format[0] == 'o' || format[0] == 'O') { + return FastFormatRoundTrip(dateTime); } format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset); @@ -962,30 +967,25 @@ internal static String Format(DateTime dateTime, String format, DateTimeFormatIn return (FormatCustomized(dateTime, format, dtfi, offset)); } - internal static string RoundTripFormat(ref DateTime dateTime) + internal static string FastFormatRoundTrip(DateTime dateTime) { StringBuilder result = StringBuilderCache.Acquire(); - Append(result, dateTime.Year, 4); + AppendNumber(result, dateTime.Year, 4); result.Append('-'); - - Append(result, dateTime.Month, 2); + AppendNumber(result, dateTime.Month, 2); result.Append('-'); - - Append(result, dateTime.Day, 2); + AppendNumber(result, dateTime.Day, 2); result.Append('T'); - - Append(result, dateTime.Hour, 2); + AppendNumber(result, dateTime.Hour, 2); result.Append(':'); - - Append(result, dateTime.Minute, 2); + AppendNumber(result, dateTime.Minute, 2); result.Append(':'); - - Append(result, dateTime.Second, 2); + AppendNumber(result, dateTime.Second, 2); result.Append('.'); long fraction = dateTime.Ticks % TimeSpan.TicksPerSecond; - Append(result, fraction, 7); + AppendNumber(result, fraction, 7); switch (dateTime.Kind) { @@ -1003,31 +1003,35 @@ internal static string RoundTripFormat(ref DateTime dateTime) offset = offset.Negate(); } - Append(result, offset.Hours, 2); + AppendNumber(result, offset.Hours, 2); result.Append(':'); - Append(result, offset.Minutes, 2); + AppendNumber(result, offset.Minutes, 2); } break; case DateTimeKind.Utc: result.Append('Z'); break; - - default: - break; } return StringBuilderCache.GetStringAndRelease(result); } - internal static void Append(StringBuilder builder, long val, int digit) + internal static void AppendNumber(StringBuilder builder, long val, int digits) { - if (digit > 1) + for (int i = 0; i < digits; i++) { - Append(builder, val / 10, digit - 1); + builder.Append('0'); } - builder.Append((char)('0' + (val % 10))); + int index = 1; + + while (val > 0 && index <= digits) + { + builder[builder.Length - index] = (char)('0' + (val % 10)); + val = val / 10; + index++; + } } From dfe10ff50e6491d6d3494be7bc8510d771e05e6b Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Thu, 27 Oct 2016 14:37:14 -0700 Subject: [PATCH 5/8] fixing whitespace --- src/mscorlib/src/System/Globalization/DateTimeFormat.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs index 2190d7538d8f..640f2483139a 100644 --- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs +++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs @@ -1034,7 +1034,6 @@ internal static void AppendNumber(StringBuilder builder, long val, int digits) } } - internal static String[] GetAllDateTimes(DateTime dateTime, char format, DateTimeFormatInfo dtfi) { Contract.Requires(dtfi != null); From bf79a189d6ba788ab31c7b43b5641106cb2b2aed Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Thu, 27 Oct 2016 14:57:30 -0700 Subject: [PATCH 6/8] Fix Casing --- src/mscorlib/src/System/Globalization/DateTimeFormat.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs index 640f2483139a..16c11c7cfb1f 100644 --- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs +++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs @@ -958,7 +958,7 @@ internal static String Format(DateTime dateTime, String format, DateTimeFormatIn if (format.Length == 1) { if (format[0] == 'o' || format[0] == 'O') { - return FastFormatRoundTrip(dateTime); + return FastFormatRoundtrip(dateTime); } format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset); @@ -967,7 +967,7 @@ internal static String Format(DateTime dateTime, String format, DateTimeFormatIn return (FormatCustomized(dateTime, format, dtfi, offset)); } - internal static string FastFormatRoundTrip(DateTime dateTime) + internal static string FastFormatRoundtrip(DateTime dateTime) { StringBuilder result = StringBuilderCache.Acquire(); AppendNumber(result, dateTime.Year, 4); From 1321303ba77058eca68a7bdc0a9eb5db2a2035c7 Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Fri, 28 Oct 2016 10:44:58 -0700 Subject: [PATCH 7/8] fixing DateTimeOffset --- .../System/Globalization/DateTimeFormat.cs | 39 ++++--------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs index 16c11c7cfb1f..c182835b205d 100644 --- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs +++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs @@ -775,7 +775,9 @@ private static void FormatCustomizedRoundripTimeZone(DateTime dateTime, TimeSpan offset = offset.Negate(); } - result.AppendFormat(CultureInfo.InvariantCulture, "{0:00}:{1:00}", offset.Hours, offset.Minutes); + AppendNumber(result, offset.Hours, 2); + result.Append(':'); + AppendNumber(result, offset.Minutes, 2); } @@ -958,7 +960,7 @@ internal static String Format(DateTime dateTime, String format, DateTimeFormatIn if (format.Length == 1) { if (format[0] == 'o' || format[0] == 'O') { - return FastFormatRoundtrip(dateTime); + return FastFormatRoundtrip(dateTime, offset); } format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset); @@ -967,9 +969,10 @@ internal static String Format(DateTime dateTime, String format, DateTimeFormatIn return (FormatCustomized(dateTime, format, dtfi, offset)); } - internal static string FastFormatRoundtrip(DateTime dateTime) + internal static string FastFormatRoundtrip(DateTime dateTime, TimeSpan offset) { StringBuilder result = StringBuilderCache.Acquire(); + AppendNumber(result, dateTime.Year, 4); result.Append('-'); AppendNumber(result, dateTime.Month, 2); @@ -984,39 +987,13 @@ internal static string FastFormatRoundtrip(DateTime dateTime) result.Append('.'); long fraction = dateTime.Ticks % TimeSpan.TicksPerSecond; - AppendNumber(result, fraction, 7); - switch (dateTime.Kind) - { - case DateTimeKind.Local: - { - TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(dateTime); - - if (offset >= TimeSpan.Zero) - { - result.Append('+'); - } - else - { - result.Append('-'); - offset = offset.Negate(); - } - - AppendNumber(result, offset.Hours, 2); - result.Append(':'); - AppendNumber(result, offset.Minutes, 2); - } - break; - - case DateTimeKind.Utc: - result.Append('Z'); - break; - } + FormatCustomizedRoundripTimeZone(dateTime, offset, result); return StringBuilderCache.GetStringAndRelease(result); } - + internal static void AppendNumber(StringBuilder builder, long val, int digits) { for (int i = 0; i < digits; i++) From ec5af22a692a3ee3adbf37e620a3333e081c3708 Mon Sep 17 00:00:00 2001 From: Peter Marcu Date: Fri, 28 Oct 2016 11:53:48 -0700 Subject: [PATCH 8/8] adding assert --- src/mscorlib/src/System/Globalization/DateTimeFormat.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs index c182835b205d..c05ba97645ae 100644 --- a/src/mscorlib/src/System/Globalization/DateTimeFormat.cs +++ b/src/mscorlib/src/System/Globalization/DateTimeFormat.cs @@ -1002,13 +1002,14 @@ internal static void AppendNumber(StringBuilder builder, long val, int digits) } int index = 1; - while (val > 0 && index <= digits) { builder[builder.Length - index] = (char)('0' + (val % 10)); val = val / 10; index++; } + + Contract.Assert(val == 0, "DateTimeFormat.AppendNumber(): digits less than size of val"); } internal static String[] GetAllDateTimes(DateTime dateTime, char format, DateTimeFormatInfo dtfi)