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