Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/runtime/standard/time_functions.cc
Line
Count
Source
1
// Copyright 2023 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "runtime/standard/time_functions.h"
16
17
#include <cstdint>
18
#include <functional>
19
#include <string>
20
21
#include "absl/status/status.h"
22
#include "absl/status/statusor.h"
23
#include "absl/strings/match.h"
24
#include "absl/strings/str_replace.h"
25
#include "absl/strings/string_view.h"
26
#include "absl/time/civil_time.h"
27
#include "absl/time/time.h"
28
#include "base/builtins.h"
29
#include "base/function_adapter.h"
30
#include "common/value.h"
31
#include "internal/overflow.h"
32
#include "internal/status_macros.h"
33
#include "runtime/function_registry.h"
34
#include "runtime/runtime_options.h"
35
36
namespace cel {
37
namespace {
38
39
// Timestamp
40
absl::Status FindTimeBreakdown(absl::Time timestamp, absl::string_view tz,
41
0
                               absl::TimeZone::CivilInfo* breakdown) {
42
0
  absl::TimeZone time_zone;
43
44
  // Early return if there is no timezone.
45
0
  if (tz.empty()) {
46
0
    *breakdown = time_zone.At(timestamp);
47
0
    return absl::OkStatus();
48
0
  }
49
50
  // Check to see whether the timezone is an IANA timezone.
51
0
  if (absl::LoadTimeZone(tz, &time_zone)) {
52
0
    *breakdown = time_zone.At(timestamp);
53
0
    return absl::OkStatus();
54
0
  }
55
56
  // Check for times of the format: [+-]HH:MM and convert them into durations
57
  // specified as [+-]HHhMMm.
58
0
  if (absl::StrContains(tz, ":")) {
59
0
    std::string dur = absl::StrCat(tz, "m");
60
0
    absl::StrReplaceAll({{":", "h"}}, &dur);
61
0
    absl::Duration d;
62
0
    if (absl::ParseDuration(dur, &d)) {
63
0
      timestamp += d;
64
0
      *breakdown = time_zone.At(timestamp);
65
0
      return absl::OkStatus();
66
0
    }
67
0
  }
68
69
  // Otherwise, error.
70
0
  return absl::InvalidArgumentError("Invalid timezone");
71
0
}
72
73
Value GetTimeBreakdownPart(
74
    absl::Time timestamp, absl::string_view tz,
75
    const std::function<int64_t(const absl::TimeZone::CivilInfo&)>&
76
0
        extractor_func) {
77
0
  absl::TimeZone::CivilInfo breakdown;
78
0
  auto status = FindTimeBreakdown(timestamp, tz, &breakdown);
79
80
0
  if (!status.ok()) {
81
0
    return ErrorValue(status);
82
0
  }
83
84
0
  return IntValue(extractor_func(breakdown));
85
0
}
86
87
0
Value GetFullYear(absl::Time timestamp, absl::string_view tz) {
88
0
  return GetTimeBreakdownPart(timestamp, tz,
89
0
                              [](const absl::TimeZone::CivilInfo& breakdown) {
90
0
                                return breakdown.cs.year();
91
0
                              });
92
0
}
93
94
0
Value GetMonth(absl::Time timestamp, absl::string_view tz) {
95
0
  return GetTimeBreakdownPart(timestamp, tz,
96
0
                              [](const absl::TimeZone::CivilInfo& breakdown) {
97
0
                                return breakdown.cs.month() - 1;
98
0
                              });
99
0
}
100
101
0
Value GetDayOfYear(absl::Time timestamp, absl::string_view tz) {
102
0
  return GetTimeBreakdownPart(
103
0
      timestamp, tz, [](const absl::TimeZone::CivilInfo& breakdown) {
104
0
        return absl::GetYearDay(absl::CivilDay(breakdown.cs)) - 1;
105
0
      });
106
0
}
107
108
0
Value GetDayOfMonth(absl::Time timestamp, absl::string_view tz) {
109
0
  return GetTimeBreakdownPart(timestamp, tz,
110
0
                              [](const absl::TimeZone::CivilInfo& breakdown) {
111
0
                                return breakdown.cs.day() - 1;
112
0
                              });
113
0
}
114
115
0
Value GetDate(absl::Time timestamp, absl::string_view tz) {
116
0
  return GetTimeBreakdownPart(timestamp, tz,
117
0
                              [](const absl::TimeZone::CivilInfo& breakdown) {
118
0
                                return breakdown.cs.day();
119
0
                              });
120
0
}
121
122
0
Value GetDayOfWeek(absl::Time timestamp, absl::string_view tz) {
123
0
  return GetTimeBreakdownPart(
124
0
      timestamp, tz, [](const absl::TimeZone::CivilInfo& breakdown) {
125
0
        absl::Weekday weekday = absl::GetWeekday(breakdown.cs);
126
127
        // get day of week from the date in UTC, zero-based, zero for Sunday,
128
        // based on GetDayOfWeek CEL function definition.
129
0
        int weekday_num = static_cast<int>(weekday);
130
0
        weekday_num = (weekday_num == 6) ? 0 : weekday_num + 1;
131
0
        return weekday_num;
132
0
      });
133
0
}
134
135
0
Value GetHours(absl::Time timestamp, absl::string_view tz) {
136
0
  return GetTimeBreakdownPart(timestamp, tz,
137
0
                              [](const absl::TimeZone::CivilInfo& breakdown) {
138
0
                                return breakdown.cs.hour();
139
0
                              });
140
0
}
141
142
0
Value GetMinutes(absl::Time timestamp, absl::string_view tz) {
143
0
  return GetTimeBreakdownPart(timestamp, tz,
144
0
                              [](const absl::TimeZone::CivilInfo& breakdown) {
145
0
                                return breakdown.cs.minute();
146
0
                              });
147
0
}
148
149
0
Value GetSeconds(absl::Time timestamp, absl::string_view tz) {
150
0
  return GetTimeBreakdownPart(timestamp, tz,
151
0
                              [](const absl::TimeZone::CivilInfo& breakdown) {
152
0
                                return breakdown.cs.second();
153
0
                              });
154
0
}
155
156
0
Value GetMilliseconds(absl::Time timestamp, absl::string_view tz) {
157
0
  return GetTimeBreakdownPart(
158
0
      timestamp, tz, [](const absl::TimeZone::CivilInfo& breakdown) {
159
0
        return absl::ToInt64Milliseconds(breakdown.subsecond);
160
0
      });
161
0
}
162
163
absl::Status RegisterTimestampFunctions(FunctionRegistry& registry,
164
14.5k
                                        const RuntimeOptions& options) {
165
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
166
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
167
14.5k
          CreateDescriptor(builtin::kFullYear, true),
168
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
169
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
170
14.5k
            return GetFullYear(ts, tz.ToString());
171
14.5k
          })));
172
173
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
174
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
175
14.5k
          builtin::kFullYear, true),
176
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
177
14.5k
          [](absl::Time ts) -> Value { return GetFullYear(ts, ""); })));
178
179
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
180
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
181
14.5k
          CreateDescriptor(builtin::kMonth, true),
182
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
183
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
184
14.5k
            return GetMonth(ts, tz.ToString());
185
14.5k
          })));
186
187
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
188
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kMonth,
189
14.5k
                                                                true),
190
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
191
14.5k
          [](absl::Time ts) -> Value { return GetMonth(ts, ""); })));
192
193
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
194
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
195
14.5k
          CreateDescriptor(builtin::kDayOfYear, true),
196
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
197
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
198
14.5k
            return GetDayOfYear(ts, tz.ToString());
199
14.5k
          })));
200
201
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
202
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
203
14.5k
          builtin::kDayOfYear, true),
204
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
205
14.5k
          [](absl::Time ts) -> Value { return GetDayOfYear(ts, ""); })));
206
207
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
208
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
209
14.5k
          CreateDescriptor(builtin::kDayOfMonth, true),
210
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
211
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
212
14.5k
            return GetDayOfMonth(ts, tz.ToString());
213
14.5k
          })));
214
215
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
216
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
217
14.5k
          builtin::kDayOfMonth, true),
218
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
219
14.5k
          [](absl::Time ts) -> Value { return GetDayOfMonth(ts, ""); })));
220
221
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
222
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
223
14.5k
          CreateDescriptor(builtin::kDate, true),
224
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
225
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
226
14.5k
            return GetDate(ts, tz.ToString());
227
14.5k
          })));
228
229
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
230
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kDate,
231
14.5k
                                                                true),
232
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
233
14.5k
          [](absl::Time ts) -> Value { return GetDate(ts, ""); })));
234
235
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
236
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
237
14.5k
          CreateDescriptor(builtin::kDayOfWeek, true),
238
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
239
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
240
14.5k
            return GetDayOfWeek(ts, tz.ToString());
241
14.5k
          })));
242
243
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
244
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
245
14.5k
          builtin::kDayOfWeek, true),
246
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
247
14.5k
          [](absl::Time ts) -> Value { return GetDayOfWeek(ts, ""); })));
248
249
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
250
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
251
14.5k
          CreateDescriptor(builtin::kHours, true),
252
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
253
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
254
14.5k
            return GetHours(ts, tz.ToString());
255
14.5k
          })));
256
257
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
258
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kHours,
259
14.5k
                                                                true),
260
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
261
14.5k
          [](absl::Time ts) -> Value { return GetHours(ts, ""); })));
262
263
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
264
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
265
14.5k
          CreateDescriptor(builtin::kMinutes, true),
266
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
267
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
268
14.5k
            return GetMinutes(ts, tz.ToString());
269
14.5k
          })));
270
271
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
272
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
273
14.5k
          builtin::kMinutes, true),
274
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
275
14.5k
          [](absl::Time ts) -> Value { return GetMinutes(ts, ""); })));
276
277
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
278
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
279
14.5k
          CreateDescriptor(builtin::kSeconds, true),
280
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
281
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
282
14.5k
            return GetSeconds(ts, tz.ToString());
283
14.5k
          })));
284
285
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
286
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
287
14.5k
          builtin::kSeconds, true),
288
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
289
14.5k
          [](absl::Time ts) -> Value { return GetSeconds(ts, ""); })));
290
291
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
292
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
293
14.5k
          CreateDescriptor(builtin::kMilliseconds, true),
294
14.5k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
295
14.5k
          WrapFunction([](absl::Time ts, const StringValue& tz) -> Value {
296
14.5k
            return GetMilliseconds(ts, tz.ToString());
297
14.5k
          })));
298
299
14.5k
  return registry.Register(
300
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
301
14.5k
          builtin::kMilliseconds, true),
302
14.5k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
303
14.5k
          [](absl::Time ts) -> Value { return GetMilliseconds(ts, ""); }));
304
14.5k
}
305
306
absl::Status RegisterCheckedTimeArithmeticFunctions(
307
0
    FunctionRegistry& registry) {
308
0
  CEL_RETURN_IF_ERROR(registry.Register(
309
0
      BinaryFunctionAdapter<Value, absl::Time,
310
0
                            absl::Duration>::CreateDescriptor(builtin::kAdd,
311
0
                                                              false),
312
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>::
313
0
          WrapFunction(
314
0
              [](absl::Time t1, absl::Duration d2) -> absl::StatusOr<Value> {
315
0
                auto sum = cel::internal::CheckedAdd(t1, d2);
316
0
                if (!sum.ok()) {
317
0
                  return ErrorValue(sum.status());
318
0
                }
319
0
                return TimestampValue(*sum);
320
0
              })));
321
322
0
  CEL_RETURN_IF_ERROR(registry.Register(
323
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration,
324
0
                            absl::Time>::CreateDescriptor(builtin::kAdd, false),
325
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration, absl::Time>::
326
0
          WrapFunction(
327
0
              [](absl::Duration d2, absl::Time t1) -> absl::StatusOr<Value> {
328
0
                auto sum = cel::internal::CheckedAdd(t1, d2);
329
0
                if (!sum.ok()) {
330
0
                  return ErrorValue(sum.status());
331
0
                }
332
0
                return TimestampValue(*sum);
333
0
              })));
334
335
0
  CEL_RETURN_IF_ERROR(registry.Register(
336
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration,
337
0
                            absl::Duration>::CreateDescriptor(builtin::kAdd,
338
0
                                                              false),
339
0
      BinaryFunctionAdapter<
340
0
          absl::StatusOr<Value>, absl::Duration,
341
0
          absl::Duration>::WrapFunction([](absl::Duration d1, absl::Duration d2)
342
0
                                            -> absl::StatusOr<Value> {
343
0
        auto sum = cel::internal::CheckedAdd(d1, d2);
344
0
        if (!sum.ok()) {
345
0
          return ErrorValue(sum.status());
346
0
        }
347
0
        return DurationValue(*sum);
348
0
      })));
349
350
0
  CEL_RETURN_IF_ERROR(registry.Register(
351
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>::
352
0
          CreateDescriptor(builtin::kSubtract, false),
353
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>::
354
0
          WrapFunction(
355
0
              [](absl::Time t1, absl::Duration d2) -> absl::StatusOr<Value> {
356
0
                auto diff = cel::internal::CheckedSub(t1, d2);
357
0
                if (!diff.ok()) {
358
0
                  return ErrorValue(diff.status());
359
0
                }
360
0
                return TimestampValue(*diff);
361
0
              })));
362
363
0
  CEL_RETURN_IF_ERROR(registry.Register(
364
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time,
365
0
                            absl::Time>::CreateDescriptor(builtin::kSubtract,
366
0
                                                          false),
367
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Time>::
368
0
          WrapFunction(
369
0
              [](absl::Time t1, absl::Time t2) -> absl::StatusOr<Value> {
370
0
                auto diff = cel::internal::CheckedSub(t1, t2);
371
0
                if (!diff.ok()) {
372
0
                  return ErrorValue(diff.status());
373
0
                }
374
0
                return DurationValue(*diff);
375
0
              })));
376
377
0
  CEL_RETURN_IF_ERROR(registry.Register(
378
0
      BinaryFunctionAdapter<
379
0
          absl::StatusOr<Value>, absl::Duration,
380
0
          absl::Duration>::CreateDescriptor(builtin::kSubtract, false),
381
0
      BinaryFunctionAdapter<
382
0
          absl::StatusOr<Value>, absl::Duration,
383
0
          absl::Duration>::WrapFunction([](absl::Duration d1, absl::Duration d2)
384
0
                                            -> absl::StatusOr<Value> {
385
0
        auto diff = cel::internal::CheckedSub(d1, d2);
386
0
        if (!diff.ok()) {
387
0
          return ErrorValue(diff.status());
388
0
        }
389
0
        return DurationValue(*diff);
390
0
      })));
391
392
0
  return absl::OkStatus();
393
0
}
394
395
absl::Status RegisterUncheckedTimeArithmeticFunctions(
396
14.5k
    FunctionRegistry& registry) {
397
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
398
14.5k
      BinaryFunctionAdapter<Value, absl::Time,
399
14.5k
                            absl::Duration>::CreateDescriptor(builtin::kAdd,
400
14.5k
                                                              false),
401
14.5k
      BinaryFunctionAdapter<Value, absl::Time, absl::Duration>::WrapFunction(
402
14.5k
          [](absl::Time t1, absl::Duration d2) -> Value {
403
14.5k
            return UnsafeTimestampValue(t1 + d2);
404
14.5k
          })));
405
406
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
407
14.5k
      BinaryFunctionAdapter<Value, absl::Duration,
408
14.5k
                            absl::Time>::CreateDescriptor(builtin::kAdd, false),
409
14.5k
      BinaryFunctionAdapter<Value, absl::Duration, absl::Time>::WrapFunction(
410
14.5k
          [](absl::Duration d2, absl::Time t1) -> Value {
411
14.5k
            return UnsafeTimestampValue(t1 + d2);
412
14.5k
          })));
413
414
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
415
14.5k
      BinaryFunctionAdapter<Value, absl::Duration,
416
14.5k
                            absl::Duration>::CreateDescriptor(builtin::kAdd,
417
14.5k
                                                              false),
418
14.5k
      BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>::
419
14.5k
          WrapFunction([](absl::Duration d1, absl::Duration d2) -> Value {
420
14.5k
            return UnsafeDurationValue(d1 + d2);
421
14.5k
          })));
422
423
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
424
14.5k
      BinaryFunctionAdapter<Value, absl::Time, absl::Duration>::
425
14.5k
          CreateDescriptor(builtin::kSubtract, false),
426
427
14.5k
      BinaryFunctionAdapter<Value, absl::Time, absl::Duration>::WrapFunction(
428
429
14.5k
          [](absl::Time t1, absl::Duration d2) -> Value {
430
14.5k
            return UnsafeTimestampValue(t1 - d2);
431
14.5k
          })));
432
433
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
434
14.5k
      BinaryFunctionAdapter<Value, absl::Time, absl::Time>::CreateDescriptor(
435
14.5k
          builtin::kSubtract, false),
436
14.5k
      BinaryFunctionAdapter<Value, absl::Time, absl::Time>::WrapFunction(
437
438
14.5k
          [](absl::Time t1, absl::Time t2) -> Value {
439
14.5k
            return UnsafeDurationValue(t1 - t2);
440
14.5k
          })));
441
442
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
443
14.5k
      BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>::
444
14.5k
          CreateDescriptor(builtin::kSubtract, false),
445
14.5k
      BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>::
446
14.5k
          WrapFunction([](absl::Duration d1, absl::Duration d2) -> Value {
447
14.5k
            return UnsafeDurationValue(d1 - d2);
448
14.5k
          })));
449
450
14.5k
  return absl::OkStatus();
451
14.5k
}
452
453
14.5k
absl::Status RegisterDurationFunctions(FunctionRegistry& registry) {
454
  // duration breakdown accessor functions
455
14.5k
  using DurationAccessorFunction =
456
14.5k
      UnaryFunctionAdapter<int64_t, absl::Duration>;
457
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
458
14.5k
      DurationAccessorFunction::CreateDescriptor(builtin::kHours, true),
459
14.5k
      DurationAccessorFunction::WrapFunction(
460
14.5k
          [](absl::Duration d) -> int64_t { return absl::ToInt64Hours(d); })));
461
462
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
463
14.5k
      DurationAccessorFunction::CreateDescriptor(builtin::kMinutes, true),
464
14.5k
      DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t {
465
14.5k
        return absl::ToInt64Minutes(d);
466
14.5k
      })));
467
468
14.5k
  CEL_RETURN_IF_ERROR(registry.Register(
469
14.5k
      DurationAccessorFunction::CreateDescriptor(builtin::kSeconds, true),
470
14.5k
      DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t {
471
14.5k
        return absl::ToInt64Seconds(d);
472
14.5k
      })));
473
474
14.5k
  return registry.Register(
475
14.5k
      DurationAccessorFunction::CreateDescriptor(builtin::kMilliseconds, true),
476
14.5k
      DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t {
477
0
        constexpr int64_t millis_per_second = 1000L;
478
0
        return absl::ToInt64Milliseconds(d) % millis_per_second;
479
0
      }));
480
14.5k
}
481
482
}  // namespace
483
484
absl::Status RegisterTimeFunctions(FunctionRegistry& registry,
485
14.5k
                                   const RuntimeOptions& options) {
486
14.5k
  CEL_RETURN_IF_ERROR(RegisterTimestampFunctions(registry, options));
487
14.5k
  CEL_RETURN_IF_ERROR(RegisterDurationFunctions(registry));
488
489
  // Special arithmetic operators for Timestamp and Duration
490
  // TODO(uncreated-issue/37): deprecate unchecked time math functions when clients no
491
  // longer depend on them.
492
14.5k
  if (options.enable_timestamp_duration_overflow_errors) {
493
0
    return RegisterCheckedTimeArithmeticFunctions(registry);
494
0
  }
495
496
14.5k
  return RegisterUncheckedTimeArithmeticFunctions(registry);
497
14.5k
}
498
499
}  // namespace cel