Skip to content

Commit bba244c

Browse files
Matthias Gessingercommonsensesoftware
authored andcommitted
Backport DateTimeOffset.ToUnixTimeSeconds
1 parent f74dedd commit bba244c

7 files changed

Lines changed: 41 additions & 21 deletions

File tree

src/AspNet/WebApi/src/Asp.Versioning.WebApi/Asp.Versioning.WebApi.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<Compile Include="$(BackportDir)BitOperations.cs" Visible="false" />
2222
<Compile Include="$(BackportDir)HashCode.cs" Visible="false" />
2323
<Compile Include="$(BackportDir)NullableAttributes.cs" Visible="false" />
24+
<Compile Include="$(BackportDir)DateTimeOffsetExtensions.cs" Visible="false" />
2425
</ItemGroup>
2526

2627
<ItemGroup>

src/AspNet/WebApi/src/Asp.Versioning.WebApi/System.Net.Http/HttpResponseMessageExtensions.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ public static class HttpResponseMessageExtensions
1616
private const string Deprecation = nameof( Deprecation );
1717
private const string Link = nameof( Link );
1818

19-
private static readonly DateTime unixEpoch = new DateTime( 1970, 1, 1 );
20-
2119
/// <summary>
2220
/// Writes the sunset policy to the specified HTTP response.
2321
/// </summary>
@@ -50,14 +48,11 @@ public static void WriteDeprecationPolicy( this HttpResponseMessage response, De
5048

5149
var headers = response.Headers;
5250

53-
if ( deprecationPolicy.Date.HasValue )
51+
if ( deprecationPolicy.Date is { } when )
5452
{
55-
long unixTimestamp;
56-
DateTimeOffset deprecationDate = deprecationPolicy.Date.Value;
57-
58-
unixTimestamp = (int) deprecationDate.Subtract( unixEpoch ).TotalSeconds;
53+
var unixTimestamp = when.ToUnixTimeSeconds();
5954

60-
headers.Add( Deprecation, $"@{unixTimestamp}" );
55+
headers.Add( Deprecation, unixTimestamp.ToString( "'@'0" ) );
6156
}
6257

6358
AddLinkHeaders( headers, deprecationPolicy.Links );

src/AspNet/WebApi/test/Asp.Versioning.WebApi.Tests/DefaultApiVersionReporterTest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ public void report_should_add_expected_headers()
5151
// assert
5252
var headers = response.Headers;
5353

54-
long unixTimestamp = (int) deprecationDate.Subtract( new DateTime( 1970, 1, 1 ) ).TotalSeconds;
54+
// This line uses an explicit calculation of the unix timestamp to surface any bugs in the backport of ToUnixTimeSeconds.
55+
var unixTimestamp = (long) deprecationDate.Subtract( new DateTime( 1970, 1, 1 ) ).TotalSeconds;
5556

5657
headers.GetValues( "api-supported-versions" ).Should().Equal( "1.0, 2.0" );
5758
headers.GetValues( "api-deprecated-versions" ).Should().Equal( "0.9" );

src/AspNetCore/WebApi/src/Asp.Versioning.Http/Http/HttpResponseExtensions.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Microsoft.AspNetCore.Http;
55
using Asp.Versioning;
66
using Microsoft.Extensions.Primitives;
77
using Microsoft.Net.Http.Headers;
8+
using System.Globalization;
89

910
/// <summary>
1011
/// Provides extension methods for <see cref="HttpResponse"/>.
@@ -66,14 +67,9 @@ public static void WriteDeprecationPolicy( this HttpResponse response, Deprecati
6667
return;
6768
}
6869

69-
if ( deprecationPolicy.Date.HasValue )
70+
if ( deprecationPolicy.Date is { } when )
7071
{
71-
long unixTimestamp;
72-
DateTimeOffset deprecationDate = deprecationPolicy.Date.Value;
73-
74-
unixTimestamp = deprecationDate.ToUnixTimeSeconds();
75-
76-
headers[Deprecation] = $"@{unixTimestamp}";
72+
headers[Deprecation] = when.ToUnixTimeSeconds().ToString( "'@'0", CultureInfo.InvariantCulture );
7773
}
7874

7975
AddLinkHeaders( headers, deprecationPolicy.Links );

src/AspNetCore/WebApi/test/Asp.Versioning.Http.Tests/DefaultApiVersionReporterTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void report_should_add_expected_headers()
6161
reporter.Report( response.Object, model );
6262

6363
// assert
64-
long unixTimestamp = (int) deprecationDate.Subtract( new DateTime( 1970, 1, 1 ) ).TotalSeconds;
64+
var unixTimestamp = deprecationDate.ToUnixTimeSeconds();
6565

6666
headers["api-supported-versions"].Should().Equal( "1.0, 2.0" );
6767
headers["api-deprecated-versions"].Should().Equal( "0.9" );

src/Client/src/Asp.Versioning.Http.Client/System.Net.Http/HttpResponseMessageExtensions.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ public static class HttpResponseMessageExtensions
1818
private const string Deprecation = nameof( Deprecation );
1919
private const string Link = nameof( Link );
2020

21+
#if NETSTANDARD1_1
22+
private static readonly DateTime UnixEpoch = new DateTime( 1970, 1, 1 );
23+
#endif
24+
2125
/// <summary>
2226
/// Gets an API sunset policy from the HTTP response.
2327
/// </summary>
@@ -89,12 +93,20 @@ public static DeprecationPolicy ReadDeprecationPolicy( this HttpResponseMessage
8993

9094
foreach ( var value in values )
9195
{
92-
var split = value.Trim( '@' );
93-
if ( long.TryParse( split, out var unixTimestamp ) )
96+
if ( value.Length < 2 || value[0] != '@' )
9497
{
95-
DateTimeOffset parsed;
98+
continue;
99+
}
100+
96101
#if NETSTANDARD
97-
parsed = new DateTime(1970, 1, 1) + TimeSpan.FromSeconds(unixTimestamp);
102+
if ( long.TryParse( value.Substring( 1 ), out var unixTimestamp ) )
103+
#else
104+
if ( long.TryParse( value.AsSpan()[1..], out var unixTimestamp ) )
105+
#endif
106+
{
107+
DateTimeOffset parsed;
108+
#if NETSTANDARD1_1
109+
parsed = UnixEpoch + TimeSpan.FromSeconds( unixTimestamp );
98110
#else
99111
parsed = DateTimeOffset.FromUnixTimeSeconds( unixTimestamp );
100112
#endif
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace System;
4+
5+
internal static class DateTimeOffsetExtensions
6+
{
7+
private const long UnixEpochSeconds = 62_135_596_800L;
8+
9+
// REF: https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs#L745
10+
public static long ToUnixTimeSeconds( this DateTimeOffset dateTimeOffset )
11+
{
12+
var seconds = (long) ( (ulong) dateTimeOffset.UtcTicks / TimeSpan.TicksPerSecond );
13+
return seconds - UnixEpochSeconds;
14+
}
15+
}

0 commit comments

Comments
 (0)