1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
18 // Implementation of casting to (or between) temporal types
22 #include "arrow/array/builder_time.h"
23 #include "arrow/compute/kernels/common.h"
24 #include "arrow/compute/kernels/scalar_cast_internal.h"
25 #include "arrow/compute/kernels/temporal_internal.h"
26 #include "arrow/util/bitmap_reader.h"
27 #include "arrow/util/time.h"
28 #include "arrow/util/value_parsing.h"
32 using internal::ParseValue
;
37 constexpr int64_t kMillisecondsInDay
= 86400000;
39 // ----------------------------------------------------------------------
40 // From one timestamp to another
42 template <typename in_type
, typename out_type
>
43 Status
ShiftTime(KernelContext
* ctx
, const util::DivideOrMultiply factor_op
,
44 const int64_t factor
, const ArrayData
& input
, ArrayData
* output
) {
45 const CastOptions
& options
= checked_cast
<const CastState
&>(*ctx
->state()).options
;
46 auto in_data
= input
.GetValues
<in_type
>(1);
47 auto out_data
= output
->GetMutableValues
<out_type
>(1);
50 for (int64_t i
= 0; i
< input
.length
; i
++) {
51 out_data
[i
] = static_cast<out_type
>(in_data
[i
]);
53 } else if (factor_op
== util::MULTIPLY
) {
54 if (options
.allow_time_overflow
) {
55 for (int64_t i
= 0; i
< input
.length
; i
++) {
56 out_data
[i
] = static_cast<out_type
>(in_data
[i
] * factor
);
59 #define RAISE_OVERFLOW_CAST(VAL) \
60 return Status::Invalid("Casting from ", input.type->ToString(), " to ", \
61 output->type->ToString(), " would result in ", \
62 "out of bounds timestamp: ", VAL);
64 int64_t max_val
= std::numeric_limits
<int64_t>::max() / factor
;
65 int64_t min_val
= std::numeric_limits
<int64_t>::min() / factor
;
66 if (input
.null_count
!= 0) {
67 BitmapReader
bit_reader(input
.buffers
[0]->data(), input
.offset
, input
.length
);
68 for (int64_t i
= 0; i
< input
.length
; i
++) {
69 if (bit_reader
.IsSet() && (in_data
[i
] < min_val
|| in_data
[i
] > max_val
)) {
70 RAISE_OVERFLOW_CAST(in_data
[i
]);
72 out_data
[i
] = static_cast<out_type
>(in_data
[i
] * factor
);
76 for (int64_t i
= 0; i
< input
.length
; i
++) {
77 if (in_data
[i
] < min_val
|| in_data
[i
] > max_val
) {
78 RAISE_OVERFLOW_CAST(in_data
[i
]);
80 out_data
[i
] = static_cast<out_type
>(in_data
[i
] * factor
);
84 #undef RAISE_OVERFLOW_CAST
87 if (options
.allow_time_truncate
) {
88 for (int64_t i
= 0; i
< input
.length
; i
++) {
89 out_data
[i
] = static_cast<out_type
>(in_data
[i
] / factor
);
92 #define RAISE_INVALID_CAST(VAL) \
93 return Status::Invalid("Casting from ", input.type->ToString(), " to ", \
94 output->type->ToString(), " would lose data: ", VAL);
96 if (input
.null_count
!= 0) {
97 BitmapReader
bit_reader(input
.buffers
[0]->data(), input
.offset
, input
.length
);
98 for (int64_t i
= 0; i
< input
.length
; i
++) {
99 out_data
[i
] = static_cast<out_type
>(in_data
[i
] / factor
);
100 if (bit_reader
.IsSet() && (out_data
[i
] * factor
!= in_data
[i
])) {
101 RAISE_INVALID_CAST(in_data
[i
]);
106 for (int64_t i
= 0; i
< input
.length
; i
++) {
107 out_data
[i
] = static_cast<out_type
>(in_data
[i
] / factor
);
108 if (out_data
[i
] * factor
!= in_data
[i
]) {
109 RAISE_INVALID_CAST(in_data
[i
]);
114 #undef RAISE_INVALID_CAST
121 template <template <typename
...> class Op
, typename OutType
, typename
... Args
>
122 Status
ExtractTemporal(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
,
124 const auto& ty
= checked_cast
<const TimestampType
&>(*batch
[0].type());
127 case TimeUnit::SECOND
:
128 return TemporalComponentExtract
<Op
, std::chrono::seconds
, TimestampType
, OutType
,
129 Args
...>::Exec(ctx
, batch
, out
, args
...);
130 case TimeUnit::MILLI
:
131 return TemporalComponentExtract
<Op
, std::chrono::milliseconds
, TimestampType
,
132 OutType
, Args
...>::Exec(ctx
, batch
, out
, args
...);
133 case TimeUnit::MICRO
:
134 return TemporalComponentExtract
<Op
, std::chrono::microseconds
, TimestampType
,
135 OutType
, Args
...>::Exec(ctx
, batch
, out
, args
...);
137 return TemporalComponentExtract
<Op
, std::chrono::nanoseconds
, TimestampType
,
138 OutType
, Args
...>::Exec(ctx
, batch
, out
, args
...);
140 return Status::Invalid("Unknown timestamp unit: ", ty
);
143 // <TimestampType, TimestampType> and <DurationType, DurationType>
144 template <typename O
, typename I
>
147 enable_if_t
<(is_timestamp_type
<O
>::value
&& is_timestamp_type
<I
>::value
) ||
148 (is_duration_type
<O
>::value
&& is_duration_type
<I
>::value
)>> {
149 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
150 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
152 const ArrayData
& input
= *batch
[0].array();
153 ArrayData
* output
= out
->mutable_array();
155 // If units are the same, zero copy, otherwise convert
156 const auto& in_type
= checked_cast
<const I
&>(*batch
[0].type());
157 const auto& out_type
= checked_cast
<const O
&>(*output
->type
);
159 // The units may be equal if the time zones are different. We might go to
160 // lengths to make this zero copy in the future but we leave it for now
162 auto conversion
= util::GetTimestampConversion(in_type
.unit(), out_type
.unit());
163 return ShiftTime
<int64_t, int64_t>(ctx
, conversion
.first
, conversion
.second
, input
,
168 // ----------------------------------------------------------------------
169 // From timestamp to date32 or date64
172 struct CastFunctor
<Date32Type
, TimestampType
> {
173 template <typename Duration
, typename Localizer
>
175 Date32(const FunctionOptions
* options
, Localizer
&& localizer
)
176 : localizer_(std::move(localizer
)) {}
178 template <typename T
, typename Arg0
>
179 T
Call(KernelContext
*, Arg0 arg
, Status
*) const {
180 return static_cast<T
>(static_cast<const int32_t>(
181 floor
<days
>(localizer_
.template ConvertTimePoint
<Duration
>(arg
))
186 Localizer localizer_
;
189 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
190 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
191 return ExtractTemporal
<Date32
, Date32Type
>(ctx
, batch
, out
);
196 struct CastFunctor
<Date64Type
, TimestampType
> {
197 template <typename Duration
, typename Localizer
>
199 constexpr static int64_t kMillisPerDay
= 86400000;
200 Date64(const FunctionOptions
* options
, Localizer
&& localizer
)
201 : localizer_(std::move(localizer
)) {}
203 template <typename T
, typename Arg0
>
204 T
Call(KernelContext
*, Arg0 arg
, Status
*) const {
205 return static_cast<T
>(
207 static_cast<const int32_t>(
208 floor
<days
>(localizer_
.template ConvertTimePoint
<Duration
>(arg
))
213 Localizer localizer_
;
216 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
217 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
218 return ExtractTemporal
<Date64
, Date64Type
>(ctx
, batch
, out
);
222 // ----------------------------------------------------------------------
223 // From timestamp to time32 or time64
225 template <typename Duration
, typename Localizer
>
226 struct ExtractTimeDownscaled
{
227 ExtractTimeDownscaled(const FunctionOptions
* options
, Localizer
&& localizer
,
228 const int64_t factor
)
229 : localizer_(std::move(localizer
)), factor_(factor
) {}
231 template <typename T
, typename Arg0
>
232 T
Call(KernelContext
*, Arg0 arg
, Status
* st
) const {
233 const auto t
= localizer_
.template ConvertTimePoint
<Duration
>(arg
);
234 const int64_t orig_value
= (t
- floor
<days
>(t
)).count();
235 const T scaled
= static_cast<T
>(orig_value
/ factor_
);
236 const int64_t unscaled
= static_cast<int64_t>(scaled
) * factor_
;
237 if (unscaled
!= orig_value
) {
238 *st
= Status::Invalid("Cast would lose data: ", orig_value
);
244 Localizer localizer_
;
245 const int64_t factor_
;
248 template <typename Duration
, typename Localizer
>
249 struct ExtractTimeUpscaledUnchecked
{
250 ExtractTimeUpscaledUnchecked(const FunctionOptions
* options
, Localizer
&& localizer
,
251 const int64_t factor
)
252 : localizer_(std::move(localizer
)), factor_(factor
) {}
254 template <typename T
, typename Arg0
>
255 T
Call(KernelContext
*, Arg0 arg
, Status
*) const {
256 const auto t
= localizer_
.template ConvertTimePoint
<Duration
>(arg
);
257 const int64_t orig_value
= (t
- floor
<days
>(t
)).count();
258 return static_cast<T
>(orig_value
* factor_
);
261 Localizer localizer_
;
262 const int64_t factor_
;
265 template <typename Duration
, typename Localizer
>
266 struct ExtractTimeDownscaledUnchecked
{
267 ExtractTimeDownscaledUnchecked(const FunctionOptions
* options
, Localizer
&& localizer
,
268 const int64_t factor
)
269 : localizer_(std::move(localizer
)), factor_(factor
) {}
271 template <typename T
, typename Arg0
>
272 T
Call(KernelContext
*, Arg0 arg
, Status
*) const {
273 const auto t
= localizer_
.template ConvertTimePoint
<Duration
>(arg
);
274 const int64_t orig_value
= (t
- floor
<days
>(t
)).count();
275 return static_cast<T
>(orig_value
/ factor_
);
278 Localizer localizer_
;
279 const int64_t factor_
;
283 struct CastFunctor
<Time32Type
, TimestampType
> {
284 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
285 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
286 const auto& in_type
= checked_cast
<const TimestampType
&>(*batch
[0].type());
287 const auto& out_type
= checked_cast
<const Time32Type
&>(*out
->type());
288 const CastOptions
& options
= checked_cast
<const CastState
&>(*ctx
->state()).options
;
290 // Shifting before extraction won't work since the timestamp may not fit
291 // even if the time itself fits
292 if (in_type
.unit() != out_type
.unit()) {
293 auto conversion
= util::GetTimestampConversion(in_type
.unit(), out_type
.unit());
294 if (conversion
.first
== util::MULTIPLY
) {
295 return ExtractTemporal
<ExtractTimeUpscaledUnchecked
, Time32Type
>(
296 ctx
, batch
, out
, conversion
.second
);
298 if (options
.allow_time_truncate
) {
299 return ExtractTemporal
<ExtractTimeDownscaledUnchecked
, Time32Type
>(
300 ctx
, batch
, out
, conversion
.second
);
302 return ExtractTemporal
<ExtractTimeDownscaled
, Time32Type
>(ctx
, batch
, out
,
307 return ExtractTemporal
<ExtractTimeUpscaledUnchecked
, Time32Type
>(ctx
, batch
, out
, 1);
312 struct CastFunctor
<Time64Type
, TimestampType
> {
313 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
314 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
315 const auto& in_type
= checked_cast
<const TimestampType
&>(*batch
[0].type());
316 const auto& out_type
= checked_cast
<const Time64Type
&>(*out
->type());
317 const CastOptions
& options
= checked_cast
<const CastState
&>(*ctx
->state()).options
;
319 // Shifting before extraction won't work since the timestamp may not fit
320 // even if the time itself fits
321 if (in_type
.unit() != out_type
.unit()) {
322 auto conversion
= util::GetTimestampConversion(in_type
.unit(), out_type
.unit());
323 if (conversion
.first
== util::MULTIPLY
) {
324 return ExtractTemporal
<ExtractTimeUpscaledUnchecked
, Time64Type
>(
325 ctx
, batch
, out
, conversion
.second
);
327 if (options
.allow_time_truncate
) {
328 return ExtractTemporal
<ExtractTimeDownscaledUnchecked
, Time64Type
>(
329 ctx
, batch
, out
, conversion
.second
);
331 return ExtractTemporal
<ExtractTimeDownscaled
, Time64Type
>(ctx
, batch
, out
,
336 return ExtractTemporal
<ExtractTimeUpscaledUnchecked
, Time64Type
>(ctx
, batch
, out
, 1);
340 // ----------------------------------------------------------------------
341 // From one time32 or time64 to another
343 template <typename O
, typename I
>
344 struct CastFunctor
<O
, I
, enable_if_t
<is_time_type
<I
>::value
&& is_time_type
<O
>::value
>> {
345 using in_t
= typename
I::c_type
;
346 using out_t
= typename
O::c_type
;
348 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
349 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
351 const ArrayData
& input
= *batch
[0].array();
352 ArrayData
* output
= out
->mutable_array();
354 // If units are the same, zero copy, otherwise convert
355 const auto& in_type
= checked_cast
<const I
&>(*input
.type
);
356 const auto& out_type
= checked_cast
<const O
&>(*output
->type
);
357 DCHECK_NE(in_type
.unit(), out_type
.unit()) << "Do not cast equal types";
358 auto conversion
= util::GetTimestampConversion(in_type
.unit(), out_type
.unit());
359 return ShiftTime
<in_t
, out_t
>(ctx
, conversion
.first
, conversion
.second
, input
,
364 // ----------------------------------------------------------------------
365 // Between date32 and date64
368 struct CastFunctor
<Date64Type
, Date32Type
> {
369 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
370 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
372 return ShiftTime
<int32_t, int64_t>(ctx
, util::MULTIPLY
, kMillisecondsInDay
,
373 *batch
[0].array(), out
->mutable_array());
378 struct CastFunctor
<Date32Type
, Date64Type
> {
379 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
380 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
382 return ShiftTime
<int64_t, int32_t>(ctx
, util::DIVIDE
, kMillisecondsInDay
,
383 *batch
[0].array(), out
->mutable_array());
387 // ----------------------------------------------------------------------
388 // date32, date64 to timestamp
391 struct CastFunctor
<TimestampType
, Date32Type
> {
392 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
393 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
395 const auto& out_type
= checked_cast
<const TimestampType
&>(*out
->type());
396 // get conversion SECOND -> unit
397 auto conversion
= util::GetTimestampConversion(TimeUnit::SECOND
, out_type
.unit());
398 DCHECK_EQ(conversion
.first
, util::MULTIPLY
);
400 // multiply to achieve days -> unit
401 conversion
.second
*= kMillisecondsInDay
/ 1000;
402 return ShiftTime
<int32_t, int64_t>(ctx
, util::MULTIPLY
, conversion
.second
,
403 *batch
[0].array(), out
->mutable_array());
408 struct CastFunctor
<TimestampType
, Date64Type
> {
409 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
410 DCHECK_EQ(batch
[0].kind(), Datum::ARRAY
);
412 const auto& out_type
= checked_cast
<const TimestampType
&>(*out
->type());
414 // date64 is ms since epoch
415 auto conversion
= util::GetTimestampConversion(TimeUnit::MILLI
, out_type
.unit());
416 return ShiftTime
<int64_t, int64_t>(ctx
, conversion
.first
, conversion
.second
,
417 *batch
[0].array(), out
->mutable_array());
421 // ----------------------------------------------------------------------
422 // String to Timestamp
424 struct ParseTimestamp
{
425 template <typename OutValue
, typename Arg0Value
>
426 OutValue
Call(KernelContext
*, Arg0Value val
, Status
* st
) const {
428 if (ARROW_PREDICT_FALSE(!ParseValue(type
, val
.data(), val
.size(), &result
))) {
429 *st
= Status::Invalid("Failed to parse string: '", val
, "' as a scalar of type ",
435 const TimestampType
& type
;
438 template <typename I
>
439 struct CastFunctor
<TimestampType
, I
, enable_if_t
<is_base_binary_type
<I
>::value
>> {
440 static Status
Exec(KernelContext
* ctx
, const ExecBatch
& batch
, Datum
* out
) {
441 const auto& out_type
= checked_cast
<const TimestampType
&>(*out
->type());
442 applicator::ScalarUnaryNotNullStateful
<TimestampType
, I
, ParseTimestamp
> kernel(
443 ParseTimestamp
{out_type
});
444 return kernel
.Exec(ctx
, batch
, out
);
448 template <typename Type
>
449 void AddCrossUnitCast(CastFunction
* func
) {
451 kernel
.exec
= TrivialScalarUnaryAsArraysExec(CastFunctor
<Type
, Type
>::Exec
);
452 kernel
.signature
= KernelSignature::Make({InputType(Type::type_id
)}, kOutputTargetType
);
453 DCHECK_OK(func
->AddKernel(Type::type_id
, std::move(kernel
)));
456 std::shared_ptr
<CastFunction
> GetDate32Cast() {
457 auto func
= std::make_shared
<CastFunction
>("cast_date32", Type::DATE32
);
458 auto out_ty
= date32();
459 AddCommonCasts(Type::DATE32
, out_ty
, func
.get());
462 AddZeroCopyCast(Type::INT32
, int32(), date32(), func
.get());
465 AddSimpleCast
<Date64Type
, Date32Type
>(date64(), date32(), func
.get());
467 // timestamp -> date32
468 AddSimpleCast
<TimestampType
, Date32Type
>(InputType(Type::TIMESTAMP
), date32(),
473 std::shared_ptr
<CastFunction
> GetDate64Cast() {
474 auto func
= std::make_shared
<CastFunction
>("cast_date64", Type::DATE64
);
475 auto out_ty
= date64();
476 AddCommonCasts(Type::DATE64
, out_ty
, func
.get());
479 AddZeroCopyCast(Type::INT64
, int64(), date64(), func
.get());
482 AddSimpleCast
<Date32Type
, Date64Type
>(date32(), date64(), func
.get());
484 // timestamp -> date64
485 AddSimpleCast
<TimestampType
, Date64Type
>(InputType(Type::TIMESTAMP
), date64(),
490 std::shared_ptr
<CastFunction
> GetDurationCast() {
491 auto func
= std::make_shared
<CastFunction
>("cast_duration", Type::DURATION
);
492 AddCommonCasts(Type::DURATION
, kOutputTargetType
, func
.get());
494 auto seconds
= duration(TimeUnit::SECOND
);
495 auto millis
= duration(TimeUnit::MILLI
);
496 auto micros
= duration(TimeUnit::MICRO
);
497 auto nanos
= duration(TimeUnit::NANO
);
499 // Same integer representation
500 AddZeroCopyCast(Type::INT64
, /*in_type=*/int64(), kOutputTargetType
, func
.get());
503 AddCrossUnitCast
<DurationType
>(func
.get());
508 std::shared_ptr
<CastFunction
> GetIntervalCast() {
509 auto func
= std::make_shared
<CastFunction
>("cast_month_day_nano_interval",
510 Type::INTERVAL_MONTH_DAY_NANO
);
511 AddCommonCasts(Type::INTERVAL_MONTH_DAY_NANO
, kOutputTargetType
, func
.get());
515 std::shared_ptr
<CastFunction
> GetTime32Cast() {
516 auto func
= std::make_shared
<CastFunction
>("cast_time32", Type::TIME32
);
517 AddCommonCasts(Type::TIME32
, kOutputTargetType
, func
.get());
519 // Zero copy when the unit is the same or same integer representation
520 AddZeroCopyCast(Type::INT32
, /*in_type=*/int32(), kOutputTargetType
, func
.get());
523 AddSimpleCast
<Time64Type
, Time32Type
>(InputType(Type::TIME64
), kOutputTargetType
,
527 AddCrossUnitCast
<Time32Type
>(func
.get());
529 // timestamp -> time32
530 AddSimpleCast
<TimestampType
, Time32Type
>(InputType(Type::TIMESTAMP
), kOutputTargetType
,
536 std::shared_ptr
<CastFunction
> GetTime64Cast() {
537 auto func
= std::make_shared
<CastFunction
>("cast_time64", Type::TIME64
);
538 AddCommonCasts(Type::TIME64
, kOutputTargetType
, func
.get());
540 // Zero copy when the unit is the same or same integer representation
541 AddZeroCopyCast(Type::INT64
, /*in_type=*/int64(), kOutputTargetType
, func
.get());
544 AddSimpleCast
<Time32Type
, Time64Type
>(InputType(Type::TIME32
), kOutputTargetType
,
548 AddCrossUnitCast
<Time64Type
>(func
.get());
550 // timestamp -> time64
551 AddSimpleCast
<TimestampType
, Time64Type
>(InputType(Type::TIMESTAMP
), kOutputTargetType
,
557 std::shared_ptr
<CastFunction
> GetTimestampCast() {
558 auto func
= std::make_shared
<CastFunction
>("cast_timestamp", Type::TIMESTAMP
);
559 AddCommonCasts(Type::TIMESTAMP
, kOutputTargetType
, func
.get());
561 // Same integer representation
562 AddZeroCopyCast(Type::INT64
, /*in_type=*/int64(), kOutputTargetType
, func
.get());
565 // TODO: ARROW-8876, these casts are not directly tested
566 AddSimpleCast
<Date32Type
, TimestampType
>(InputType(Type::DATE32
), kOutputTargetType
,
568 AddSimpleCast
<Date64Type
, TimestampType
>(InputType(Type::DATE64
), kOutputTargetType
,
571 // string -> timestamp
572 AddSimpleCast
<StringType
, TimestampType
>(utf8(), kOutputTargetType
, func
.get());
573 // large_string -> timestamp
574 AddSimpleCast
<LargeStringType
, TimestampType
>(large_utf8(), kOutputTargetType
,
577 // From one timestamp to another
578 AddCrossUnitCast
<TimestampType
>(func
.get());
583 std::vector
<std::shared_ptr
<CastFunction
>> GetTemporalCasts() {
584 std::vector
<std::shared_ptr
<CastFunction
>> functions
;
586 functions
.push_back(GetDate32Cast());
587 functions
.push_back(GetDate64Cast());
588 functions
.push_back(GetDurationCast());
589 functions
.push_back(GetIntervalCast());
590 functions
.push_back(GetTime32Cast());
591 functions
.push_back(GetTime64Cast());
592 functions
.push_back(GetTimestampCast());
596 } // namespace internal
597 } // namespace compute