Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve DateTime{Offset} formatting further in a variety of cases #84963

Merged
merged 4 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Formatter\FormattingHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Formatter\Utf8Formatter.Boolean.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Formatter\Utf8Formatter.Date.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Formatter\Utf8Formatter.Date.G.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Formatter\Utf8Formatter.Date.L.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Formatter\Utf8Formatter.Decimal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Formatter\Utf8Formatter.Float.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\Utf8Formatter\Utf8Formatter.Guid.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ internal static partial class Utf8Constants
public const byte Space = (byte)' ';
public const byte Hyphen = (byte)'-';

// Invariant formatting uses groups of 3 for each number group separated by commas.
// ex. 1,234,567,890
public const int GroupSize = 3;

public static readonly TimeSpan NullUtcOffset = TimeSpan.MinValue; // Utc offsets must range from -14:00 to 14:00 so this is never a valid offset.

public const int DateTimeMaxUtcOffsetHours = 14; // The UTC offset portion of a TimeSpan or DateTime can be no more than 14 hours and no less than -14 hours.

public const int DateTimeNumFractionDigits = 7; // TimeSpan and DateTime formats allow exactly up to many digits for specifying the fraction after the seconds.
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Text;

namespace System.Buffers.Text
{
public static partial class Utf8Formatter
Expand Down Expand Up @@ -29,18 +32,15 @@ public static partial class Utf8Formatter
/// </exceptions>
public static bool TryFormat(DateTimeOffset value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
TimeSpan offset = Utf8Constants.NullUtcOffset;
char symbol = format.Symbol;
if (format.IsDefault)
{
symbol = 'G';
offset = value.Offset;
return DateTimeFormat.TryFormatInvariantG(value.DateTime, value.Offset, destination, out bytesWritten);
}

switch (symbol)
switch (format.Symbol)
{
case 'R':
return DateTimeFormat.TryFormatR(value.UtcDateTime, new TimeSpan(DateTimeFormat.NullOffset), destination, out bytesWritten);
return DateTimeFormat.TryFormatR(value.UtcDateTime, NullOffset, destination, out bytesWritten);

case 'O':
return DateTimeFormat.TryFormatO(value.DateTime, value.Offset, destination, out bytesWritten);
Expand All @@ -49,7 +49,7 @@ public static bool TryFormat(DateTimeOffset value, Span<byte> destination, out i
return TryFormatDateTimeL(value.UtcDateTime, destination, out bytesWritten);

case 'G':
return TryFormatDateTimeG(value.DateTime, offset, destination, out bytesWritten);
return DateTimeFormat.TryFormatInvariantG(value.DateTime, NullOffset, destination, out bytesWritten);

default:
ThrowHelper.ThrowFormatException_BadFormatSpecifier();
Expand Down Expand Up @@ -83,21 +83,36 @@ public static bool TryFormat(DateTime value, Span<byte> destination, out int byt
switch (FormattingHelpers.GetSymbolOrDefault(format, 'G'))
{
case 'R':
return DateTimeFormat.TryFormatR(value, new TimeSpan(DateTimeFormat.NullOffset), destination, out bytesWritten);
return DateTimeFormat.TryFormatR(value, NullOffset, destination, out bytesWritten);

case 'O':
return DateTimeFormat.TryFormatO(value, Utf8Constants.NullUtcOffset, destination, out bytesWritten);
return DateTimeFormat.TryFormatO(value, NullOffset, destination, out bytesWritten);

case 'l':
return TryFormatDateTimeL(value, destination, out bytesWritten);

case 'G':
return TryFormatDateTimeG(value, Utf8Constants.NullUtcOffset, destination, out bytesWritten);
return DateTimeFormat.TryFormatInvariantG(value, NullOffset, destination, out bytesWritten);

default:
ThrowHelper.ThrowFormatException_BadFormatSpecifier();
goto case 'R'; // unreachable
}
}

// Rfc1123 lowercased
private static bool TryFormatDateTimeL(DateTime value, Span<byte> destination, out int bytesWritten)
{
if (DateTimeFormat.TryFormatR(value, NullOffset, destination, out bytesWritten))
{
Debug.Assert(bytesWritten == DateTimeFormat.FormatRLength);
Ascii.ToLowerInPlace(destination.Slice(0, bytesWritten), out bytesWritten);
return true;
}

return false;
}

private static TimeSpan NullOffset => new TimeSpan(DateTimeFormat.NullOffset);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ public void Dispose()
}
}

// Note that consuming implementations depend on the list only growing if it's absolutely
// required. If the list is already large enough to hold the additional items be added,
// it must not grow. The list is used in a number of places where the reference is checked
// and it's expected to match the initial reference provided to the constructor if that
// span was sufficiently large.
private void Grow(int additionalCapacityRequired = 1)
{
const int ArrayMaxLength = 0x7FFFFFC7; // same as Array.MaxLength
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ public string ToString([StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] stri
}
}

DateTimeFormat.IsValidCustomDateFormat(format.AsSpan(), throwOnError: true);
DateTimeFormat.IsValidCustomDateOnlyFormat(format.AsSpan(), throwOnError: true);
return DateTimeFormat.Format(GetEquivalentDateTime(), format, provider);
}

Expand Down Expand Up @@ -820,7 +820,7 @@ private bool TryFormatCore<TChar>(Span<TChar> destination, out int charsWritten,
}
}

if (!DateTimeFormat.IsValidCustomDateFormat(format, throwOnError: false))
if (!DateTimeFormat.IsValidCustomDateOnlyFormat(format, throwOnError: false))
{
throw new FormatException(SR.Format(SR.Format_DateTimeOnlyContainsNoneDateParts, format.ToString(), nameof(DateOnly)));
}
Expand Down
Loading