Skip to content

Commit dc4f71b

Browse files
committed
Add timestamp decoding for MessagePack extension in SessionParser
1 parent 0e1b158 commit dc4f71b

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

visualstudio-extension/src/CopilotTokenTracker/Data/SessionParser.cs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Buffers;
23
using System.Collections.Generic;
34
using System.IO;
45
using System.Text;
@@ -160,6 +161,57 @@ public static string ExtractText(object? contentObj)
160161

161162
// ── Low-level MessagePack reader ───────────────────────────────────────
162163

164+
/// <summary>
165+
/// Decodes a MessagePack Timestamp extension (type code -1) into an ISO-8601 string.
166+
/// Handles all three timestamp formats: 32-bit, 64-bit, and 96-bit.
167+
/// </summary>
168+
private static string? DecodeTimestamp(ReadOnlySequence<byte> data)
169+
{
170+
try
171+
{
172+
long seconds;
173+
uint nanoseconds;
174+
var bytes = data.ToArray();
175+
176+
switch (bytes.Length)
177+
{
178+
case 4: // Timestamp32: seconds in uint32
179+
seconds = ((uint)bytes[0] << 24) | ((uint)bytes[1] << 16)
180+
| ((uint)bytes[2] << 8) | bytes[3];
181+
nanoseconds = 0;
182+
break;
183+
184+
case 8: // Timestamp64: upper 30 bits = nanoseconds, lower 34 bits = seconds
185+
ulong val = 0;
186+
for (int i = 0; i < 8; i++)
187+
val = (val << 8) | bytes[i];
188+
nanoseconds = (uint)(val >> 34);
189+
seconds = (long)(val & 0x3FFFFFFFFUL);
190+
break;
191+
192+
case 12: // Timestamp96: 4 bytes nanoseconds + 8 bytes signed seconds
193+
nanoseconds = ((uint)bytes[0] << 24) | ((uint)bytes[1] << 16)
194+
| ((uint)bytes[2] << 8) | bytes[3];
195+
seconds = 0;
196+
for (int i = 4; i < 12; i++)
197+
seconds = (seconds << 8) | bytes[i];
198+
break;
199+
200+
default:
201+
return null;
202+
}
203+
204+
var dt = DateTimeOffset.FromUnixTimeSeconds(seconds)
205+
.AddTicks(nanoseconds / 100)
206+
.UtcDateTime;
207+
return dt.ToString("o");
208+
}
209+
catch
210+
{
211+
return null;
212+
}
213+
}
214+
163215
private static object? ReadValue(ref MessagePackReader reader)
164216
{
165217
switch (reader.NextMessagePackType)
@@ -213,7 +265,11 @@ public static string ExtractText(object? contentObj)
213265
return null;
214266

215267
case MessagePackType.Extension:
216-
reader.ReadExtensionFormat();
268+
var ext = reader.ReadExtensionFormat();
269+
if (ext.TypeCode == -1) // MessagePack Timestamp
270+
{
271+
return DecodeTimestamp(ext.Data);
272+
}
217273
return null;
218274

219275
default:

0 commit comments

Comments
 (0)