Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/Dapper.AOT/Internal/CommandUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,26 @@ internal static T As<T>(object? value)
}
else if (typeof(T) == typeof(DateTime))
{
#if NET6_0_OR_GREATER
// Npgsql 10 hands back DateOnly for "date" columns; not IConvertible
if (value is DateOnly dateOnlySource)
{
DateTime fromDateOnly = dateOnlySource.ToDateTime(TimeOnly.MinValue);
return Unsafe.As<DateTime, T>(ref fromDateOnly);
}
#endif
DateTime t = Convert.ToDateTime(value, CultureInfo.InvariantCulture);
return Unsafe.As<DateTime, T>(ref t);
}
else if (typeof(T) == typeof(DateTime?))
{
#if NET6_0_OR_GREATER
if (value is DateOnly dateOnlySource)
{
DateTime? fromDateOnly = dateOnlySource.ToDateTime(TimeOnly.MinValue);
return Unsafe.As<DateTime?, T>(ref fromDateOnly);
}
#endif
DateTime? t = Convert.ToDateTime(value, CultureInfo.InvariantCulture);
return Unsafe.As<DateTime?, T>(ref t);
}
Expand All @@ -187,6 +202,12 @@ internal static T As<T>(object? value)
var fromSpan = TimeOnly.FromTimeSpan(timeSpan);
return Unsafe.As<TimeOnly, T>(ref fromSpan);
}
if (value is DateOnly)
{
// a date has no time component; same answer a zero-time DateTime gives
TimeOnly zero = default;
return Unsafe.As<TimeOnly, T>(ref zero);
}

DateTime t = Convert.ToDateTime(value, CultureInfo.InvariantCulture);
var timeOnly = TimeOnly.FromDateTime(t);
Expand All @@ -199,6 +220,11 @@ internal static T As<T>(object? value)
var fromSpan = TimeOnly.FromTimeSpan(timeSpan);
return Unsafe.As<TimeOnly, T>(ref fromSpan);
}
if (value is DateOnly)
{
TimeOnly? zero = default(TimeOnly);
return Unsafe.As<TimeOnly?, T>(ref zero);
}

DateTime? t = Convert.ToDateTime(value, CultureInfo.InvariantCulture);
TimeOnly? timeOnly = t is null ? null : TimeOnly.FromDateTime(t.Value);
Expand Down
40 changes: 40 additions & 0 deletions test/Dapper.AOT.Test/CommandUtilsDateOnlyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#if NET6_0_OR_GREATER
using System;
using Dapper.Internal;
using Xunit;

namespace Dapper.AOT.Test
{
// Npgsql 10 hands back DateOnly (not DateTime) for "date" columns; these are the
// docker-free half of DateOnlyTimeOnlyPostgreSqlTests, so the coverage does not
// depend on a live container (see #202)
public class CommandUtilsDateOnlyTests
{
private static readonly object BoxedDateOnly = new DateOnly(2021, 1, 2);

[Fact]
public void As_DateOnlyToDateTime()
=> Assert.Equal(new DateTime(2021, 1, 2), CommandUtils.As<DateTime>(BoxedDateOnly));

[Fact]
public void As_DateOnlyToNullableDateTime()
=> Assert.Equal(new DateTime(2021, 1, 2), CommandUtils.As<DateTime?>(BoxedDateOnly));

[Fact] // a date has no time component; same answer a zero-time DateTime gives
public void As_DateOnlyToTimeOnly()
=> Assert.Equal(default, CommandUtils.As<TimeOnly>(BoxedDateOnly));

[Fact]
public void As_DateOnlyToNullableTimeOnly()
=> Assert.Equal(default(TimeOnly), CommandUtils.As<TimeOnly?>(BoxedDateOnly));

[Fact] // pass-through, unchanged
public void As_DateOnlyToDateOnly()
=> Assert.Equal(new DateOnly(2021, 1, 2), CommandUtils.As<DateOnly>(BoxedDateOnly));

[Fact] // the pre-Npgsql-10 shape, unchanged
public void As_DateTimeToDateOnly()
=> Assert.Equal(new DateOnly(2021, 1, 2), CommandUtils.As<DateOnly>((object)new DateTime(2021, 1, 2)));
}
}
#endif
Loading