Skip to content
Merged
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
66 changes: 50 additions & 16 deletions r/src/r_to_arrow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,33 +583,37 @@ int64_t get_TimeUnit_multiplier(TimeUnit::type unit) {
}
}

Result<int> get_difftime_unit_multiplier(SEXP x) {
std::string unit(CHAR(STRING_ELT(Rf_getAttrib(x, symbols::units), 0)));
if (unit == "secs") {
return 1;
} else if (unit == "mins") {
return 60;
} else if (unit == "hours") {
return 3600;
} else if (unit == "days") {
return 86400;
} else if (unit == "weeks") {
return 604800;
} else {
return Status::Invalid("unknown difftime unit");
}
}

template <typename T>
class RPrimitiveConverter<T, enable_if_t<is_time_type<T>::value>>
: public PrimitiveConverter<T, RConverter> {
public:
Status Extend(SEXP x, int64_t size, int64_t offset = 0) override {
RETURN_NOT_OK(this->Reserve(size - offset));
auto rtype = GetVectorType(x);
// This probably also not accept duration
if (rtype != TIME && rtype != DURATION) {
return Status::Invalid("Invalid conversion to time");
}

// multiplier to get the number of seconds from the value stored in the R vector
int difftime_multiplier;
std::string unit(CHAR(STRING_ELT(Rf_getAttrib(x, symbols::units), 0)));
if (unit == "secs") {
difftime_multiplier = 1;
} else if (unit == "mins") {
difftime_multiplier = 60;
} else if (unit == "hours") {
difftime_multiplier = 3600;
} else if (unit == "days") {
difftime_multiplier = 86400;
} else if (unit == "weeks") {
difftime_multiplier = 604800;
} else {
return Status::Invalid("unknown difftime unit");
}
ARROW_ASSIGN_OR_RAISE(int difftime_multiplier, get_difftime_unit_multiplier(x));

// then multiply the seconds by this to match the time unit
auto multiplier =
Expand Down Expand Up @@ -825,7 +829,37 @@ class RPrimitiveConverter<T, enable_if_t<is_duration_type<T>::value>>
: public PrimitiveConverter<T, RConverter> {
public:
Status Extend(SEXP x, int64_t size, int64_t offset = 0) override {
// TODO: look in lubridate
auto rtype = GetVectorType(x);

// only handle <difftime> R objects
if (rtype == DURATION) {
RETURN_NOT_OK(this->Reserve(size - offset));

ARROW_ASSIGN_OR_RAISE(int difftime_multiplier, get_difftime_unit_multiplier(x));

int64_t multiplier = get_TimeUnit_multiplier(this->primitive_type_->unit()) * difftime_multiplier;

auto append_value = [this, multiplier](double value) {
auto converted = static_cast<typename T::c_type>(value * multiplier);
this->primitive_builder_->UnsafeAppend(converted);
return Status::OK();
};
auto append_null = [this]() {
this->primitive_builder_->UnsafeAppendNull();
return Status::OK();
};

if (ALTREP(x)) {
return VisitVector(RVectorIterator_ALTREP<double>(x, offset), size, append_null,
append_value);
} else {
return VisitVector(RVectorIterator<double>(x, offset), size, append_null,
append_value);
}

return Status::OK();
}

return Status::NotImplemented("Extend");
}
};
Expand Down