|
1 | | -@testitem "Date -> DateTime64/InlineDateTime64" begin |
| 1 | +@testitem "Date -> DateTime64" begin |
2 | 2 | using Dates |
3 | 3 | using PythonCall: NumpyDates |
4 | 4 |
|
|
100 | 100 | end |
101 | 101 | end |
102 | 102 |
|
| 103 | +@testitem "String -> DateTime64" begin |
| 104 | + using Dates |
| 105 | + using PythonCall: NumpyDates |
| 106 | + |
| 107 | + # Data generated by: uv run test/scripts/np_dates.py |
| 108 | + # Format: (string_date, unit_symbol, numpy_int_value) |
| 109 | + cases = [ |
| 110 | + ("1969-12-31", :Y, -1), |
| 111 | + ("1969-12-31", :M, -1), |
| 112 | + ("1969-12-31", :D, -1), |
| 113 | + ("1969-12-31", :h, -24), |
| 114 | + ("1969-12-31", :m, -1440), |
| 115 | + ("1969-12-31", :s, -86400), |
| 116 | + ("1969-12-31", :ms, -86400000), |
| 117 | + ("1969-12-31", :us, -86400000000), |
| 118 | + ("1969-12-31", :ns, -86400000000000), |
| 119 | + ("1970-01-01", :Y, 0), |
| 120 | + ("1970-01-01", :M, 0), |
| 121 | + ("1970-01-01", :D, 0), |
| 122 | + ("1970-01-01", :h, 0), |
| 123 | + ("1970-01-01", :m, 0), |
| 124 | + ("1970-01-01", :s, 0), |
| 125 | + ("1970-01-01", :ms, 0), |
| 126 | + ("1970-01-01", :us, 0), |
| 127 | + ("1970-01-01", :ns, 0), |
| 128 | + ("1970-01-02", :Y, 0), |
| 129 | + ("1970-01-02", :M, 0), |
| 130 | + ("1970-01-02", :D, 1), |
| 131 | + ("1970-01-02", :h, 24), |
| 132 | + ("1970-01-02", :m, 1440), |
| 133 | + ("1970-01-02", :s, 86400), |
| 134 | + ("1970-01-02", :ms, 86400000), |
| 135 | + ("1970-01-02", :us, 86400000000), |
| 136 | + ("1970-01-02", :ns, 86400000000000), |
| 137 | + ("1999-12-31", :Y, 29), |
| 138 | + ("1999-12-31", :M, 359), |
| 139 | + ("1999-12-31", :D, 10956), |
| 140 | + ("1999-12-31", :h, 262944), |
| 141 | + ("1999-12-31", :m, 15776640), |
| 142 | + ("1999-12-31", :s, 946598400), |
| 143 | + ("1999-12-31", :ms, 946598400000), |
| 144 | + ("1999-12-31", :us, 946598400000000), |
| 145 | + ("1999-12-31", :ns, 946598400000000000), |
| 146 | + ("2000-02-29", :Y, 30), |
| 147 | + ("2000-02-29", :M, 361), |
| 148 | + ("2000-02-29", :D, 11016), |
| 149 | + ("2000-02-29", :h, 264384), |
| 150 | + ("2000-02-29", :m, 15863040), |
| 151 | + ("2000-02-29", :s, 951782400), |
| 152 | + ("2000-02-29", :ms, 951782400000), |
| 153 | + ("2000-02-29", :us, 951782400000000), |
| 154 | + ("2000-02-29", :ns, 951782400000000000), |
| 155 | + ("1900-01-01", :Y, -70), |
| 156 | + ("1900-01-01", :M, -840), |
| 157 | + ("1900-01-01", :D, -25567), |
| 158 | + ("1900-01-01", :h, -613608), |
| 159 | + ("1900-01-01", :m, -36816480), |
| 160 | + ("1900-01-01", :s, -2208988800), |
| 161 | + ("1900-01-01", :ms, -2208988800000), |
| 162 | + ("1900-01-01", :us, -2208988800000000), |
| 163 | + ("1900-01-01", :ns, -2208988800000000000), |
| 164 | + ("2100-01-01", :Y, 130), |
| 165 | + ("2100-01-01", :M, 1560), |
| 166 | + ("2100-01-01", :D, 47482), |
| 167 | + ("2100-01-01", :h, 1139568), |
| 168 | + ("2100-01-01", :m, 68374080), |
| 169 | + ("2100-01-01", :s, 4102444800), |
| 170 | + ("2100-01-01", :ms, 4102444800000), |
| 171 | + ("2100-01-01", :us, 4102444800000000), |
| 172 | + ("2100-01-01", :ns, 4102444800000000000), |
| 173 | + ] |
| 174 | + |
| 175 | + @testset "$s $usym" for (s, usym, expected) in cases |
| 176 | + # DateTime64 from string |
| 177 | + dt64 = NumpyDates.DateTime64(s, usym) |
| 178 | + @test Dates.value(dt64) == expected |
| 179 | + |
| 180 | + # Inline typed from string |
| 181 | + Uconst = NumpyDates.Unit(usym) |
| 182 | + inline_typed = NumpyDates.InlineDateTime64{Uconst}(s) |
| 183 | + @test Dates.value(inline_typed) == expected |
| 184 | + |
| 185 | + # Inline dynamic from string |
| 186 | + inline_dyn = NumpyDates.InlineDateTime64(s, usym) |
| 187 | + @test Dates.value(inline_dyn) == expected |
| 188 | + @test NumpyDates.unitpair(inline_dyn) == NumpyDates.unitpair(usym) |
| 189 | + end |
| 190 | + |
| 191 | + # NaT string handling (all should produce NaT) |
| 192 | + @testset "$nat" for nat in ("NaT", "nan", "NAN") |
| 193 | + d1 = NumpyDates.DateTime64(nat, :D) |
| 194 | + @test isnan(d1) |
| 195 | + d2 = NumpyDates.InlineDateTime64{NumpyDates.DAYS}(nat) |
| 196 | + @test isnan(d2) |
| 197 | + d3 = NumpyDates.InlineDateTime64(nat, :D) |
| 198 | + @test isnan(d3) |
| 199 | + end |
| 200 | +end |
| 201 | + |
| 202 | +@testitem "String and DateFormat -> DateTime64" begin |
| 203 | + using Dates |
| 204 | + using PythonCall: NumpyDates |
| 205 | + |
| 206 | + # Data based on: uv run test/scripts/np_dates.py and uv run test/scripts/np_datetimes.py |
| 207 | + # We deliberately use formats that differ from the default parser to exercise the (str, format, unit) constructors. |
| 208 | + cases = [ |
| 209 | + # date-only with custom format |
| 210 | + ("1999/12/31", DateFormat("yyyy/mm/dd"), :D, 10956), |
| 211 | + ("1999/12/31", DateFormat("yyyy/mm/dd"), :s, 946598400), |
| 212 | + # datetime with custom format |
| 213 | + ("2000-02-29 12:34:56", DateFormat("yyyy-mm-dd HH:MM:SS"), :s, 951_827_696), |
| 214 | + ( |
| 215 | + "2000-02-29 12:34:56", |
| 216 | + DateFormat("yyyy-mm-dd HH:MM:SS"), |
| 217 | + :ns, |
| 218 | + 951_827_696_000_000_000, |
| 219 | + ), |
| 220 | + ] |
| 221 | + |
| 222 | + @testset "$s $f $usym" for (s, f, usym, expected) in cases |
| 223 | + # DateTime64 from string + format |
| 224 | + dt64 = NumpyDates.DateTime64(s, f, usym) |
| 225 | + @test Dates.value(dt64) == expected |
| 226 | + |
| 227 | + # Inline typed from string + format |
| 228 | + Uconst = NumpyDates.Unit(usym) |
| 229 | + inline_typed = NumpyDates.InlineDateTime64{Uconst}(s, f) |
| 230 | + @test Dates.value(inline_typed) == expected |
| 231 | + |
| 232 | + # NOTE: InlineDateTime64(s, f, u) dynamic constructor is not exercised here |
| 233 | + # because it currently dispatches to InlineTimeDelta64 in the implementation. |
| 234 | + # When fixed, we can add: |
| 235 | + # inline_dyn = NumpyDates.InlineDateTime64(s, f, usym) |
| 236 | + # @test Dates.value(inline_dyn) == expected |
| 237 | + end |
| 238 | +end |
| 239 | + |
| 240 | +@testitem "AbstractDateTime64 -> DateTime64" begin |
| 241 | + using Dates |
| 242 | + using PythonCall: NumpyDates |
| 243 | + |
| 244 | + # Pass-through when units match |
| 245 | + d = Date(1970, 1, 2) |
| 246 | + x = NumpyDates.DateTime64(d, :D) # expected value 1 |
| 247 | + y = NumpyDates.DateTime64(x, :D) |
| 248 | + @test Dates.value(y) == 1 |
| 249 | + @test NumpyDates.unitpair(y) == NumpyDates.unitpair(:D) |
| 250 | + |
| 251 | + # NaT changes unit and remains NaT |
| 252 | + nat_d = NumpyDates.DateTime64("NaT", :D) |
| 253 | + z = NumpyDates.DateTime64(nat_d, :s) |
| 254 | + @test isnan(z) |
| 255 | + @test NumpyDates.unitpair(z) == NumpyDates.unitpair(:s) |
| 256 | +end |
| 257 | + |
| 258 | +@testitem "Integer -> DateTime64" begin |
| 259 | + using Dates |
| 260 | + using PythonCall: NumpyDates |
| 261 | + |
| 262 | + # DateTime64(value, unit) |
| 263 | + x = NumpyDates.DateTime64(946_684_799, :s) # 1999-12-31T23:59:59 |
| 264 | + @test Dates.value(x) == 946_684_799 |
| 265 | + @test Dates.DateTime(x) == DateTime(1999, 12, 31, 23, 59, 59) |
| 266 | + |
| 267 | + y = NumpyDates.DateTime64(10_956, :D) # 1999-12-31 |
| 268 | + @test Dates.value(y) == 10_956 |
| 269 | + @test Dates.Date(y) == Date(1999, 12, 31) |
| 270 | + |
| 271 | + # InlineDateTime64{U}(value) |
| 272 | + s1 = NumpyDates.InlineDateTime64{NumpyDates.SECONDS}(3_600) # +1 hour |
| 273 | + @test Dates.value(s1) == 3_600 |
| 274 | + @test Dates.DateTime(s1) == DateTime(1970, 1, 1, 1, 0, 0) |
| 275 | + |
| 276 | + # InlineDateTime64 with multiplier in the unit parameter |
| 277 | + s2 = NumpyDates.InlineDateTime64{(NumpyDates.SECONDS, 2)}(1_800) # 1_800 * 2s = 3_600s |
| 278 | + @test Dates.value(s2) == 1_800 |
| 279 | + @test Dates.DateTime(s2) == DateTime(1970, 1, 1, 1, 0, 0) |
| 280 | +end |
| 281 | + |
103 | 282 | @testitem "DateTime -> DateTime64/InlineDateTime64" begin |
104 | 283 | using Dates |
105 | 284 | using PythonCall: NumpyDates |
|
0 commit comments