Skip to content

Commit f87a95a

Browse files
committed
Add support for writing TimeTz to data chunk
1 parent 668c65e commit f87a95a

File tree

6 files changed

+24
-5
lines changed

6 files changed

+24
-5
lines changed

DuckDB.NET.Bindings/NativeMethods/NativeMethods.DateTime.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public static class DateTimeHelpers
1616
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_from_time")]
1717
public static extern DuckDBTimeOnly DuckDBFromTime(DuckDBTime time);
1818

19+
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_create_time_tz")]
20+
public static extern DuckDBTimeTzStruct DuckDBCreateTimeTz(long micros, int offset);
21+
1922
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_from_time_tz")]
2023
public static extern DuckDBTimeTz DuckDBFromTimeTz(DuckDBTimeTzStruct micros);
2124

DuckDB.NET.Data/DuckDBAppenderRow.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ public void EndRow()
9292

9393
public DuckDBAppenderRow AppendValue(DateTime? value) => AppendValueInternal(value);
9494

95+
public DuckDBAppenderRow AppendValue(DateTimeOffset? value) => AppendValueInternal(value);
96+
9597
public DuckDBAppenderRow AppendValue(TimeSpan? value)
9698
{
9799
return AppendValueInternal(value);

DuckDB.NET.Data/Internal/Writer/DateTimeVectorDataWriter.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ internal override bool AppendDateTime(DateTime value, int rowIndex)
3232
return AppendValueInternal(timestamp, rowIndex);
3333
}
3434

35+
internal override bool AppendDateTimeOffset(DateTimeOffset value, int rowIndex)
36+
{
37+
var time = NativeMethods.DateTimeHelpers.DuckDBToTime((DuckDBTimeOnly)value.DateTime);
38+
var timeTz = NativeMethods.DateTimeHelpers.DuckDBCreateTimeTz(time.Micros, (int)value.Offset.TotalSeconds);
39+
40+
return AppendValueInternal(timeTz, rowIndex);
41+
}
42+
3543
#if NET6_0_OR_GREATER
3644
internal override bool AppendDateOnly(DateOnly value, int rowIndex) => AppendValueInternal(NativeMethods.DateTimeHelpers.DuckDBToDate(value), rowIndex);
3745

DuckDB.NET.Data/Internal/Writer/VectorDataWriterBase.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public unsafe void AppendValue<T>(T value, int rowIndex)
5858
DateOnly val => AppendDateOnly(val, rowIndex),
5959
TimeOnly val => AppendTimeOnly(val, rowIndex),
6060
#endif
61+
DateTimeOffset val => AppendDateTimeOffset(val, rowIndex),
6162
_ => ThrowException<T>()
6263
};
6364
}
@@ -86,6 +87,8 @@ public unsafe void AppendValue<T>(T value, int rowIndex)
8687

8788
internal virtual bool AppendTimeOnly(DuckDBTimeOnly value, int rowIndex) => ThrowException<DuckDBTimeOnly>();
8889

90+
internal virtual bool AppendDateTimeOffset(DateTimeOffset value, int rowIndex) => ThrowException<DateTimeOffset>();
91+
8992
internal virtual bool AppendNumeric<T>(T value, int rowIndex) where T : unmanaged => ThrowException<T>();
9093

9194
internal virtual bool AppendBigInteger(BigInteger value, int rowIndex) => ThrowException<BigInteger>();

DuckDB.NET.Data/Internal/Writer/VectorDataWriterFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public static unsafe VectorDataWriterBase CreateWriter(IntPtr vector, DuckDBLogi
1515
DuckDBType.Uuid => new GuidVectorDataWriter(vector, dataPointer, columnType),
1616
DuckDBType.Date => new DateTimeVectorDataWriter(vector, dataPointer, columnType),
1717
DuckDBType.Time => new DateTimeVectorDataWriter(vector, dataPointer, columnType),
18-
DuckDBType.TimeTz => throw new NotImplementedException($"Writing {columnType} to data chunk is not yet supported"),
18+
DuckDBType.TimeTz => new DateTimeVectorDataWriter(vector, dataPointer, columnType),
1919
DuckDBType.Interval => new IntervalVectorDataWriter(vector, dataPointer, columnType),
2020
DuckDBType.Timestamp => new DateTimeVectorDataWriter(vector, dataPointer, columnType),
2121

DuckDB.NET.Test/ManagedAppenderTests.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Linq;
1010
using System.Numerics;
1111
using Dapper;
12+
using FluentAssertions.Common;
1213

1314
namespace DuckDB.NET.Test;
1415

@@ -235,10 +236,10 @@ public void IntervalValues()
235236
[Fact]
236237
public void TemporalValues()
237238
{
238-
Command.CommandText = "CREATE TABLE managedAppenderTemporal(a Date, b TimeStamp, c TIMESTAMP_NS, d TIMESTAMP_MS, e TIMESTAMP_S, f TIMESTAMPTZ);";
239+
Command.CommandText = "CREATE TABLE managedAppenderTemporal(a Date, b TimeStamp, c TIMESTAMP_NS, d TIMESTAMP_MS, e TIMESTAMP_S, f TIMESTAMPTZ, g TIMETZ);";
239240
Command.ExecuteNonQuery();
240241

241-
var dates = Enumerable.Range(0, 20).Select(i => new DateTime(1900, 1, 1).AddDays(Random.Shared.Next(1, 50000))).ToList();
242+
var dates = Enumerable.Range(0, 20).Select(i => new DateTime(1900, 1, 1).AddDays(Random.Shared.Next(1, 50000)).AddSeconds(Random.Shared.Next(3600 * 2, 3600 * 24))).ToList();
242243

243244
using (var appender = Connection.CreateAppender("managedAppenderTemporal"))
244245
{
@@ -247,19 +248,21 @@ public void TemporalValues()
247248
appender.CreateRow()
248249
.AppendValue(value).AppendValue(value)
249250
.AppendValue(value).AppendValue(value)
250-
.AppendValue(value).AppendValue(value)
251+
.AppendValue(value).AppendValue(value).AppendValue(value.ToDateTimeOffset(TimeSpan.FromHours(1)))
251252
.EndRow();
252253
}
253254
}
254255

255-
var result = Connection.Query<(DateOnly, DateTime, DateTime, DateTime, DateTime, DateTime)>("SELECT a, b, c, d, e, f FROM managedAppenderTemporal").ToList();
256+
var result = Connection.Query<(DateOnly, DateTime, DateTime, DateTime, DateTime, DateTime, DateTimeOffset)>("SELECT a, b, c, d, e, f, g FROM managedAppenderTemporal").ToList();
256257

257258
result.Select(tuple => tuple.Item1).Should().BeEquivalentTo(dates.Select(DateOnly.FromDateTime));
258259
result.Select(tuple => tuple.Item2).Should().BeEquivalentTo(dates);
259260
result.Select(tuple => tuple.Item3).Should().BeEquivalentTo(dates);
260261
result.Select(tuple => tuple.Item4).Should().BeEquivalentTo(dates);
261262
result.Select(tuple => tuple.Item5).Should().BeEquivalentTo(dates);
262263
result.Select(tuple => tuple.Item6).Should().BeEquivalentTo(dates);
264+
result.Select(tuple => tuple.Item7).Should().BeEquivalentTo(dates.Select(time => time.ToDateTimeOffset(TimeSpan.FromHours(1))),
265+
options => options.ComparingByMembers<DateTimeOffset>().Including(offset => offset.Offset).Including(offset => offset.TimeOfDay));
263266
}
264267

265268
[Fact]

0 commit comments

Comments
 (0)