From ade02c3f670a9e9d590d0a30b389c1bfe8e6796b Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 12 Dec 2014 12:17:53 -0500 Subject: [PATCH] [mscorlib/Android] CultureInfo.ClearCachedData() clears DateTime. Context: https://bugzilla.xamarin.com/show_bug.cgi?id=24947 When an Android user changes the timezone, those TimeZone changes aren't reflected in Xamarin.Android apps. Part of this is a Xamarin.Android bug, in which it needs to listen for TimeZone change notifications and in turn let Mono know that the TimeZone changed. Xamarin.Android can/will call Thread.CurrentCulture.ClearCachedData() and Thread.CurrentUICulture.ClearCachedData() when the TimeZone has changed. This will allow Mono to lookup the TimeZone info again. At which point we hit two problems within Mono: 1. TimeZoneInfo.AndroidTimeZones.Local is unnecessarily cached. 2. DateTime itself caches the UTC offset for use by DateTime.Now. TimeZoneInfo.Local is *already* cached, and TimeZoneInfo.Local is properly cleared by TimeZoneInfo.ClearCachedData() while TimeZoneInfo.AndroidTimeZones.Local wasn't. Removing the extra cache allows the TimeZoneInfo to be looked up again. Which brings us to DateTime.Now: for my simple test case, after calling CultureInfo.ClearCachedData() the result of DateTime.Now.ToString() didn't reflect the newly current TimeZone. The cause for this was DateTime.to_local_time_span_object and DateTime.last_now, which DateTime.Now uses as a cache for the TimeZone's UTC offset. Since these DateTime fields weren't cleared, subsequent DateTime.Now invocations reported the *previous* TimeZone instead of the current timezone. To fix this, add an `internal` DateTime.ClearCachedData() method, and call DateTime.ClearCachedData() from CultureInfo.ClearCachedData(). --- mcs/class/System.Core/System/TimeZoneInfo.Android.cs | 10 ++-------- mcs/class/corlib/System.Globalization/CultureInfo.cs | 1 + mcs/class/corlib/System/DateTime.cs | 7 ++++++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mcs/class/System.Core/System/TimeZoneInfo.Android.cs b/mcs/class/System.Core/System/TimeZoneInfo.Android.cs index 8805dfe8982..b0f65d61dff 100644 --- a/mcs/class/System.Core/System/TimeZoneInfo.Android.cs +++ b/mcs/class/System.Core/System/TimeZoneInfo.Android.cs @@ -531,17 +531,11 @@ namespace System { return sign * (hour * 60) * 60; } - static readonly object _lock = new object (); - static TimeZoneInfo defaultZone; internal static TimeZoneInfo Local { get { - lock (_lock) { - if (defaultZone != null) - return defaultZone; - var id = GetDefaultTimeZoneName (); - return defaultZone = GetTimeZone (id, id); - } + var id = GetDefaultTimeZoneName (); + return defaultZone = GetTimeZone (id, id); } } diff --git a/mcs/class/corlib/System.Globalization/CultureInfo.cs b/mcs/class/corlib/System.Globalization/CultureInfo.cs index 5edf1fab803..1fde454eae0 100644 --- a/mcs/class/corlib/System.Globalization/CultureInfo.cs +++ b/mcs/class/corlib/System.Globalization/CultureInfo.cs @@ -377,6 +377,7 @@ namespace System.Globalization RegionInfo.ClearCachedData (); TimeZone.ClearCachedData (); + DateTime.ClearCachedData (); #if NET_4_5 TimeZoneInfo.ClearCachedData (); #endif diff --git a/mcs/class/corlib/System/DateTime.cs b/mcs/class/corlib/System/DateTime.cs index 8ff4901e4a3..8e64a783ecf 100644 --- a/mcs/class/corlib/System/DateTime.cs +++ b/mcs/class/corlib/System/DateTime.cs @@ -460,6 +460,11 @@ namespace System [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern long GetNow (); + internal static void ClearCachedData () + { + to_local_time_span_object = null; + } + // // To reduce the time consumed by DateTime.Now, we keep // the difference to map the system time into a local @@ -474,7 +479,7 @@ namespace System long now = GetNow (); DateTime dt = new DateTime (now); - if (Math.Abs (now - last_now) > TimeSpan.TicksPerMinute){ + if (to_local_time_span_object == null || Math.Abs (now - last_now) > TimeSpan.TicksPerMinute){ to_local_time_span_object = TimeZone.CurrentTimeZone.GetLocalTimeDiff (dt); last_now = now; -- 2.25.1