Skip to content

Commit c9fbbad

Browse files
author
Steve Pfister
committed
[Android] Update DateTimeOffset.Now fast path routine
dotnet#74965 contained improvements for the routine. This change brings them back to main.
1 parent 4486805 commit c9fbbad

File tree

1 file changed

+25
-41
lines changed

1 file changed

+25
-41
lines changed

src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.Android.cs

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ namespace System
77
{
88
public readonly partial struct DateTimeOffset
99
{
10-
private static bool s_androidTZDataLoaded;
11-
private static readonly object s_localUtcOffsetLock = new();
12-
private static Thread? s_loadAndroidTZData;
13-
private static bool s_startNewBackgroundThread = true;
10+
// 0 == in process of being loaded, 1 == loaded
11+
private static volatile int s_androidTZDataLoaded = -1;
1412

1513
// Now on Android does the following
1614
// 1) quickly returning a fast path result when first called if the right AppContext data element is set
@@ -29,52 +27,38 @@ public static DateTimeOffset Now
2927
{
3028
DateTime utcDateTime = DateTime.UtcNow;
3129

32-
if (s_androidTZDataLoaded) // The background thread finished, the cache is loaded.
30+
if (s_androidTZDataLoaded == 1) // The background thread finished, the cache is loaded.
31+
{
3332
return ToLocalTime(utcDateTime, true);
33+
}
3434

35-
if (s_startNewBackgroundThread) // The cache isn't loaded and no background thread has been created
35+
object? localDateTimeOffset = AppContext.GetData("System.TimeZoneInfo.LocalDateTimeOffset");
36+
if (localDateTimeOffset == null) // If no offset property provided through monovm app context, default
3637
{
37-
lock (s_localUtcOffsetLock)
38-
{
39-
// Now may be called multiple times before a cache is loaded and a background thread is running,
40-
// once the lock is available, check for a cache and background thread.
41-
if (s_androidTZDataLoaded)
42-
return ToLocalTime(utcDateTime, true);
38+
// no need to create the thread, load tzdata now
39+
s_androidTZDataLoaded = 1;
40+
return ToLocalTime(utcDateTime, true);
41+
}
4342

44-
if (s_loadAndroidTZData == null)
43+
// The cache isn't loaded yet.
44+
if (Interlocked.CompareExchange(ref s_androidTZDataLoaded, 0, -1) == -1)
45+
{
46+
new Thread(() =>
47+
{
48+
try
4549
{
46-
s_loadAndroidTZData = new Thread(() => {
47-
// Delay the background thread to avoid impacting startup, if it still coincides after 1s, startup is already perceived as slow
48-
Thread.Sleep(1000);
49-
50-
_ = TimeZoneInfo.Local; // Load AndroidTZData
51-
s_androidTZDataLoaded = true;
50+
// Delay the background thread to avoid impacting startup, if it still coincides after 1s, startup is already perceived as slow
51+
Thread.Sleep(1000);
5252

53-
lock (s_localUtcOffsetLock)
54-
{
55-
s_loadAndroidTZData = null; // Ensure thread is cleared when cache is loaded
56-
}
57-
});
58-
s_loadAndroidTZData.IsBackground = true;
53+
_ = TimeZoneInfo.Local; // Load AndroidTZData
5954
}
60-
}
61-
62-
if (s_startNewBackgroundThread)
63-
{
64-
// Because Start does not block the calling thread,
65-
// setting the boolean flag to false immediately after should
66-
// prevent two calls to DateTimeOffset.Now in quick succession
67-
// from both reaching here.
68-
s_loadAndroidTZData.Start();
69-
s_startNewBackgroundThread = false;
70-
}
55+
finally
56+
{
57+
s_androidTZDataLoaded = 1;
58+
}
59+
}) { IsBackground = true }.Start();
7160
}
7261

73-
74-
object? localDateTimeOffset = AppContext.GetData("System.TimeZoneInfo.LocalDateTimeOffset");
75-
if (localDateTimeOffset == null) // If no offset property provided through monovm app context, default
76-
return ToLocalTime(utcDateTime, true);
77-
7862
// Fast path obtained offset incorporated into ToLocalTime(DateTime.UtcNow, true) logic
7963
int localDateTimeOffsetSeconds = Convert.ToInt32(localDateTimeOffset);
8064
TimeSpan offset = TimeSpan.FromSeconds(localDateTimeOffsetSeconds);

0 commit comments

Comments
 (0)