Bug 18791 - TimeZoneInfo.Local is null on Android when device timezone wasn't set
Summary: TimeZoneInfo.Local is null on Android when device timezone wasn't set
Status: RESOLVED DUPLICATE of bug 4902
Alias: None
Product: Android
Classification: Xamarin
Component: BCL Class Libraries ()
Version: 4.12.0
Hardware: PC Windows
: Normal normal
Target Milestone: ---
Assignee: Jonathan Pryor
URL:
Depends on:
Blocks:
 
Reported: 2014-04-03 09:30 UTC by Andrew
Modified: 2014-04-22 11:10 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
sample project to reproduce the issue (10.35 KB, application/zip)
2014-04-03 09:30 UTC, Andrew
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED DUPLICATE of bug 4902

Description Andrew 2014-04-03 09:30:58 UTC
Created attachment 6484 [details]
sample project to reproduce the issue

After the recent Xamarin.Android update I found my application broken. It fails in Newtonsoft Json.Net serilizer (ver 6.0.2), when it serializes a Datetime value, with NullReferenceException:


------ Inner Exception ------
Message: Object reference not set to an instance of an object

Exception: System.NullReferenceException
Trace:
  at Newtonsoft.Json.Utilities.DateTimeUtils.GetUtcOffset (DateTime d) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.Utilities.DateTimeUtils.WriteDateTimeString (System.Char[] chars, Int32 start, DateTime value, Nullable`1 offset, DateTimeKind kind, DateFormatHandling format) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.JsonTextWriter.WriteValue (DateTime value) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.JsonWriter.WriteValue (Newtonsoft.Json.JsonWriter writer, PrimitiveTypeCode typeCode, System.Object value) [0x00000] in <filename unknown>:0 

The code is:

public static TimeSpan GetUtcOffset(this DateTime d)
{
    return TimeZoneInfo.get_Local().GetUtcOffset(d);
}

TimeZoneInfo.Local property returns null in the recent Xamarin build.

I'm using Xamarin.Android   4.12.02001 (a1e3982a)

I attached a clean sample projects that prints "true" to console, if TimeZoneInfo.Local is null:

var t = TimeZoneInfo.Local;
Console.WriteLine("t == null: " + (t == null));

04-03 13:19:50.261 I/mono-stdout( 1730): t == null: True
Comment 1 Andrew 2014-04-03 09:46:22 UTC
Tested on Android 4.1.1 (Genymotion emulator, Nexus 4, API 16)
Comment 2 Andrew 2014-04-03 10:03:01 UTC
More on this issue: I went to Android settings and selected another time zone (the original was 00:00 GMT) and TimeZoneInfo.Local started returning a value.

I traced the code that initializes that value, it can return null if there's an exception during initializaiton, and the exception is suppressed. IMHO it's a bad practice, leading to expected results on production (and it actually did in my case):

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\mscorlib.dll


internal static TimeZoneInfo GetTimeZone(string id)
      {
        if (id != null)
        {
          if (id == "GMT" || id == "UTC")
            return new TimeZoneInfo(id, TimeSpan.FromSeconds(0.0), id, id, id, (TimeZoneInfo.AdjustmentRule[]) null, true);
          if (id.StartsWith("GMT"))
            return new TimeZoneInfo(id, TimeSpan.FromSeconds((double) TimeZoneInfo.AndroidTimeZones.ParseNumericZone(id)), id, id, id, (TimeZoneInfo.AdjustmentRule[]) null, true);
        }
        try
        {
          return TimeZoneInfo.AndroidTimeZones._GetTimeZone(id);
        }
        catch (Exception ex)
        {
          return (TimeZoneInfo) null;
        }
      }


Can that code be chenged to either return some default timezone (for example 00:00) or rethrow the exception instead of returning null?

Thanks.
Comment 3 Ram Chandra 2014-04-04 10:25:36 UTC
I have tried to reproduce this  issue with attached project but I am unable to reproduce it.

When I debug the attached project, I observed that  I am getting the  value of variable t is "False" because of the "TimeZoneInfo.Local" is getting the "local timezone value" . I have also tried to change the values of Timezone and it is still returning the value of time zone. So, the value of variable t is always "False".

As per "comment 2" I have checked the definition of "GetTimeZone(string id)" in "assembly browser" and I observed that it returns "null" value when there is exception during initialization time.

Screencast: http://www.screencast.com/t/J0nREFtlV

Please let me know if I am missing anything.

Environment Info: 

Xamarin Studio
Version 4.2.3 (build 60)
Installation UUID: 851620d2-e950-4682-b459-991ccec9d895
Runtime:
 Microsoft .NET 4.0.30319.18408
 GTK+ 2.24.22 theme: MS-Windows
 GTK# (2.12.0.0)

Xamarin.Android
Version: 4.12.2 (Enterprise Edition)
Android SDK: D:\SDK\AndroidSDK
 Supported Android versions:
  2.1   (API level 7)
  2.2   (API level 8)
  2.3   (API level 10)
  3.1   (API level 12)
  3.2   (API level 13)
  4.0   (API level 14)
  4.0.3 (API level 15)
  4.1   (API level 16)
  4.2   (API level 17)
  4.3   (API level 18)
  4.4   (API level 19)
Java SDK: C:\Program Files (x86)\Java\jdk1.6.0_31
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) Client VM (build 20.6-b01, mixed mode, sharing)

Build Information
Release ID: 402030060
30c4afc300c2a39ec5300851357ce02e49dd217e
Build date: 2014-03-05 16:53:54Z
Xamarin addins: f8a9589b57c2bfab2ccd73c880e7ad81e3ecf044

Operating System
Windows 6.1.7601.65536 (64-bit)
Comment 4 Andrew 2014-04-04 11:01:04 UTC
All correct. I used Genymotion emulator for testing and get the null there. But since the exception is supressed, I can't investigate what's caused initialization error and give you more detail.

Note that the bug is visible by a naked eye in the code of GetTimeZone, in case of id parameter is null, the call tree will be:

TimeZoneInfo.GetTimeZone(id)
TimeZoneInfo.AndroidTimeZones._GetTimeZone(name)
TimeZoneInfo.ParseTZBuffer(name, ...)
TimeZoneInfo.CreateCustomTimeZone(id, ....)
TimeZoneInfo.CreateCustomTimeZone()
return new TimeZoneInfo(id, ...)

and there's a check for null in the TimeZoneInfo constructor:

if (id == null)
        throw new ArgumentNullException("id");


So, more likely TimeZoneInfo.GetTimeZone should not execute TimeZoneInfo.AndroidTimeZones._GetTimeZone if "id" parameter value is null, as it will guaranteed throw a null reference exception deeper by stacktrace.

In my case, with Genymotion emulator, I believe that GetDefaultTimeZoneName returned null, as "persist.sys.timezone" property was not returned by Android.

private static string GetDefaultTimeZoneName()
      {
        StringBuilder stringBuilder = new StringBuilder(93);
        if (TimeZoneInfo.AndroidTimeZones.__system_property_get("persist.sys.timezone", stringBuilder) > 0)
          return ((object) stringBuilder).ToString();
        else
          return (string) null;
      }

Btw, I found the same issue described here: https://bugzilla.xamarin.com/show_bug.cgi?id=4902

I run "adb shell getprop persist.sys.timezone" and it returned an empty string to console.

I have no idea about the probability of "persist.sys.timezone" prop can be absent on some real devices in real life... So you decide this issue severity.
Comment 5 Jonathan Pryor 2014-04-22 11:10:19 UTC
This should be a dupe of Bug #4902, that persist.sys.timezone shouldn't be the only way to specify the default timezone (as it's not always set).

*** This bug has been marked as a duplicate of bug 4902 ***