@@ -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