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

Add parsing for datetime.time #1069

Merged
merged 3 commits into from
Mar 11, 2024
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
28 changes: 28 additions & 0 deletions src/pydates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ const PyDate_HEAD = sizeof(Int)+sizeof(PyPtr)+sizeof(Py_hash_t)+1
const DateType = Ref{PyPtr}(0)
const DateTimeType = Ref{PyPtr}(0)
const DeltaType = Ref{PyPtr}(0)
const TimeType = Ref{PyPtr}(0)
const Date_FromDate = Ref{Ptr{Cvoid}}(0)
const DateTime_FromDateAndTime = Ref{Ptr{Cvoid}}(0)
const Delta_FromDelta = Ref{Ptr{Cvoid}}(0)
const Time_FromTime = Ref{Ptr{Cvoid}}(0)
function init_datetime()
# emulate PyDateTime_IMPORT:
PyDateTimeAPI = unsafe_load(@pycheckn ccall((@pysym :PyCapsule_Import),
Expand All @@ -71,9 +73,11 @@ function init_datetime()
DateType[] = PyDateTimeAPI.DateType
DateTimeType[] = PyDateTimeAPI.DateTimeType
DeltaType[] = PyDateTimeAPI.DeltaType
TimeType[] = PyDateTimeAPI.TimeType
Date_FromDate[] = PyDateTimeAPI.Date_FromDate
DateTime_FromDateAndTime[] = PyDateTimeAPI.DateTime_FromDateAndTime
Delta_FromDelta[] = PyDateTimeAPI.Delta_FromDelta
Time_FromTime[] = PyDateTimeAPI.Time_FromTime
end

PyObject(d::Dates.Date) =
Expand All @@ -99,6 +103,13 @@ PyDelta_FromDSU(days, seconds, useconds) =

PyObject(p::Dates.Day) = PyDelta_FromDSU(Dates.value(p), 0, 0)

PyObject(t::Dates.Time) =
PyObject(@pycheckn ccall(Time_FromTime[], PyPtr,
(Cint, Cint, Cint, Cint, PyPtr, PyPtr),
Dates.hour(t), Dates.minute(t), Dates.second(t),
Dates.millisecond(t) * 1000,
pynothing[], TimeType[]))

function PyObject(p::Dates.Second)
# normalize to make Cint overflow less likely
s = Dates.value(p)
Expand All @@ -120,12 +131,15 @@ end
PyDate_Check(o::PyObject) = pyisinstance(o, DateType[])
PyDateTime_Check(o::PyObject) = pyisinstance(o, DateTimeType[])
PyDelta_Check(o::PyObject) = pyisinstance(o, DeltaType[])
PyTime_Check(o::PyObject) = pyisinstance(o, TimeType[])

function pydate_query(o::PyObject)
if PyDate_Check(o)
return PyDateTime_Check(o) ? Dates.DateTime : Dates.Date
elseif PyDelta_Check(o)
return Dates.Millisecond
elseif PyTime_Check(o)
return Dates.Time
else
return Union{}
end
Expand Down Expand Up @@ -163,6 +177,20 @@ function convert(::Type{Dates.Date}, o::PyObject)
end
end

function convert(::Type{Dates.Time}, o::PyObject)
if PyTime_Check(o)
GC.@preserve o let dt = convert(Ptr{UInt8}, PyPtr(o)) + PyDate_HEAD
Dates.Time(unsafe_load(dt,1), unsafe_load(dt,2), # hour, minute
unsafe_load(dt,3), # second
div((UInt(unsafe_load(dt,4)) << 16) |
(UInt(unsafe_load(dt,5)) << 8) |
unsafe_load(dt,6), 1000)) # μs ÷ 1000
end
else
throw(ArgumentError("unknown Time type $o"))
end
end

function delta_dsμ(o::PyObject)
PyDelta_Check(o) || throw(ArgumentError("$o is not a timedelta instance"))
p = GC.@preserve o unsafe_load(convert(Ptr{PyDateTime_Delta{Py_hash_t}}, PyPtr(o)))
Expand Down
4 changes: 4 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ const PyInt = pyversion < v"3" ? Int : Clonglong
end

@test roundtripeq(Dates.Date(2012,3,4))
@test_throws ArgumentError convert(Dates.Date, PyObject(42))
@test roundtripeq(Dates.DateTime(2012,3,4, 7,8,9,11))
@test_throws ArgumentError convert(Dates.DateTime, PyObject(42))
@test roundtripeq(Dates.Time(7,8,9,11))
@test_throws ArgumentError convert(Dates.Time, PyObject(42))
@test roundtripeq(Dates.Millisecond(typemax(Int32)))
@test roundtripeq(Dates.Millisecond(typemin(Int32)))
@test roundtripeq(Dates.Second, Dates.Second(typemax(Int32)))
Expand Down
Loading