I need to convert an RFC-3339 formatted timestamp (e.g. "2024-01-04T14:30:00.119919872Z") to a unix nanosecond timestamp (e.g. 1704378600119919872). However, the C# DateTime structures maximum precision is only 100 nanoseconds. For example:
string timestamp = "2024-01-04T14:30:00.119919872Z";
DateTime dt = DateTime.Parse(timestamp);
Console.WriteLine(dt.ToString("O")); // outputs: 2024-01-04T09:30:00.1199199-05:00
So the fractional seconds components of the timestamp get rounded to - 1199199 - the nearest 100 nanoseconds. Apparently, 100 nanoseconds is the DateTime structures precision.
To avoid this loss of precision, I've written my own parsing method, but it's very ugly -
public static long ToUnixNanoseconds(string str)
{
string dateTimeStr = str[..19];
DateTime utcDateTime = DateTime.Parse(dateTimeStr + "Z");
long unixTimeSeconds = (new DateTimeOffset(utcDateTime)).ToUnixTimeSeconds();
string fractionalSecondsStr = str[19..(str.Length - 1)];
decimal fractionalSeconds = decimal.Parse(fractionalSecondsStr);
long unixNano = (long)((unixTimeSeconds + fractionalSeconds) * 1000000000);
return unixNano;
}
What better ways are there to convert an RFC-3339 timestamp to a unix timestamp with nanosecond precision in C#?
Your parsing method seems okay, if you always expect that same input format and don't want to include a full library just for this one use case (although Noda Time is really good.)
You could do a little tweaking. Here's my approach:
public static long ToUnixNanoseconds(ReadOnlySpan<char> timestamp)
{
var seconds = DateTimeOffset.Parse(timestamp[0..19], CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToUnixTimeSeconds();
var fractionalSeconds = decimal.Parse(timestamp[19..^1], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture);
return (long)((seconds + fractionalSeconds) * 1000000000);
}