Uh oh!
There was an error while loading. Please reload this page.
ARROW-13549: [C++] Add casts from timestamp to date/time - #10933
ARROW-13549: [C++] Add casts from timestamp to date/time#10933lidavidm wants to merge 2 commits into
Conversation
lidavidm
commented
Aug 13, 2021
Looks like this will conflict with #10457/ARROW-12980 so we may want to hold off on this one, as that one looks close. |
rok
commented
Aug 15, 2021
Indeed. Looks great! The only thing I would recommend would be to use |
lidavidm
commented
Aug 16, 2021
ARROW-12980 looks like it should be close so I'll rebase on top of that now. |
rok
commented
Aug 17, 2021
@lidavidmARROW-12980 was merged. |
lidavidm
commented
Aug 17, 2021
Thanks for the heads up! I'll get this rebased soon. |
There was a problem hiding this comment.
After ARROW-12980, this now works with timezones? (or can work)
There was a problem hiding this comment.
Doh, I forgot to update the docstring. Yes, they all work with timezones and there are tests. I've updated all the docstrings.
pitrou
commented
Aug 18, 2021
Why aren't these implemented as cast kernels instead? |
lidavidm
commented
Aug 18, 2021
Ah, that makes sense. I'll update this to be a cast instead, though I think we are going to need some refactoring of the utilities. |
lidavidm
commented
Aug 18, 2021
There's already a cast from timestamp to date32/date64, however, placing this implementation there would change semantics a little bit: Also Python doesn't expose a way to set only allow_time_truncate (though maybe we should just allow the cast if we refactor things here). But that does raise the question of whether a cast is appropriate for this operation (since it seems like casting is generally interpreted more like reinterpret_cast, while this is an actual conversion). Also for instance a cast of a timestamp-with-timezone right now is quite different than what this does. |
rok
commented
Aug 18, 2021
Date extraction could also be thought of as a rounding to a day interval. |
jorisvandenbossche
commented
Aug 19, 2021
Personally, I think having a separate (non-cast) kernel to extract those components make sense from a user perspective (but can of course share implementation), and complementing the other timestamp component extraction kernels we already have.
I would say that the current casting semantics are wrong and should be fixed? (in any case, the "extracted" date is clearly wrong, whether that's seen as a consequence of the "unsafe" cast or not is to be discussed I suppose) There are actually two "unsafe" steps in this conversion it seems (which explains the wrong part): arr=pa.array(["1970-01-01 00:00:59.123456789","2000-02-29 23:23:23.999999999","1899-01-01 00:59:20.001001001"]).cast(pa.timestamp("ns"))
>>>arr.cast(pa.date64())
...
ArrowInvalid: Castingfromtimestamp[ns] todate64[ms] wouldlosedata: 59123456789
../src/arrow/compute/kernels/scalar_cast_temporal.cc:178 (ShiftTime<int64_t, int64_t>(ctx, conversion.first, conversion.second, input, output))
# that error is actually coming from a conversion to milliseconds# (and you don't really care about the part being lost for conversion to date ..)>>>arr.cast(pa.timestamp("ms"))
...
ArrowInvalid: Castingfromtimestamp[ns] totimestamp[ms] wouldlosedata: 59123456789# when ignoring this lost part in conversion to ms, then casting to date gives another error:>>>arr.cast(pa.timestamp("ms"), safe=False).cast(pa.date64())
...
ArrowInvalid: Timestampvaluehadnon-zerointradaymillisecondsAnd I suppose that when those intraday milliseconds are ignored by doing arrow/cpp/src/arrow/compute/kernels/scalar_cast_temporal.cc Lines 198 to 202 in d3af6d4 By subtracting the remainder we basically round towards zero (it seems C++ module operator behaves differently as Python when involving negative integers |
pitrou
commented
Aug 19, 2021
I'm not sure I understand what you mean with the reinterpret_cast comment. Our casts are definitely conversions (see the Decimal -> Decimal casts for example). |
pitrou
commented
Aug 19, 2021
My problem is that I don't even understand the difference they're supposed to make to the "normal" casts. Are those (supposedly) different semantics really desired? I would favour fixing/improving the currently implemented casts, if necessary. |
lidavidm
commented
Aug 19, 2021
I guess I was wondering if the current behavior (just 'reinterpreting' the timestamp) is still useful, it sounds like not. I think the path here is to make the kernels in this PR into safe casts, so that users don't have to specify an unsafe cast. (In theory you could get away with just allow_time_truncate but I think there's no way to pass that in Python.) |
2b9b2a2 to
bda1eaeComparelidavidm
commented
Sep 9, 2021
This is now implemented as a cast and is rebased. For casting timestamp->time, we do check the truncation/overflow flags in some scenarios (e.g. if you want to cast a nanosecond timestamp to a time32). |
jorisvandenbossche
commented
Sep 9, 2021
BTW, I stumbled on https://issues.apache.org/jira/browse/ARROW-10213, so it seems @lidavidm you already opened an issue about this buggy (round instead of extract, see above #10933 (comment)) behaviour a while ago .. :-) |
lidavidm
commented
Sep 9, 2021
Whoops! Yeah, let me link/close-as-duplicate the issues and update the description. Thanks for finding this. |
jorisvandenbossche
commented
Sep 9, 2021
I think there can be some value in the current meaning of "safe" cast of timestamp to date. For example, it would allow you to convert timestamps-which-are-actually-dates safely to dates, without loosing any time information. While if we make the safe cast to ignore the time values by default, the only way to do this is by first checking if all hour/minute/second/subsecond components are zero. |
lidavidm
commented
Sep 27, 2021
I've rebased this again. |
| } | ||
| template <typename T> | ||
| enable_if_timestamp<T, const std::string> GetInputTimezone(const DataType& type) { |
There was a problem hiding this comment.
Doesn't this conflict with the non-template GetInputTimezone(const DataType&) above? At least it seems there's a potential for confusion. Perhaps we can simply reconcile both implementations? For example:
staticinlineconst std::string& GetInputTimezone(const DataType& type) {
staticconst std::string no_timezone = "";
switch (type.id()) {
case Type::TIMESTAMP:
return checked_cast<const TimestampType&>(type).timezone();
default:
return no_timezone;
}
}There was a problem hiding this comment.
Good point, fixed. I suppose it worked before since it was called as GetInputTimezone<T>(...).
pitrou
commented
Sep 27, 2021
@jorisvandenbossche Any further comments on this? |
Closesapache#10933 from lidavidm/arrow-13549 Authored-by: David Li <li.davidm96@gmail.com> Signed-off-by: Antoine Pitrou <antoine@python.org>
No description provided.