diff --git a/Project.toml b/Project.toml index 487e620c..72a9f8a7 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "RCall" uuid = "6f49c342-dc21-5d91-9882-a32aef131414" authors = ["Douglas Bates ", "Randy Lai ", "Simon Byrne "] -version = "0.14.2" +version = "0.14.3" [deps] CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" @@ -23,6 +23,7 @@ CategoricalArrays = "0.8, 0.9, 0.10" Conda = "1.4" DataFrames = "0.21, 0.22, 1.0" DataStructures = "0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18" +Logging = "0, 1" Preferences = "1" Requires = "0.5.2, 1" StatsModels = "0.6, 0.7" @@ -33,10 +34,11 @@ julia = "1.6" AxisArrays = "39de3d68-74b9-583c-8d2d-e117c070f3a9" CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Dates", "AxisArrays", "REPL", "Test", "Random", "CondaPkg", "Pkg"] +test = ["Dates", "AxisArrays", "REPL", "Test", "Random", "CondaPkg", "Pkg", "Logging"] diff --git a/docs/src/conversions.md b/docs/src/conversions.md index cd0c0f6c..602ff4c1 100644 --- a/docs/src/conversions.md +++ b/docs/src/conversions.md @@ -74,6 +74,20 @@ r = robject(d) rcopy(r) ``` +Note that R's `POSIXct` supports higher precision than DateTime: + +```@example 1 +r = reval("as.POSIXct('2020-10-09 12:09:46.1234')") +``` + +```@example 1 +d = rcopy(r) +``` + +!!! note "Conversions to `DateTime` are given in UTC!" + `POSIXct` stores times internally as UTC with a timezone attribute. + The conversion to `DateTime` necessarily strips away timezone information, resulting in UTC values. + ## DataFrames ```@example 1 diff --git a/src/convert/datetime.jl b/src/convert/datetime.jl index de0853cb..52ce658e 100644 --- a/src/convert/datetime.jl +++ b/src/convert/datetime.jl @@ -6,8 +6,15 @@ rcopy(::Type{Date}, s::Ptr{RealSxp}) = rcopy(Date, s[1]) rcopy(::Type{DateTime}, s::Ptr{RealSxp}) = rcopy(DateTime, s[1]) rcopy(::Type{Date}, x::Float64) = Date(Dates.UTInstant(Dates.Day((isnan(x) ? 0 : x) + 719163))) -rcopy(::Type{DateTime}, x::Float64) = - DateTime(Dates.UTInstant(Dates.Millisecond(((isnan(x) ? 0 : x) + 62135683200) * 1000))) +function rcopy(::Type{DateTime}, x::Float64) + ms = ((isnan(x) ? 0 : x) + 62135683200) * 1_000 + ms_int = round(Int, ms) + if ms != ms_int + @debug "Precision lost in conversion to DateTime" + end + + return DateTime(Dates.UTInstant(Millisecond(ms_int))) +end # implicit conversion `rcopy(d)`. function rcopytype(::Type{RClass{:Date}}, s::Ptr{RealSxp}) diff --git a/test/convert/datetime.jl b/test/convert/datetime.jl index a1b150e4..18e224b9 100644 --- a/test/convert/datetime.jl +++ b/test/convert/datetime.jl @@ -135,3 +135,13 @@ r = RObject(d) @test ismissing(rcopy(r)[2]) @test rcopy(Array, r)[[1,3]] == d[[1,3]] @test ismissing(rcopy(Array, r)[2]) + +# note that POSIXct stores times internaly as UTC, but assumes local +# timezone information +@test rcopy(R"as.POSIXct('2020-10-09 12:09:46', tz='UTC')") == DateTime("2020-10-09T12:09:46") + +# microseconds on R side #396 +@test_logs((:debug, "Precision lost in conversion to DateTime"), + min_level=Logging.Debug, + rcopy(R"as.POSIXct('2020-10-09 12:09:46.1234')")) +@test rcopy(R"as.POSIXct('2020-10-09 12:09:46.1234', tz='UTC')") == DateTime("2020-10-09T12:09:46.123") diff --git a/test/runtests.jl b/test/runtests.jl index 4174dd26..03720949 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,5 @@ using RCall +using Logging using Test using DataStructures: OrderedDict