diff --git a/CoreOSC.Tests/TimetagTest.cs b/CoreOSC.Tests/TimetagTest.cs
index 9b7300b..423e395 100644
--- a/CoreOSC.Tests/TimetagTest.cs
+++ b/CoreOSC.Tests/TimetagTest.cs
@@ -8,12 +8,14 @@ public class TimetagTest
[Fact]
public void TestTimetag()
{
- var time = (ulong) 60 * 60 * 24 * 365 * 108;
- time <<= 32;
- time += (ulong)(Math.Pow(2, 32) / 2);
- var date = Utils.TimeTagToDateTime(time);
+ ulong tag = 0;
- Assert.Equal(DateTime.Parse("2007-12-06 00:00:00.500"), date);
+ tag |= (ulong)3424309443 << 32; // https://www.timeanddate.com/date/durationresult.html?d1=1&m1=1&y1=1900&d2=6&m2=7&y2=2008&h1=0&i1=0&s1=0&h2=5&i2=4&s2=3
+ tag |= (ulong)(0xFFFFFFFF / 10); // 100ms
+
+ var date = Utils.TimeTagToDateTime(tag);
+
+ Assert.Equal(DateTime.Parse("2008-7-06 05:04:03.100"), date);
}
[Fact]
@@ -29,5 +31,6 @@ public void TestDateTimeToTimetag()
Assert.Equal(dt.Minute, dtBack.Minute);
Assert.Equal(dt.Second, dtBack.Second);
Assert.Equal(dt.Millisecond, dtBack.Millisecond);
+ Assert.Equal(dt.Microsecond, dtBack.Microsecond);
}
}
\ No newline at end of file
diff --git a/CoreOSC/TimeTag.cs b/CoreOSC/TimeTag.cs
index c60b6aa..b4d8593 100644
--- a/CoreOSC/TimeTag.cs
+++ b/CoreOSC/TimeTag.cs
@@ -4,14 +4,30 @@ namespace LucHeart.CoreOSC;
public struct TimeTag
{
+ public static TimeTag Immediate => new(1);
+
public ulong Tag;
+ ///
+ /// Gets or sets the timestamp from a DateTime. DateTime has an accuracy down to 100 nanoseconds (100'000
+ /// picoseconds)
+ ///
public DateTime Timestamp
{
get => Utils.TimeTagToDateTime(Tag);
set => Tag = Utils.DateTimeToTimeTag(value);
}
+ ///
+ /// Gets or sets the total seconds in the timestamp. the double precision number is multiplied by 2^32
+ /// giving an accuracy down to about 230 picoseconds ( 1/(2^32) of a second)
+ ///
+ public double Seconds
+ {
+ get => Utils.TimeTagToSeconds(Tag);
+ set => Tag = Utils.SecondsToTimeTag(value);
+ }
+
///
/// Gets or sets the fraction of a second in the timestamp. the double precision number is multiplied by 2^32
/// giving an accuracy down to about 230 picoseconds ( 1/(2^32) of a second)
@@ -19,7 +35,7 @@ public DateTime Timestamp
public double Fraction
{
get => Utils.TimeTagToFraction(Tag);
- set => Tag = (Tag & 0xFFFFFFFF00000000) + (uint)(value * 0xFFFFFFFF);
+ set => Tag = Utils.SecondsToTimeTag(value);
}
public TimeTag(ulong value)
diff --git a/CoreOSC/Utils.cs b/CoreOSC/Utils.cs
index e646f65..347a995 100644
--- a/CoreOSC/Utils.cs
+++ b/CoreOSC/Utils.cs
@@ -4,36 +4,57 @@ namespace LucHeart.CoreOSC;
public static class Utils
{
+ private static readonly long EpochTicks = new DateTime(1900, 1, 1).Ticks;
+ private const uint OscTicksPerSecond = 0xFFFFFFFF;
+ private const double OscTicksPerDotNetTick = OscTicksPerSecond / (double)TimeSpan.TicksPerSecond; // 429.4967295
+
public static DateTime TimeTagToDateTime(ulong val)
{
if (val == 1)
return DateTime.Now;
- var seconds = (uint)(val >> 32);
- var time = DateTime.Parse("1900-01-01 00:00:00");
- time = time.AddSeconds(seconds);
- var fraction = TimeTagToFraction(val);
- time = time.AddSeconds(fraction);
- return time;
+ uint seconds = (uint)(val >> 32);
+ uint fraction = (uint)(val & 0xFFFFFFFF);
+
+ long secondsTicks = seconds * TimeSpan.TicksPerSecond;
+ long fractionTicks = (long)Math.Round(fraction / OscTicksPerDotNetTick); // We will loose accuracy in this conversion since there is about 430 OSC ticks per dotnet tick
+
+ return new DateTime(EpochTicks + secondsTicks + fractionTicks);
}
- public static double TimeTagToFraction(ulong val)
+ public static ulong DateTimeToTimeTag(DateTime value)
+ {
+ long ticks = value.Ticks - EpochTicks;
+ if (ticks < 0) return 0;
+
+ uint seconds = (uint)(ticks / TimeSpan.TicksPerSecond);
+ uint fractions = (uint)Math.Round((ticks - (seconds * TimeSpan.TicksPerSecond)) * OscTicksPerDotNetTick);
+
+ ulong secondTicks = (ulong)seconds << 32;
+ ulong fractionTicks = (ulong)fractions & 0xFFFFFFFF;
+
+ return secondTicks | fractionTicks;
+ }
+
+ public static double TimeTagToSeconds(ulong val)
{
if (val == 1)
return 0.0;
- var seconds = (uint)(val & 0x00000000FFFFFFFF);
- var fraction = (double)seconds / 0xFFFFFFFF;
- return fraction;
+ return (double)val / OscTicksPerSecond;
}
- public static ulong DateTimeToTimeTag(DateTime value)
+ public static ulong SecondsToTimeTag(double value)
{
- ulong seconds = (uint)(value - DateTime.Parse("1900-01-01 00:00:00.000")).TotalSeconds;
- var fraction = (uint)Math.Ceiling(0xFFFFFFFF * ((double)value.Millisecond / 1000));
+ return (ulong)(value * OscTicksPerSecond);
+ }
+
+ public static double TimeTagToFraction(ulong val)
+ {
+ if (val == 1)
+ return 0.0;
- var output = (seconds << 32) + fraction;
- return output;
+ return (double)(val & 0xFFFFFFFF) / OscTicksPerSecond;
}
public static int AlignedStringLength(string val)