0

From time to time I need to send a simple email to clients with the data that we store in the objects. However the objects have the date time stored as a long? Unix Timestamp. Obviously this format is not readable for the ordinary mortals and has to be converted to something understandable for the customers. I cannot change the type of the timestamps from long to DateTime because it would break the code in many places. So far I could come up with one solution which uses custom converter for the JSON Serializer. However, I don't want to break the logic of the deserialization process. I would love to omit implementing the Read function in the Converter but if I do so I get errors. What I'm trying to do is to return just the reader's value? I think?

Can someone say if this code will not break the deserialization process of the JsonSerializer? Otherwise it would be very bad.

Or maybe there is any better solution for swapping long number for pretty date in a JSON file?

EDIT: Kinda as expected, the code blew up the application but not because of the wrong Read function but because it was crashing when trying to deserialize before serialized object. It was expecting long but was getting a nicely looking date. My workaround is to use the option WriteIndented to decide if I want the long? timestamp to be serialized as long or as a nicely looking date.

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

public class EpochToDateJSONSerializeConverter : JsonConverter<long?>
    {
        public override long? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if(reader.TryGetInt64(out long currentValue))
            {
                return currentValue;
            }
            return null;
        }

        public override void Write(Utf8JsonWriter writer, long? value, JsonSerializerOptions options)
        {
            if (options.WriteIndented)
            {
                if (value.HasValue)
                {
                    long unixTimeStamp = value.Value;
                    DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
                    dtDateTime = dtDateTime.AddMilliseconds(unixTimeStamp).ToLocalTime();
                    writer.WriteStringValue(dtDateTime.ToString());
                }
                else
                {
                    writer.WriteStringValue("null");
                }
            }
            else
            {
                if (value == null) writer.WriteStringValue("null");
                else writer.WriteNumberValue(value.Value);
            }
        }
    }

I've been testing the Converter on a simple Car class. It's important that only chosen long? properties are changed to nicely looking date and other stay untouched.

public class Car
    {
        public string Name { get; set; }
        public long? Kilometrage { get; set; }
        [JsonConverter(typeof(EpochToDateJSONSerializeConverter))]
        public long? ProductionDate { get; set; }
    }

In Main:

    Car car = new Car() { Name = "MyCar", Kilometrage = 69, ProductionDate = 1589277616910};
    Console.WriteLine(JsonSerializer.Serialize(car));
LilacBlue
  • 173
  • 1
  • 9

1 Answers1

0

If you don't mind a DateTimeOffset instead of a DateTime, there's always DateTimeOffset.FromUnixTimeSeconds and its inverse .ToUnixTimeSeconds

Powerlord
  • 87,612
  • 17
  • 125
  • 175
  • `DateTimeOffset.FromUnixTimeMilliseconds` and `.ToUnixTimeMilliseconds` also exist if you have to deal with times from Java and the like. – Powerlord Jun 10 '20 at 14:44