Xamarin.Android JSON.Net serilization fails on 4.2.2 device only TimeZoneNotFound exception

I am using JSON.Net to serialize a DTO and I am getting the following exception on the physical device. THis works on all other devices we have tested on, but is failing on the Samsung Galaxy Tab 3lite SM-T110 running version 4.2.2.

I was having this issue but when I upgraded to Xamarin 3.0, it turned into this below:

06-03 21:17:41.687 E/mono-rt (22071): [ERROR] FATAL UNHANDLED EXCEPTION: System.TimeZoneNotFoundException: Exception of type 'System.TimeZoneNotFoundException' was thrown.
06-03 21:17:41.687 E/mono-rt (22071):   at System.TimeZoneInfo.get_Local () [0x00000] in <filename unknown>:0 
06-03 21:17:41.687 E/mono-rt (22071):   at Newtonsoft.Json.Utilities.DateTimeUtils.GetUtcOffset (DateTime d) [0x00000] in <filename unknown>:0 
06-03 21:17:41.687 E/mono-rt (22071):   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 
06-03 21:17:41.687 E/mono-rt (22071):   at Newtonsoft.Json.JsonTextWriter.WriteValue (DateTime value) [0x00000] in <filename unknown>:0 
06-03 21:17:41.687 E/mono-rt (22071):   at Newtonsoft.Json.JsonWriter.WriteValue (Newtonsoft.Json.JsonWriter writer, PrimitiveTypeCode typeCode, System.Object value) [0x00000] in <filename unknown>:0 
06-03 21:17:41.687 E/mono-rt (22071):   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializePrimitive (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonPrimitiveContract contract, Newtonsoft.Json.Serialization.
06-03 21:17:41.695 I/mono-stdout(22071): Executing Command: UpdateRegistration
The program 'Mono' has exited with code 0 (0x0).

EDIT This is the DTO that I am trying to serialize. You can see when the constructor gets called, it sets it to DateTime.Now. Shouldnt this just assume the local timezone?

  public class RecordTargetFrequency : BaseCommand, ICommand {
        public Guid TargetId { get; private set; }
        public Guid? LocationId { get; private set; }
        public Guid TherapistId { get; private set; }
        public bool? Increase { get; private set; }
        public DateTime TimeStamp { get; private set; }

        public RecordTargetFrequency(Guid targetId, Guid? locationId, Guid therapistId, bool? increase) {
            TimeStamp = DateTime.Now;
            TargetId = targetId;
            LocationId = locationId;
            TherapistId = therapistId;
            Increase = increase;
        }

        public void Validate() {
            ValidateGuid(TargetId);
            ValidateGuid(TherapistId);
        }
    }

I am then serializing it with this line:

JsonConvert.SerializeObject(executedCommand);
Jon Skeet
people
quotationmark

Yes, TimeZoneInfo.Local is somewhat broken on Mono. I've seen three different failure modes here:

  • Returning a time zone which acts correctly, but has an ID of "Local"
  • Returning a null reference
  • Throwing an exception

I don't have a good solution for that, but if you're trying to record a timestamp, it would be a much better idea to use DateTime.UtcNow anyway. Then you don't need to worry about time zones at all. In most cases, you should be storing and handling date/time values just in terms of an instant in time, without caring about the time zone or even which calendar is involved.

If you can get a time zone ID from Java.Util.TimeZone.Default as it looks like you can - you'd want America/New_York here - then another alternative is to use my Noda Time project, which includes the IANA database. So you could create a ZonedDateTime which represents exactly what you need. We support Json.NET serialization too, so that part shouldn't be a problem.

Again though, I would encourage you to just use UTC unless you really need the local time.

A couple more options - you might want to consider using DateTimeOffset instead of DateTime; if you're just trying to serialize the value as "a date and time with a UTC offset" then DateTimeOffset.Now might do exactly what you want.

(If none of this helps, please give more context as to what you need and what you expect the JSON to look like.)

people

See more on this question at Stackoverflow