From 7ac86043d1b640018df07deb1d94cfacc4e791d2 Mon Sep 17 00:00:00 2001 From: Giorgi Date: Wed, 6 Mar 2024 00:44:59 +0400 Subject: [PATCH] Allow reading ntive DuckDBTimeTz type. --- .../Reader/DateTimeVectorDataReader.cs | 34 +++++++++++++++---- .../Internal/Reader/VectorDataReaderBase.cs | 2 +- .../DuckDBDataReaderTestAllTypes.cs | 18 +++++++--- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/DuckDB.NET.Data/Internal/Reader/DateTimeVectorDataReader.cs b/DuckDB.NET.Data/Internal/Reader/DateTimeVectorDataReader.cs index f16fa94..f481ace 100644 --- a/DuckDB.NET.Data/Internal/Reader/DateTimeVectorDataReader.cs +++ b/DuckDB.NET.Data/Internal/Reader/DateTimeVectorDataReader.cs @@ -9,6 +9,9 @@ internal class DateTimeVectorDataReader : VectorDataReaderBase private static readonly Type DateTimeType = typeof(DateTime); private static readonly Type DateTimeNullableType = typeof(DateTime?); + private static readonly Type DateTimeOffsetType = typeof(DateTimeOffset); + private static readonly Type DateTimeOffsetNullableType = typeof(DateTimeOffset?); + #if NET6_0_OR_GREATER private static readonly Type DateOnlyType = typeof(DateOnly); private static readonly Type DateOnlyNullableType = typeof(DateOnly?); @@ -66,7 +69,15 @@ protected override T GetValidValue(ulong offset, Type targetType) if (DuckDBType == DuckDBType.TimeTz) { - return (T)(object)GetDateTimeOffset(offset); + var timeTz = GetTimeTz(offset); + + if (targetType == DateTimeOffsetType || targetType == DateTimeOffsetNullableType) + { + var dateTimeOffset = new DateTimeOffset(timeTz.Time.ToDateTime(), TimeSpan.FromSeconds(timeTz.Offset)); + return (T)(object)dateTimeOffset; + } + + return (T)(object)timeTz; } if (DuckDBType == DuckDBType.Timestamp || DuckDBType == DuckDBType.TimestampTz) @@ -114,7 +125,7 @@ internal override object GetValue(ulong offset, Type targetType) { DuckDBType.Date => GetDate(offset, targetType), DuckDBType.Time => GetTime(offset, targetType), - DuckDBType.TimeTz => GetDateTimeOffset(offset), + DuckDBType.TimeTz => GetDateTimeOffset(offset, targetType), DuckDBType.Timestamp => GetDateTime(offset, targetType), DuckDBType.TimestampTz => GetDateTime(offset, targetType), DuckDBType.TimestampS => GetDateTime(offset, targetType, 1000000), @@ -124,6 +135,13 @@ internal override object GetValue(ulong offset, Type targetType) }; } + private DuckDBTimeTz GetTimeTz(ulong offset) + { + var data = GetFieldData(offset); + + return NativeMethods.DateTime.DuckDBFromTimeTz(data); + } + private DuckDBTimeOnly GetTimeOnly(ulong offset) { return NativeMethods.DateTime.DuckDBFromTime(GetFieldData(offset)); @@ -184,13 +202,15 @@ private object GetDateTime(ulong offset, Type targetType, int factor = 1, int di return NativeMethods.DateTime.DuckDBFromTimestamp(data); } - private DateTimeOffset GetDateTimeOffset(ulong offset) + private object GetDateTimeOffset(ulong offset, Type targetType) { - var data = GetFieldData(offset); - - var timeTz = NativeMethods.DateTime.DuckDBFromTimeTz(data); + var timeTz = GetTimeTz(offset); + if (targetType == typeof(DateTimeOffset)) + { + return new DateTimeOffset(timeTz.Time.ToDateTime(), TimeSpan.FromSeconds(timeTz.Offset)); + } - return new DateTimeOffset(timeTz.Time.ToDateTime(), TimeSpan.FromSeconds(timeTz.Offset)); + return timeTz; } } \ No newline at end of file diff --git a/DuckDB.NET.Data/Internal/Reader/VectorDataReaderBase.cs b/DuckDB.NET.Data/Internal/Reader/VectorDataReaderBase.cs index 2ee2fa4..d45f113 100644 --- a/DuckDB.NET.Data/Internal/Reader/VectorDataReaderBase.cs +++ b/DuckDB.NET.Data/Internal/Reader/VectorDataReaderBase.cs @@ -169,7 +169,7 @@ protected virtual Type GetColumnProviderSpecificType() DuckDBType.Interval => typeof(DuckDBInterval), DuckDBType.Date => typeof(DuckDBDateOnly), DuckDBType.Time => typeof(DuckDBTimeOnly), - DuckDBType.TimeTz => typeof(DateTimeOffset), + DuckDBType.TimeTz => typeof(DuckDBTimeTz), DuckDBType.HugeInt => typeof(DuckDBHugeInt), DuckDBType.UnsignedHugeInt => typeof(DuckDBUHugeInt), DuckDBType.Varchar => typeof(string), diff --git a/DuckDB.NET.Test/DuckDBDataReaderTestAllTypes.cs b/DuckDB.NET.Test/DuckDBDataReaderTestAllTypes.cs index c94375a..0ffbea0 100644 --- a/DuckDB.NET.Test/DuckDBDataReaderTestAllTypes.cs +++ b/DuckDB.NET.Test/DuckDBDataReaderTestAllTypes.cs @@ -231,14 +231,22 @@ public void ReadTimeStampNS() }, typeof(DuckDBTimestamp)); } - [Fact(Skip = "These dates can't be expressed by DateTime or is unsupported by this library")] + [Fact] public void ReadTimeTZ() { - VerifyDataStruct("time_tz", 17, new List + VerifyDataStruct("time_tz", 17, new List { - new(new(-290308, 12, 22), new(0,0,0)), - new(new(294247, 1, 10), new(4,0,54,775806)) - }); + new() + { + Offset = (int)new TimeSpan(15,59,59).TotalSeconds, + Time = new DuckDBTimeOnly() + }, + new() + { + Offset = -(int)new TimeSpan(15,59,59).TotalSeconds, + Time = new DuckDBTimeOnly(24,0,0) + }, + }, readProviderSpecificValue: true); } [Fact]