Search code examples
c#.net-core

How do I store a record property as a uint but render it as a DateTime?


Minimal example dotnet fiddle available here.

I have to wrap a 3rd-party API that stores dates as uint seconds post-epoch, but want to present them to consumers of my API as DateTime values. The mechanics of get/init the DTO record property is tripping me up. If I do as below, then I get a "can't implicitly convert from uint to DateTime" error:

public static void Main()
{
    var foobar = new FoobarModel() { created = (uint)1725747561 };
}


public static class TimeConverter
{
    public static DateTime ConvertFromUnixTimestamp(uint timestamp) =>
        DateTime.UnixEpoch.AddSeconds((double)timestamp);

    public static uint? ConvertToUnixTimestamp(DateTime date) =>
        (uint)Math.Floor((date!.ToUniversalTime() - DateTime.UnixEpoch).TotalSeconds);
}

public record FoobarModel
{
    private uint? _created;
    public DateTime? created
    {
        get => created != null
            ? TimeConverter.ConvertFromUnixTimestamp(_created!.Value)
            : null;
        init => _created = value != null
            ? TimeConverter.ConvertToUnixTimestamp(value!.Value)
            : null;
    }

    public FoobarModel() { }
}

I have to be able to instantiate a FoobarModel with uint data, but clearly my FoobarModel.created.init method isn't able to accept uint. How do I make this situation work?

(Please forgive the FoobarModel property capitalization conventions, they match the 3rd party API. Also, eventually I would like to deserialize a JSON string with this property, so the fiddle has a little JSON code available.)


Solution

  • Consider keeping the formatted DateTime as a separate non-serialized value if you want to dual-purpose the model:

    public static class TimeConverter
    {
        public static DateTime ConvertFromUnixTimestamp(uint timestamp) =>
            DateTime.UnixEpoch.AddSeconds((double)timestamp);
        public static DateTime? ConvertFromUnixTimestamp(uint? timestamp) =>
            timestamp == null ? (DateTime?) null : ConvertFromUnixTimestamp(timestamp!);
    
        public static uint ConvertToUnixTimestamp(DateTime date) =>
            (uint)Math.Floor((date.ToUniversalTime() - DateTime.UnixEpoch).TotalSeconds);
    }
    
    public uint? created { get; init; }
    [JsonIgnore]
    public DateTime? createdDateTime
    {
        get => TimeConverter.ConvertFromUnixTimestamp(created)
    }
    

    I also just moved the #nullable handling into the converter.

    The serialization/deserialization as well as any initialization continues to use the uint epoch values. Where you want to display it as a date-time use the createdDateTime property.