I'm having an issue converting a parsed string
into a correct NodaTime ZonedDateTime
. The below method takes a string (allegedly in UTC) pushed by the brokers server, and returns a ZonedDateTime
with the DateTimeZone
being set to UTC. The domain model will only accept ZonedDateTime
objects so this is happening at the system boundary.
For example, a string
being passed as the argument being exactly '2017060623:20:10' would then return a ZonedDateTime
like 2017-06-06T13-:20:10 (curiously a ten hour difference, my local time zone here in Sydney is +10 UTC).
public static ZonedDateTime GetZonedDateTimeUtcFromMarketDataString(string dateTime)
{
var dotNetDateTime = DateTime.ParseExact(
dateTime,
"yyyyMMddHH:mm:ss,
CultureInfo.InvariantCulture)
.ToUniversalTime();
return new ZonedDateTime(Instant.FromDateTimeUtc(dotNetDateTime), DateTimeZone.Utc);
}
So I changed the method to the below, which works, but I'm sure there's a better way. I'm certain my error is that I'm somehow involving my local time zone, rather than keeping everything in UTC.
public static ZonedDateTime GetZonedDateTimeUtcFromMarketDataString(string dateTime)
{
var parsedDateTime = DateTime.ParseExact(
dateTime,
"yyyyMMddHH:mm:ss",
CultureInfo.InvariantCulture);
var dotNetDateTime = new DateTime(
parsedDateTime.Year,
parsedDateTime.Month,
parsedDateTime.Day,
parsedDateTime.Hour,
parsedDateTime.Minute,
parsedDateTime.Second,
DateTimeKind.Utc);
return new ZonedDateTime(Instant.FromDateTimeUtc(dotNetDateTime), DateTimeZone.Utc);
}
I would suggest not using DateTime
at all. You're using Noda Time - so go all in :)
To parse text as a ZonedDateTime
, you use a ZonedDateTimePattern
. Here's an example:
using System;
using NodaTime;
using NodaTime.Text;
class Program
{
static void Main(string[] args)
{
string text = "2017060623:20:10";
Console.WriteLine(GetZonedDateTimeUtcFromMarketDataString(text));
}
static readonly ZonedDateTimePattern ParsePattern =
ZonedDateTimePattern.CreateWithInvariantCulture(
"yyyyMMddHH:mm:ss",
DateTimeZoneProviders.Tzdb); // Won't actually be used...
static ZonedDateTime GetZonedDateTimeUtcFromMarketDataString(string dateTime)
=> ParsePattern.Parse(dateTime).Value;
}
The default template value already uses UTC as a time zone, so you don't need to worry about that.
Alternatively, you could use a LocalDateTimePattern
given that the text you're using doesn't specify a time zone - parse to a LocalDateTime
and then call LocalDateTime.InUtc()
.
All of this raises another question though, which is why you're parsing the value to a ZonedDateTime
at all. If you've always got a UTC value, do you really need it to be a ZonedDateTime
rather than an Instant
? You don't know the time zone the value was originally observed in, so it feels more like a point in time to me.
See more on this question at Stackoverflow