Converting the date given from Apple receipts to a .net DateTime object

Although it's probably something simple - I couldn't find any place that gives any (correct) solution for it...

Apple receipts return dates in RFC 3339 It looks like that:

2016-08-10 19:47:16 America/Los_Angeles

2016-08-11 02:42:16 Etc/GMT

Any solution I found does not handle the timezone correctly... for example: DateTime object doesn' seem to have a string converter for this format at all.

Another solution I found:

string tTranDatStr = "2016-08-11 02:42:16 Etc/GMT";
trans_date = XmlConvert.ToDateTime(tTranDatStr, XmlDateTimeSerializationMode.Local);

But it throws:

The string '2016-08-11 02:42:16 Etc/GMT' is not a valid AllXsd value.

Is there any elegant solution that is also correct (converts the time to the current locale timezone...)?

THANKS!!

Jon Skeet
people
quotationmark

.NET has no built-in support for the zoneinfo/Olson/tz/IANA time zones (whatever you want to call them...) that are being used here. Fortunately, my Noda Time project does.

Here's some code using Noda Time 1.3.2 which successfully parses both the sample values you've given. The natural type for the data you've presented is ZonedDateTime, which is a date and time in a known time zone. Next, you could convert it to an OffsetDateTime, which is a bit like .NET's DateTimeOffset (which you can convert it to).

Personally I'd recommend trying to use the Noda Time types throughout your code - the aim of the project is to make date/time code a lot less fiddly and error-prone. If you really need to convert to the BCL types though, you can certainly do so.

using System;
using NodaTime;
using NodaTime.Text;

class Program
{
    private static readonly ZonedDateTimePattern ApplePattern =
        ZonedDateTimePattern.CreateWithInvariantCulture(
            "yyyy-MM-dd HH:mm:ss z", DateTimeZoneProviders.Tzdb);

    static void Main(string[] args)
    {
        ParseApple("2016-08-10 19:47:16 America/Los_Angeles");
        ParseApple("2016-08-11 02:42:16 Etc/GMT");
    }

    static void ParseApple(string text)
    {
        Console.WriteLine($"Parsing {text}");
        ParseResult<ZonedDateTime> result = ApplePattern.Parse(text);
        if (!result.Success)
        {
            Console.WriteLine($"Parse failed! {result.Exception.Message}");
            return;
        }
        ZonedDateTime zonedValue = result.Value;
        Console.WriteLine($"ZonedDateTime: {zonedValue}");
        // OffsetDateTime is a Noda Time type...
        OffsetDateTime offsetValue = zonedValue.ToOffsetDateTime();
        Console.WriteLine($"OffsetDateTime: {offsetValue}");
        // DateTimeOffset is the BCL type...
        DateTimeOffset dto = offsetValue.ToDateTimeOffset();
        Console.WriteLine($"DateTimeOffset: {dto}");
        Console.WriteLine();
    }
}

Output:

Parsing 2016-08-10 19:47:16 America/Los_Angeles
ZonedDateTime: 2016-08-10T19:47:16 America/Los_Angeles (-07)
OffsetDateTime: 2016-08-10T19:47:16-07
DateTimeOffset: 10/08/2016 19:47:16 -07:00

Parsing 2016-08-11 02:42:16 Etc/GMT
ZonedDateTime: 2016-08-11T02:42:16 Etc/GMT (+00)
OffsetDateTime: 2016-08-11T02:42:16Z
DateTimeOffset: 11/08/2016 02:42:16 +00:00

people

See more on this question at Stackoverflow