Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for datetime tzinfo conversion #81

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
30 changes: 30 additions & 0 deletions src/embed_tests/TestConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,36 @@ def GetNextDay(dateTime):

var expectedDateTime = new DateTime(year, month, day, hour, minute, second);
Assert.AreEqual(expectedDateTime, managedDateTime);

Assert.AreEqual(DateTimeKind.Unspecified, managedDateTime.Kind);
}
}

[Test]
public void ConvertDateTimeWithExplicitUTCTimeZonePythonToCSharp()
{
const int year = 2024;
const int month = 2;
const int day = 27;
const int hour = 12;
const int minute = 30;
const int second = 45;

using (Py.GIL())
{
var csDateTime = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc);
// Converter.ToPython will set the datetime tzinfo to UTC using a custom tzinfo class
using var pyDateTime = Converter.ToPython(csDateTime).MoveToPyObject();
var dateTimeResult = default(object);

Assert.DoesNotThrow(() => Converter.ToManaged(pyDateTime, typeof(DateTime), out dateTimeResult, false));

var managedDateTime = (DateTime)dateTimeResult;

var expectedDateTime = new DateTime(year, month, day, hour, minute, second);
Assert.AreEqual(expectedDateTime, managedDateTime);

Assert.AreEqual(DateTimeKind.Utc, managedDateTime.Kind);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/perf_tests/Python.PerformanceTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.*" />
<PackageReference Include="quantconnect.pythonnet" Version="2.0.27" GeneratePathProperty="true">
<PackageReference Include="quantconnect.pythonnet" Version="2.0.28" GeneratePathProperty="true">
<IncludeAssets>compile</IncludeAssets>
</PackageReference>
</ItemGroup>
Expand All @@ -25,7 +25,7 @@
</Target>

<Target Name="CopyBaseline" AfterTargets="Build">
<Copy SourceFiles="$(NuGetPackageRoot)quantconnect.pythonnet\2.0.27\lib\net5.0\Python.Runtime.dll" DestinationFolder="$(OutDir)baseline" />
<Copy SourceFiles="$(NuGetPackageRoot)quantconnect.pythonnet\2.0.28\lib\net5.0\Python.Runtime.dll" DestinationFolder="$(OutDir)baseline" />
</Target>

<Target Name="CopyNewBuild" AfterTargets="Build">
Expand Down
38 changes: 36 additions & 2 deletions src/runtime/Converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1123,13 +1123,31 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
var minute = Runtime.PyObject_GetAttrString(value, minutePtr);
var second = Runtime.PyObject_GetAttrString(value, secondPtr);
var microsecond = Runtime.PyObject_GetAttrString(value, microsecondPtr);
var timeKind = DateTimeKind.Unspecified;
var tzinfo = Runtime.PyObject_GetAttrString(value, tzinfoPtr);

NewReference hours = default;
NewReference minutes = default;
if (!ReferenceNullOrNone(tzinfo))
{
// We set the datetime kind to UTC if the tzinfo was set to UTC by the ToPthon method
// using it's custom GMT Python tzinfo class
hours = Runtime.PyObject_GetAttrString(tzinfo.Borrow(), hoursPtr);
minutes = Runtime.PyObject_GetAttrString(tzinfo.Borrow(), minutesPtr);
if (!ReferenceNullOrNone(hours) &&
!ReferenceNullOrNone(minutes) &&
Runtime.PyLong_AsLong(hours.Borrow()) == 0 && Runtime.PyLong_AsLong(minutes.Borrow()) == 0)
{
timeKind = DateTimeKind.Utc;
}
}

var convertedHour = 0L;
var convertedMinute = 0L;
var convertedSecond = 0L;
var milliseconds = 0L;
// could be python date type
if (!hour.IsNull() && !hour.IsNone())
if (!ReferenceNullOrNone(hour))
{
convertedHour = Runtime.PyLong_AsLong(hour.Borrow());
convertedMinute = Runtime.PyLong_AsLong(minute.Borrow());
Expand All @@ -1143,7 +1161,8 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
(int)convertedHour,
(int)convertedMinute,
(int)convertedSecond,
(int)milliseconds);
(int)milliseconds,
timeKind);

year.Dispose();
month.Dispose();
Expand All @@ -1153,6 +1172,16 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
second.Dispose();
microsecond.Dispose();

if (!tzinfo.IsNull())
{
tzinfo.Dispose();
if (!tzinfo.IsNone())
{
hours.Dispose();
minutes.Dispose();
}
}

Exceptions.Clear();
return true;
default:
Expand Down Expand Up @@ -1183,6 +1212,11 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
return false;
}

private static bool ReferenceNullOrNone(NewReference reference)
{
return reference.IsNull() || reference.IsNone();
}


private static void SetConversionError(BorrowedReference value, Type target)
{
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
[assembly: InternalsVisibleTo("Python.EmbeddingTest, PublicKey=00240000048000009400000006020000002400005253413100040000110000005ffd8f49fb44ab0641b3fd8d55e749f716e6dd901032295db641eb98ee46063cbe0d4a1d121ef0bc2af95f8a7438d7a80a3531316e6b75c2dae92fb05a99f03bf7e0c03980e1c3cfb74ba690aca2f3339ef329313bcc5dccced125a4ffdc4531dcef914602cd5878dc5fbb4d4c73ddfbc133f840231343e013762884d6143189")]
[assembly: InternalsVisibleTo("Python.Test, PublicKey=00240000048000009400000006020000002400005253413100040000110000005ffd8f49fb44ab0641b3fd8d55e749f716e6dd901032295db641eb98ee46063cbe0d4a1d121ef0bc2af95f8a7438d7a80a3531316e6b75c2dae92fb05a99f03bf7e0c03980e1c3cfb74ba690aca2f3339ef329313bcc5dccced125a4ffdc4531dcef914602cd5878dc5fbb4d4c73ddfbc133f840231343e013762884d6143189")]

[assembly: AssemblyVersion("2.0.27")]
[assembly: AssemblyFileVersion("2.0.27")]
[assembly: AssemblyVersion("2.0.28")]
[assembly: AssemblyFileVersion("2.0.28")]
2 changes: 1 addition & 1 deletion src/runtime/Python.Runtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<RootNamespace>Python.Runtime</RootNamespace>
<AssemblyName>Python.Runtime</AssemblyName>
<PackageId>QuantConnect.pythonnet</PackageId>
<Version>2.0.27</Version>
<Version>2.0.28</Version>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/pythonnet/pythonnet</RepositoryUrl>
Expand Down
Loading