|
1 | 1 | using System; |
| 2 | +using System.Buffers; |
2 | 3 | using System.Collections.Generic; |
3 | 4 | using System.IO; |
4 | 5 | using System.Text; |
@@ -160,6 +161,57 @@ public static string ExtractText(object? contentObj) |
160 | 161 |
|
161 | 162 | // ── Low-level MessagePack reader ─────────────────────────────────────── |
162 | 163 |
|
| 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 | + |
163 | 215 | private static object? ReadValue(ref MessagePackReader reader) |
164 | 216 | { |
165 | 217 | switch (reader.NextMessagePackType) |
@@ -213,7 +265,11 @@ public static string ExtractText(object? contentObj) |
213 | 265 | return null; |
214 | 266 |
|
215 | 267 | 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 | + } |
217 | 273 | return null; |
218 | 274 |
|
219 | 275 | default: |
|
0 commit comments