-
-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use DateTime both DateOnly and TimeOnly
Support for TimeOnly, DateOnly & Timestamp
- Loading branch information
1 parent
b7f3e52
commit b09a31f
Showing
10 changed files
with
595 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
using System; | ||
|
||
namespace DuckDB.NET.Data.Types; | ||
|
||
internal class DuckDBTimestamp : IDuckDBParameterValue | ||
{ | ||
private readonly DuckDBTimestampStruct nativeValue; | ||
|
||
private DuckDBTimestamp(DuckDBTimestampStruct native) | ||
{ | ||
nativeValue = native; | ||
} | ||
|
||
public DuckDBState Bind(DuckDBPreparedStatement preparedStatement, long index) | ||
{ | ||
return NativeMethods.PreparedStatements.DuckDBParamType(preparedStatement, index) switch | ||
{ | ||
DuckDBType.DuckdbTypeDate => BindDate(preparedStatement, index), | ||
DuckDBType.DuckdbTypeTime => BindTime(preparedStatement, index), | ||
DuckDBType.DuckdbTypeTimestamp => BindTimestamp(preparedStatement, index), | ||
DuckDBType.DuckdbTypeInvalid => BindTimestamp(preparedStatement, index), | ||
_ => throw new ArgumentOutOfRangeException("Unexpected target data type.") | ||
}; | ||
} | ||
|
||
private DuckDBState BindDate(DuckDBPreparedStatement preparedStatement, long index) | ||
{ | ||
var date = NativeMethods.DateTime.DuckDBToDate(nativeValue.Date); | ||
return NativeMethods.PreparedStatements.DuckDBBindDate(preparedStatement, index, date); | ||
} | ||
|
||
private DuckDBState BindTime(DuckDBPreparedStatement preparedStatement, long index) | ||
{ | ||
var time = NativeMethods.DateTime.DuckDBToTime(nativeValue.Time); | ||
return NativeMethods.PreparedStatements.DuckDBBindTime(preparedStatement, index, time); | ||
} | ||
|
||
private DuckDBState BindTimestamp(DuckDBPreparedStatement preparedStatement, long index) | ||
{ | ||
var timestamp = NativeMethods.DateTime.DuckDBToTimestamp(nativeValue); | ||
return NativeMethods.PreparedStatements.DuckDBBindTimestamp(preparedStatement, index, timestamp); | ||
} | ||
|
||
public static DateTime Load(DuckDBResult result, long col, long row) | ||
{ | ||
return (NativeMethods.Query.DuckDBColumnType(result, col) switch | ||
{ | ||
DuckDBType.DuckdbTypeTimestamp => LoadTimestamp(result, col, row), | ||
DuckDBType.DuckdbTypeTime => LoadTime(result, col, row), | ||
DuckDBType.DuckdbTypeDate => LoadDate(result, col, row), | ||
_ => throw new ArgumentOutOfRangeException("Unexpected data type.") | ||
}).ToDateTime(); | ||
} | ||
|
||
private static DuckDBTimestamp LoadTimestamp(DuckDBResult result, long col, long row) | ||
{ | ||
var timestamp = NativeMethods.Types.DuckDbValueTimestamp(result, col, row); | ||
var timestampStruct = NativeMethods.DateTime.DuckDBFromTimestamp(timestamp); | ||
return new DuckDBTimestamp(timestampStruct); | ||
} | ||
|
||
private static DuckDBTimestamp LoadTime(DuckDBResult result, long col, long row) | ||
{ | ||
var time = NativeMethods.Types.DuckDbValueTime(result, col, row); | ||
var timeStruct = NativeMethods.DateTime.DuckDBFromTime(time); | ||
var timestamp = new DuckDBTimestampStruct | ||
{ | ||
Time = timeStruct, | ||
Date = new DuckDBDateStruct() | ||
}; | ||
return new DuckDBTimestamp(timestamp); | ||
} | ||
|
||
private static DuckDBTimestamp LoadDate(DuckDBResult result, long col, long row) | ||
{ | ||
var date = NativeMethods.Types.DuckDbValueDate(result, col, row); | ||
var dateStruct = NativeMethods.DateTime.DuckDBFromDate(date); | ||
var timestamp = new DuckDBTimestampStruct | ||
{ | ||
Date = dateStruct, | ||
Time = new DuckDBTimeStruct() | ||
}; | ||
return new DuckDBTimestamp(timestamp); | ||
} | ||
|
||
public DateTime ToDateTime() | ||
{ | ||
return new DateTime( | ||
Math.Max(nativeValue.Date.Year, DateTime.MinValue.Year), | ||
Math.Max(nativeValue.Date.Month, DateTime.MinValue.Month), | ||
Math.Max(nativeValue.Date.Day, DateTime.MinValue.Day), | ||
Math.Max(nativeValue.Time.Hour, DateTime.MinValue.Hour), | ||
Math.Max(nativeValue.Time.Min, DateTime.MinValue.Minute), | ||
Math.Max(nativeValue.Time.Sec, DateTime.MinValue.Second), | ||
Math.Max(nativeValue.Time.Msec, DateTime.MinValue.Millisecond) | ||
); | ||
} | ||
|
||
public static DuckDBTimestamp FromDateTime(DateTime dateTime) | ||
{ | ||
var nativeDate = new DuckDBDateStruct | ||
{ | ||
Year = dateTime.Year, | ||
Month = (byte)dateTime.Month, | ||
Day = (byte)dateTime.Day | ||
}; | ||
|
||
var nativeTime = new DuckDBTimeStruct | ||
{ | ||
Hour = (byte)dateTime.Hour, | ||
Min = (byte)dateTime.Minute, | ||
Sec = (byte)dateTime.Second, | ||
Msec = dateTime.Millisecond | ||
}; | ||
|
||
var value = new DuckDBTimestampStruct { | ||
Date = nativeDate, | ||
Time = nativeTime | ||
}; | ||
return new DuckDBTimestamp(value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System; | ||
|
||
namespace DuckDB.NET.Data.Types; | ||
|
||
internal interface IDuckDBParameterValue | ||
{ | ||
DuckDBState Bind(DuckDBPreparedStatement preparedStatement, long index); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
using System; | ||
using DuckDB.NET.Data; | ||
using FluentAssertions; | ||
using Xunit; | ||
|
||
namespace DuckDB.NET.Test.DateTimeTests; | ||
|
||
public class DateTests | ||
{ | ||
[Theory] | ||
[InlineData(1992, 09, 20)] | ||
[InlineData(2022, 05, 04)] | ||
[InlineData(2022, 04, 05)] | ||
[InlineData(1, 1, 1)] | ||
public void QueryScalarTest(int year, int mon, int day) | ||
{ | ||
using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); | ||
connection.Open(); | ||
|
||
using var cmd = connection.CreateCommand(); | ||
cmd.CommandText = $"SELECT DATE '{year}-{mon}-{day}';"; | ||
|
||
var scalar = cmd.ExecuteScalar(); | ||
|
||
scalar.Should().BeOfType<DateTime>(); | ||
|
||
var dateOnly = (DateTime) scalar; | ||
|
||
dateOnly.Year.Should().Be(year); | ||
dateOnly.Month.Should().Be(mon); | ||
dateOnly.Day.Should().Be(day); | ||
dateOnly.Hour.Should().Be(DateTime.MinValue.Hour); | ||
dateOnly.Minute.Should().Be(DateTime.MinValue.Minute); | ||
dateOnly.Second.Should().Be(DateTime.MinValue.Second); | ||
dateOnly.Minute.Should().Be(DateTime.MinValue.Millisecond); | ||
} | ||
|
||
[Theory] | ||
[InlineData(1992, 09, 20)] | ||
[InlineData(2022, 05, 04)] | ||
[InlineData(2022, 04, 05)] | ||
[InlineData(1, 1, 1)] | ||
public void BindParamTest(int year, int mon, int day) | ||
{ | ||
using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); | ||
connection.Open(); | ||
|
||
var expectedValue = new DateTime(year, mon, day); | ||
|
||
using var cmd = connection.CreateCommand(); | ||
cmd.CommandText = "SELECT ?::DATE;"; | ||
cmd.Parameters.Add(new DuckDBParameter(expectedValue)); | ||
|
||
var scalar = cmd.ExecuteScalar(); | ||
|
||
scalar.Should().BeOfType<DateTime>(); | ||
|
||
var dateOnly = (DateTime) scalar; | ||
|
||
dateOnly.Year.Should().Be(year); | ||
dateOnly.Month.Should().Be(mon); | ||
dateOnly.Day.Should().Be(day); | ||
dateOnly.Hour.Should().Be(DateTime.MinValue.Hour); | ||
dateOnly.Minute.Should().Be(DateTime.MinValue.Minute); | ||
dateOnly.Second.Should().Be(DateTime.MinValue.Second); | ||
dateOnly.Minute.Should().Be(DateTime.MinValue.Millisecond); | ||
|
||
dateOnly.Should().Be(expectedValue); | ||
} | ||
|
||
[Theory] | ||
[InlineData(1992, 09, 20)] | ||
[InlineData(2022, 05, 04)] | ||
[InlineData(2022, 04, 05)] | ||
[InlineData(1, 1, 1)] | ||
public void BindAndInsert(int year, int mon, int day) | ||
{ | ||
using var connection = new DuckDBConnection(DuckDBConnectionStringBuilder.InMemoryConnectionString); | ||
connection.Open(); | ||
|
||
var expectedValue = new DateTime(year, mon, day); | ||
|
||
using var cmd = connection.CreateCommand(); | ||
|
||
try | ||
{ | ||
cmd.CommandText = "CREATE TABLE date_test (d DATE);"; | ||
cmd.ExecuteNonQuery(); | ||
|
||
cmd.CommandText = "INSERT INTO date_test (d) VALUES (?);"; | ||
cmd.Parameters.Add(new DuckDBParameter(expectedValue)); | ||
cmd.ExecuteNonQuery(); | ||
|
||
cmd.CommandText = "SELECT * FROM date_test;"; | ||
cmd.Parameters.Clear(); | ||
var scalar = cmd.ExecuteScalar(); | ||
|
||
scalar.Should().BeOfType<DateTime>(); | ||
|
||
var dateOnly = (DateTime) scalar; | ||
|
||
dateOnly.Year.Should().Be(year); | ||
dateOnly.Month.Should().Be(mon); | ||
dateOnly.Day.Should().Be(day); | ||
dateOnly.Hour.Should().Be(DateTime.MinValue.Hour); | ||
dateOnly.Minute.Should().Be(DateTime.MinValue.Minute); | ||
dateOnly.Second.Should().Be(DateTime.MinValue.Second); | ||
dateOnly.Minute.Should().Be(DateTime.MinValue.Millisecond); | ||
|
||
dateOnly.Should().Be(expectedValue); | ||
} | ||
finally | ||
{ | ||
cmd.CommandText = "DROP TABLE date_test;"; | ||
cmd.ExecuteNonQuery(); | ||
} | ||
} | ||
} |
Oops, something went wrong.