Skip to content

Commit f98cda4

Browse files
committed
improve timezone support
1 parent 869fecc commit f98cda4

File tree

2 files changed

+65
-32
lines changed

2 files changed

+65
-32
lines changed

src/Serilog.Sinks.AzureTableStorage/Sinks/AzureTableStorage/DefaultKeyGenerator.cs

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Dynamic;
23
using System.Threading;
34

45
using Azure.Data.Tables;
@@ -11,6 +12,7 @@ namespace Serilog.Sinks.AzureTableStorage;
1112
/// <summary>
1213
/// Default document key generator
1314
/// </summary>
15+
/// <seealso cref="Serilog.Sinks.AzureTableStorage.IKeyGenerator" />
1416
public class DefaultKeyGenerator : IKeyGenerator
1517
{
1618
private const string PartitionKeyName = nameof(ITableEntity.PartitionKey);
@@ -31,7 +33,7 @@ public virtual string GeneratePartitionKey(LogEvent logEvent, AzureTableStorageS
3133
// batch insert is used to get around time based partition key performance issues
3234
// values are created in reverse chronological order so newest are always first
3335

34-
var utcEventTime = logEvent.Timestamp.UtcDateTime;
36+
var utcEventTime = logEvent.Timestamp;
3537
var partitionKeyRounding = options?.PartitionKeyRounding;
3638

3739
return GeneratePartitionKey(utcEventTime, partitionKeyRounding);
@@ -50,7 +52,7 @@ public virtual string GenerateRowKey(LogEvent logEvent, AzureTableStorageSinkOpt
5052

5153
// row key created in reverse chronological order so newest are always first
5254

53-
var utcEventTime = logEvent.Timestamp.UtcDateTime;
55+
var utcEventTime = logEvent.Timestamp;
5456
return GenerateRowKey(utcEventTime);
5557
}
5658

@@ -68,7 +70,12 @@ public virtual string GenerateRowKey(LogEvent logEvent, AzureTableStorageSinkOpt
6870
/// </remarks>
6971
public static string GeneratePartitionKey(DateTimeOffset eventTime, TimeSpan? roundSpan = null)
7072
{
71-
return GeneratePartitionKey(eventTime.UtcDateTime, roundSpan);
73+
var span = roundSpan ?? TimeSpan.FromMinutes(5);
74+
var dateTime = eventTime.ToUniversalTime();
75+
var roundedEvent = dateTime.Round(span);
76+
77+
// create a 19 character String for reverse chronological ordering.
78+
return $"{DateTimeOffset.MaxValue.Ticks - roundedEvent.Ticks:D19}";
7279
}
7380

7481
/// <summary>
@@ -84,12 +91,10 @@ public static string GeneratePartitionKey(DateTimeOffset eventTime, TimeSpan? ro
8491
/// </remarks>
8592
public static string GeneratePartitionKey(DateTime eventTime, TimeSpan? roundSpan = null)
8693
{
87-
var span = roundSpan ?? TimeSpan.FromMinutes(5);
8894
var dateTime = eventTime.ToUniversalTime();
89-
var roundedEvent = dateTime.Round(span);
95+
var dateTimeOffset = new DateTimeOffset(dateTime, TimeSpan.Zero);
9096

91-
// create a 19 character String for reverse chronological ordering.
92-
return $"{DateTime.MaxValue.Ticks - roundedEvent.Ticks:D19}";
97+
return GeneratePartitionKey(dateTimeOffset, roundSpan);
9398
}
9499

95100

@@ -102,7 +107,13 @@ public static string GeneratePartitionKey(DateTime eventTime, TimeSpan? roundSpa
102107
/// </returns>
103108
public static string GenerateRowKey(DateTimeOffset eventTime)
104109
{
105-
return GenerateRowKey(eventTime.UtcDateTime);
110+
var dateTime = eventTime.ToUniversalTime();
111+
112+
// create a reverse chronological ordering date, newest logs sorted first
113+
var timestamp = dateTime.ToReverseChronological();
114+
115+
// use Ulid for speed and efficiency
116+
return Ulid.NewUlid(timestamp).ToString();
106117
}
107118

108119
/// <summary>
@@ -115,12 +126,9 @@ public static string GenerateRowKey(DateTimeOffset eventTime)
115126
public static string GenerateRowKey(DateTime eventTime)
116127
{
117128
var dateTime = eventTime.ToUniversalTime();
129+
var dateTimeOffset = new DateTimeOffset(dateTime, TimeSpan.Zero);
118130

119-
// create a reverse chronological ordering date, newest logs sorted first
120-
var timestamp = dateTime.ToReverseChronological();
121-
122-
// use Ulid for speed and efficiency
123-
return Ulid.NewUlid(timestamp).ToString();
131+
return GenerateRowKey(dateTimeOffset);
124132
}
125133

126134

@@ -129,11 +137,30 @@ public static string GenerateRowKey(DateTime eventTime)
129137
/// Generates the partition key query using the specified <paramref name="date"/>.
130138
/// </summary>
131139
/// <param name="date">The date to use for query.</param>
140+
/// <param name="offset">The date's offset from Coordinated Universal Time (UTC).</param>
141+
/// <returns>An Azure Table partiion key query.</returns>
142+
public static string GeneratePartitionKeyQuery(DateOnly date, TimeSpan offset)
143+
{
144+
// date is assumed to be in local time, will be converted to UTC
145+
var eventTime = new DateTimeOffset(date.Year, date.Month, date.Day, 0, 0, 0, offset);
146+
return GeneratePartitionKeyQuery(eventTime);
147+
}
148+
149+
/// <summary>
150+
/// Generates the partition key query using the specified <paramref name="date"/>.
151+
/// </summary>
152+
/// <param name="date">The date to use for query.</param>
153+
/// <param name="zone">The time zone the date is in.</param>
132154
/// <returns>An Azure Table partiion key query.</returns>
133-
public static string GeneratePartitionKeyQuery(DateOnly date)
155+
public static string GeneratePartitionKeyQuery(DateOnly date, TimeZoneInfo zone = null)
134156
{
135157
// date is assumed to be in local time, will be converted to UTC
136-
var eventTime = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Local);
158+
zone ??= TimeZoneInfo.Local;
159+
160+
var dateTime = date.ToDateTime(TimeOnly.MinValue);
161+
var offset = zone.GetUtcOffset(dateTime);
162+
163+
var eventTime = new DateTimeOffset(dateTime, offset);
137164
return GeneratePartitionKeyQuery(eventTime);
138165
}
139166
#endif
@@ -146,11 +173,9 @@ public static string GeneratePartitionKeyQuery(DateOnly date)
146173
public static string GeneratePartitionKeyQuery(DateTime eventTime)
147174
{
148175
var dateTime = eventTime.ToUniversalTime();
176+
var dateTimeOffset = new DateTimeOffset(dateTime, TimeSpan.Zero);
149177

150-
var upper = dateTime.ToReverseChronological().Ticks.ToString("D19");
151-
var lower = dateTime.AddDays(1).ToReverseChronological().Ticks.ToString("D19");
152-
153-
return $"({PartitionKeyName} ge '{lower}') and ({PartitionKeyName} lt '{upper}')";
178+
return GeneratePartitionKeyQuery(dateTimeOffset);
154179
}
155180

156181
/// <summary>
@@ -160,7 +185,12 @@ public static string GeneratePartitionKeyQuery(DateTime eventTime)
160185
/// <returns>An Azure Table partiion key query.</returns>
161186
public static string GeneratePartitionKeyQuery(DateTimeOffset eventTime)
162187
{
163-
return GeneratePartitionKeyQuery(eventTime.UtcDateTime);
188+
var dateTime = eventTime.ToUniversalTime();
189+
190+
var upper = dateTime.ToReverseChronological().Ticks.ToString("D19");
191+
var lower = dateTime.AddDays(1).ToReverseChronological().Ticks.ToString("D19");
192+
193+
return $"({PartitionKeyName} ge '{lower}') and ({PartitionKeyName} lt '{upper}')";
164194
}
165195

166196
}

test/Serilog.Sinks.AzureTableStorage.Tests/DefaultKeyGeneratorTests.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public void GenerateRowKeyDateTimeOffsetNow()
3232
parsed.Should().BeTrue();
3333
ulid.Should().NotBeNull();
3434

35-
var reversed = dateTime.ToReverseChronological();
35+
var reversed = dateTime.ToUniversalTime().ToReverseChronological();
3636
var ulidDate = ulid.Time;
3737

3838
ulidDate.Year.Should().Be(reversed.Year);
@@ -56,16 +56,17 @@ public void GeneratePartitionKeyDateTimeOffsetNow()
5656
[Fact]
5757
public void GeneratePartitionKeyDateTimeNow()
5858
{
59-
var dateTime = new DateTime(2024, 4, 1, 23, 0, 0, DateTimeKind.Local);
59+
var dateTime = new DateTimeOffset(2024, 4, 1, 23, 0, 0, TimeSpan.FromHours(-5));
60+
var eventTime = dateTime.UtcDateTime;
6061

61-
var partitionKey = DefaultKeyGenerator.GeneratePartitionKey(dateTime);
62+
var partitionKey = DefaultKeyGenerator.GeneratePartitionKey(eventTime);
6263
partitionKey.Should().NotBeNull();
6364
partitionKey.Should().Be("2516902703999999999");
6465
}
6566

6667
[Theory]
6768
[MemberData(nameof(GetDateRounding))]
68-
public void GeneratePartitionKeyDateTimeNowRound(DateTime dateTime, string expected)
69+
public void GeneratePartitionKeyDateTimeNowRound(DateTimeOffset dateTime, string expected)
6970
{
7071
var partitionKey = DefaultKeyGenerator.GeneratePartitionKey(dateTime);
7172
partitionKey.Should().NotBeNull();
@@ -76,46 +77,48 @@ public static IEnumerable<object[]> GetDateRounding()
7677
{
7778
yield return new object[]
7879
{
79-
new DateTime(2024, 4, 1, 23, 1, 0, DateTimeKind.Local),
80+
new DateTimeOffset(2024, 4, 1, 23, 1, 0, TimeSpan.FromHours(-5)),
8081
"2516902703999999999"
8182
};
8283
yield return new object[]
8384
{
84-
new DateTime(2024, 4, 1, 23, 2, 55, DateTimeKind.Local),
85+
new DateTimeOffset(2024, 4, 1, 23, 2, 55, TimeSpan.FromHours(-5)),
8586
"2516902700999999999"
8687
};
8788
yield return new object[]
8889
{
89-
new DateTime(2024, 4, 1, 23, 3, 5, DateTimeKind.Local),
90+
new DateTimeOffset(2024, 4, 1, 23, 3, 5, TimeSpan.FromHours(-5)),
9091
"2516902700999999999"
9192
};
9293
yield return new object[]
9394
{
94-
new DateTime(2024, 4, 1, 23, 4, 11, DateTimeKind.Local),
95+
new DateTimeOffset(2024, 4, 1, 23, 4, 11, TimeSpan.FromHours(-5)),
9596
"2516902700999999999"
9697
};
9798
yield return new object[]
9899
{
99-
new DateTime(2024, 4, 1, 23, 4, 43, DateTimeKind.Local),
100+
new DateTimeOffset(2024, 4, 1, 23, 4, 43, TimeSpan.FromHours(-5)),
100101
"2516902700999999999"
101102
};
102103
}
104+
103105
[Fact]
104106
public void GeneratePartitionKeyQueryDateOnly()
105107
{
106108
var date = new DateOnly(2024, 4, 1);
107109

108-
var partitionKeyQuery = DefaultKeyGenerator.GeneratePartitionKeyQuery(date);
110+
var partitionKeyQuery = DefaultKeyGenerator.GeneratePartitionKeyQuery(date, TimeSpan.FromHours(-5));
109111
partitionKeyQuery.Should().NotBeNull();
110112
partitionKeyQuery.Should().Be("(PartitionKey ge '2516902667999999999') and (PartitionKey lt '2516903531999999999')");
111113
}
112114

113115
[Fact]
114116
public void GeneratePartitionKeyQueryDateTime()
115117
{
116-
var dateTime = new DateTime(2024, 4, 1, 0, 0, 0, DateTimeKind.Local);
118+
var dateTime = new DateTimeOffset(2024, 4, 1, 0, 0, 0, TimeSpan.FromHours(-5));
119+
var eventTime = dateTime.UtcDateTime;
117120

118-
var partitionKeyQuery = DefaultKeyGenerator.GeneratePartitionKeyQuery(dateTime);
121+
var partitionKeyQuery = DefaultKeyGenerator.GeneratePartitionKeyQuery(eventTime);
119122
partitionKeyQuery.Should().NotBeNull();
120123
partitionKeyQuery.Should().Be("(PartitionKey ge '2516902667999999999') and (PartitionKey lt '2516903531999999999')");
121124
}

0 commit comments

Comments
 (0)