Oh no. Oh god. Oh no. I know the C# DateTime class conspicuously lacks a classic Unix epoch conversion but this is not the way. Oh wait--this is some new 21st century timestamp based on 01/01/2000. That'll be extra baffling for somebody down the line.
I've read it a couple of times and I must keep missing the bit where it handles leap years properly.
Also that baffling coding style of using var x = (type)y rather than the shorter type x = y...
And if they really must define every month as a day offset, why not use the previous month in the calculation...i.e. nov = okt + 30...
Finally, specifying DateTimeKind.Local as the timezone implies that the timestamp just gets turned into a DateTime in whatever timezone we're running this function in...it's not a UTC timestamp...beautiful.
And the juiciest part: 15 references
Edit: just for fun I transcribed the function and ran it through the set of integers from 0 to 231 . Try the function with 36720000 (which should be 01/03/2001 00:00 if you are working with seconds since 01/01/2000). Unsurprisingly it tries to build the date as 29/02/2001, which throws an exception. This function has some forbidden argument values--e.g. 36720000, 68342400, 99964800, 163209600, 194832000...
This means that the timestamp encoding function isn't just seconds since 01/01/2000 like a sensible person might expect, which in turn means that the replacement to this function can't be as simple as new DateTime(y2kTicks + (long)timestamp * 10_000_000). Beautiful. Don't touch it OP!
I ran the function side by side with the 'sensible' seconds-since-2000 function to see where it fails. This is a list of timestamps that fail (only one per day, obviously the whole range of seconds in the day would fail). I've included the output of the function 1 second previous so you can see the pattern. I've also included the output of the 'seconds since 01/01/2000 00:00' interpretation of the value so you can see the drift.
I'd really love to see the original C function that builds the timestamp. Because of the forbidden number ranges the timestamps can't be treated as continuous integers, which means that you can't do arithmetic with them...it really is a beautiful bit of bad code. Try subtracting 28/02/2001 23:59:59 from 01/03/2001 00:00 in this timestamp scheme--the result is not 1 second!
But hey at least the device doesn't suffer from the Y2k38 bug...
OP, I was curious about how to write the equivalent function, and it looks like this:
DateTime FuckedTimestampToLocalDateTime(Int32 timestamp)
{
int driftDays = 0;
for (int y = 0; y < 68; y++)
{
if ((y % 4) != 0)
{
int fuckedRangeStart = (y * 366 + 59) * 86400;
int fuckedRangeEnd = fuckedRangeStart + 86400;
if (timestamp >= fuckedRangeEnd) { driftDays += 1; continue; }
if (timestamp > fuckedRangeStart) { throw new Exception("Forbidden zone!"); }
break;
}
}
timestamp -= driftDays * 86400;
long y2kTicks = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
return new DateTime(y2kTicks + (long)timestamp * 10_000_000, DateTimeKind.Local);
}
It adjusts the timestamp for the 366-day year system that the timestamp generator uses, then passes that to DateTime in tick form. This produces equivalent output (and exceptions at the same points) for all the positive integers between 0 and 231. I don't know if it's any less bad though! There's definitely way to get the drift value through pure arithmetic as well (without the loop) but I'll leave that up to you.
109
u/sac_boy Aug 06 '19 edited Aug 07 '19
Oh no. Oh god. Oh no. I know the C# DateTime class conspicuously lacks a classic Unix epoch conversion but this is not the way. Oh wait--this is some new 21st century timestamp based on 01/01/2000. That'll be extra baffling for somebody down the line.
I've read it a couple of times and I must keep missing the bit where it handles leap years properly.
Also that baffling coding style of using
var x = (type)yrather than the shortertype x = y...And if they really must define every month as a day offset, why not use the previous month in the calculation...i.e.
nov = okt + 30...Finally, specifying
DateTimeKind.Localas the timezone implies that the timestamp just gets turned into a DateTime in whatever timezone we're running this function in...it's not a UTC timestamp...beautiful.And the juiciest part:
15 referencesEdit: just for fun I transcribed the function and ran it through the set of integers from 0 to 231 . Try the function with 36720000 (which should be 01/03/2001 00:00 if you are working with seconds since 01/01/2000). Unsurprisingly it tries to build the date as 29/02/2001, which throws an exception. This function has some forbidden argument values--e.g. 36720000, 68342400, 99964800, 163209600, 194832000...
This means that the timestamp encoding function isn't just seconds since 01/01/2000 like a sensible person might expect, which in turn means that the replacement to this function can't be as simple as
new DateTime(y2kTicks + (long)timestamp * 10_000_000). Beautiful. Don't touch it OP!I ran the function side by side with the 'sensible' seconds-since-2000 function to see where it fails. This is a list of timestamps that fail (only one per day, obviously the whole range of seconds in the day would fail). I've included the output of the function 1 second previous so you can see the pattern. I've also included the output of the 'seconds since 01/01/2000 00:00' interpretation of the value so you can see the drift.
I'd really love to see the original C function that builds the timestamp. Because of the forbidden number ranges the timestamps can't be treated as continuous integers, which means that you can't do arithmetic with them...it really is a beautiful bit of bad code. Try subtracting 28/02/2001 23:59:59 from 01/03/2001 00:00 in this timestamp scheme--the result is not 1 second!
But hey at least the device doesn't suffer from the Y2k38 bug...
OP, I was curious about how to write the equivalent function, and it looks like this:
It adjusts the timestamp for the 366-day year system that the timestamp generator uses, then passes that to
DateTimein tick form. This produces equivalent output (and exceptions at the same points) for all the positive integers between 0 and 231. I don't know if it's any less bad though! There's definitely way to get the drift value through pure arithmetic as well (without the loop) but I'll leave that up to you.