Coverage Report

Created: 2026-10-09 06:57

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.h"
34
#include "runtime/function_registry.h"
35
#include "runtime/runtime_options.h"
36
#include "google/protobuf/arena.h"
37
38
namespace cel {
39
namespace {
40
41
// Timestamp
42
absl::Status FindTimeBreakdown(absl::Time timestamp, absl::string_view tz,
43
0
                               absl::TimeZone::CivilInfo* breakdown) {
44
0
  absl::TimeZone time_zone;
45
46
  // Early return if there is no timezone.
47
0
  if (tz.empty()) {
48
0
    *breakdown = time_zone.At(timestamp);
49
0
    return absl::OkStatus();
50
0
  }
51
52
  // Check to see whether the timezone is an IANA timezone.
53
0
  if (absl::LoadTimeZone(tz, &time_zone)) {
54
0
    *breakdown = time_zone.At(timestamp);
55
0
    return absl::OkStatus();
56
0
  }
57
58
  // Check for times of the format: [+-]HH:MM and convert them into durations
59
  // specified as [+-]HHhMMm.
60
0
  if (absl::StrContains(tz, ":")) {
61
0
    std::string dur = absl::StrCat(tz, "m");
62
0
    absl::StrReplaceAll({{":", "h"}}, &dur);
63
0
    absl::Duration d;
64
0
    if (absl::ParseDuration(dur, &d)) {
65
0
      timestamp += d;
66
0
      *breakdown = time_zone.At(timestamp);
67
0
      return absl::OkStatus();
68
0
    }
69
0
  }
70
71
  // Otherwise, error.
72
0
  return absl::InvalidArgumentError("Invalid timezone");
73
0
}
74
75
Value GetTimeBreakdownPart(
76
    absl::Time timestamp, absl::string_view tz,
77
    const std::function<int64_t(const absl::TimeZone::CivilInfo&)>&
78
        extractor_func,
79
0
    google::protobuf::Arena* arena) {
80
0
  absl::TimeZone::CivilInfo breakdown;
81
0
  auto status = FindTimeBreakdown(timestamp, tz, &breakdown);
82
83
0
  if (!status.ok()) {
84
0
    return ErrorValue::From(status, arena);
85
0
  }
86
87
0
  return IntValue(extractor_func(breakdown));
88
0
}
89
90
Value GetFullYear(absl::Time timestamp, absl::string_view tz,
91
0
                  const Function::InvokeContext& context) {
92
0
  return GetTimeBreakdownPart(
93
0
      timestamp, tz,
94
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
95
0
        return breakdown.cs.year();
96
0
      },
97
0
      context.arena());
98
0
}
99
100
Value GetMonth(absl::Time timestamp, absl::string_view tz,
101
0
               const Function::InvokeContext& context) {
102
0
  return GetTimeBreakdownPart(
103
0
      timestamp, tz,
104
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
105
0
        return breakdown.cs.month() - 1;
106
0
      },
107
0
      context.arena());
108
0
}
109
110
Value GetDayOfYear(absl::Time timestamp, absl::string_view tz,
111
0
                   const Function::InvokeContext& context) {
112
0
  return GetTimeBreakdownPart(
113
0
      timestamp, tz,
114
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
115
0
        return absl::GetYearDay(absl::CivilDay(breakdown.cs)) - 1;
116
0
      },
117
0
      context.arena());
118
0
}
119
120
Value GetDayOfMonth(absl::Time timestamp, absl::string_view tz,
121
0
                    const Function::InvokeContext& context) {
122
0
  return GetTimeBreakdownPart(
123
0
      timestamp, tz,
124
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
125
0
        return breakdown.cs.day() - 1;
126
0
      },
127
0
      context.arena());
128
0
}
129
130
Value GetDate(absl::Time timestamp, absl::string_view tz,
131
0
              const Function::InvokeContext& context) {
132
0
  return GetTimeBreakdownPart(
133
0
      timestamp, tz,
134
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
135
0
        return breakdown.cs.day();
136
0
      },
137
0
      context.arena());
138
0
}
139
140
Value GetDayOfWeek(absl::Time timestamp, absl::string_view tz,
141
0
                   const Function::InvokeContext& context) {
142
0
  return GetTimeBreakdownPart(
143
0
      timestamp, tz,
144
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
145
0
        absl::Weekday weekday = absl::GetWeekday(breakdown.cs);
146
147
        // get day of week from the date in UTC, zero-based, zero for Sunday,
148
        // based on GetDayOfWeek CEL function definition.
149
0
        int weekday_num = static_cast<int>(weekday);
150
0
        weekday_num = (weekday_num == 6) ? 0 : weekday_num + 1;
151
0
        return weekday_num;
152
0
      },
153
0
      context.arena());
154
0
}
155
156
Value GetHours(absl::Time timestamp, absl::string_view tz,
157
0
               const Function::InvokeContext& context) {
158
0
  return GetTimeBreakdownPart(
159
0
      timestamp, tz,
160
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
161
0
        return breakdown.cs.hour();
162
0
      },
163
0
      context.arena());
164
0
}
165
166
Value GetMinutes(absl::Time timestamp, absl::string_view tz,
167
0
                 const Function::InvokeContext& context) {
168
0
  return GetTimeBreakdownPart(
169
0
      timestamp, tz,
170
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
171
0
        return breakdown.cs.minute();
172
0
      },
173
0
      context.arena());
174
0
}
175
176
Value GetSeconds(absl::Time timestamp, absl::string_view tz,
177
0
                 const Function::InvokeContext& context) {
178
0
  return GetTimeBreakdownPart(
179
0
      timestamp, tz,
180
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
181
0
        return breakdown.cs.second();
182
0
      },
183
0
      context.arena());
184
0
}
185
186
Value GetMilliseconds(absl::Time timestamp, absl::string_view tz,
187
0
                      const Function::InvokeContext& context) {
188
0
  return GetTimeBreakdownPart(
189
0
      timestamp, tz,
190
0
      [](const absl::TimeZone::CivilInfo& breakdown) {
191
0
        return absl::ToInt64Milliseconds(breakdown.subsecond);
192
0
      },
193
0
      context.arena());
194
0
}
195
196
absl::Status RegisterTimestampFunctions(FunctionRegistry& registry,
197
22.7k
                                        const RuntimeOptions& options) {
198
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
199
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
200
22.7k
          CreateDescriptor(builtin::kFullYear, true),
201
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
202
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
203
22.7k
                          const Function::InvokeContext& context) -> Value {
204
22.7k
            return GetFullYear(ts, tz.ToString(), context);
205
22.7k
          })));
206
207
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
208
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
209
22.7k
          builtin::kFullYear, true),
210
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
211
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
212
22.7k
            return GetFullYear(ts, "", context);
213
22.7k
          })));
214
215
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
216
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
217
22.7k
          CreateDescriptor(builtin::kMonth, true),
218
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
219
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
220
22.7k
                          const Function::InvokeContext& context) -> Value {
221
22.7k
            return GetMonth(ts, tz.ToString(), context);
222
22.7k
          })));
223
224
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
225
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kMonth,
226
22.7k
                                                                true),
227
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
228
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
229
22.7k
            return GetMonth(ts, "", context);
230
22.7k
          })));
231
232
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
233
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
234
22.7k
          CreateDescriptor(builtin::kDayOfYear, true),
235
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
236
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
237
22.7k
                          const Function::InvokeContext& context) -> Value {
238
22.7k
            return GetDayOfYear(ts, tz.ToString(), context);
239
22.7k
          })));
240
241
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
242
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
243
22.7k
          builtin::kDayOfYear, true),
244
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
245
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
246
22.7k
            return GetDayOfYear(ts, "", context);
247
22.7k
          })));
248
249
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
250
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
251
22.7k
          CreateDescriptor(builtin::kDayOfMonth, true),
252
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
253
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
254
22.7k
                          const Function::InvokeContext& context) -> Value {
255
22.7k
            return GetDayOfMonth(ts, tz.ToString(), context);
256
22.7k
          })));
257
258
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
259
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
260
22.7k
          builtin::kDayOfMonth, true),
261
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
262
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
263
22.7k
            return GetDayOfMonth(ts, "", context);
264
22.7k
          })));
265
266
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
267
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
268
22.7k
          CreateDescriptor(builtin::kDate, true),
269
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
270
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
271
22.7k
                          const Function::InvokeContext& context) -> Value {
272
22.7k
            return GetDate(ts, tz.ToString(), context);
273
22.7k
          })));
274
275
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
276
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kDate,
277
22.7k
                                                                true),
278
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
279
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
280
22.7k
            return GetDate(ts, "", context);
281
22.7k
          })));
282
283
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
284
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
285
22.7k
          CreateDescriptor(builtin::kDayOfWeek, true),
286
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
287
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
288
22.7k
                          const Function::InvokeContext& context) -> Value {
289
22.7k
            return GetDayOfWeek(ts, tz.ToString(), context);
290
22.7k
          })));
291
292
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
293
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
294
22.7k
          builtin::kDayOfWeek, true),
295
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
296
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
297
22.7k
            return GetDayOfWeek(ts, "", context);
298
22.7k
          })));
299
300
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
301
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
302
22.7k
          CreateDescriptor(builtin::kHours, true),
303
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
304
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
305
22.7k
                          const Function::InvokeContext& context) -> Value {
306
22.7k
            return GetHours(ts, tz.ToString(), context);
307
22.7k
          })));
308
309
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
310
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kHours,
311
22.7k
                                                                true),
312
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
313
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
314
22.7k
            return GetHours(ts, "", context);
315
22.7k
          })));
316
317
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
318
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
319
22.7k
          CreateDescriptor(builtin::kMinutes, true),
320
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
321
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
322
22.7k
                          const Function::InvokeContext& context) -> Value {
323
22.7k
            return GetMinutes(ts, tz.ToString(), context);
324
22.7k
          })));
325
326
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
327
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
328
22.7k
          builtin::kMinutes, true),
329
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
330
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
331
22.7k
            return GetMinutes(ts, "", context);
332
22.7k
          })));
333
334
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
335
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
336
22.7k
          CreateDescriptor(builtin::kSeconds, true),
337
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
338
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
339
22.7k
                          const Function::InvokeContext& context) -> Value {
340
22.7k
            return GetSeconds(ts, tz.ToString(), context);
341
22.7k
          })));
342
343
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
344
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
345
22.7k
          builtin::kSeconds, true),
346
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
347
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
348
22.7k
            return GetSeconds(ts, "", context);
349
22.7k
          })));
350
351
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
352
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
353
22.7k
          CreateDescriptor(builtin::kMilliseconds, true),
354
22.7k
      BinaryFunctionAdapter<Value, absl::Time, const StringValue&>::
355
22.7k
          WrapFunction([](absl::Time ts, const StringValue& tz,
356
22.7k
                          const Function::InvokeContext& context) -> Value {
357
22.7k
            return GetMilliseconds(ts, tz.ToString(), context);
358
22.7k
          })));
359
360
22.7k
  return registry.Register(
361
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(
362
22.7k
          builtin::kMilliseconds, true),
363
22.7k
      UnaryFunctionAdapter<Value, absl::Time>::WrapFunction(
364
22.7k
          [](absl::Time ts, const Function::InvokeContext& context) -> Value {
365
0
            return GetMilliseconds(ts, "", context);
366
0
          }));
367
22.7k
}
368
369
absl::Status RegisterCheckedTimeArithmeticFunctions(
370
0
    FunctionRegistry& registry) {
371
0
  CEL_RETURN_IF_ERROR(registry.Register(
372
0
      BinaryFunctionAdapter<Value, absl::Time,
373
0
                            absl::Duration>::CreateDescriptor(builtin::kAdd,
374
0
                                                              false),
375
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>::
376
0
          WrapFunction([](absl::Time t1, absl::Duration d2,
377
0
                          const Function::InvokeContext& context)
378
0
                           -> absl::StatusOr<Value> {
379
0
            auto sum = cel::internal::CheckedAdd(t1, d2);
380
0
            if (!sum.ok()) {
381
0
              return ErrorValue::From(sum.status(), context.arena());
382
0
            }
383
0
            return TimestampValue(*sum);
384
0
          })));
385
386
0
  CEL_RETURN_IF_ERROR(registry.Register(
387
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration,
388
0
                            absl::Time>::CreateDescriptor(builtin::kAdd, false),
389
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration, absl::Time>::
390
0
          WrapFunction([](absl::Duration d2, absl::Time t1,
391
0
                          const Function::InvokeContext& context)
392
0
                           -> absl::StatusOr<Value> {
393
0
            auto sum = cel::internal::CheckedAdd(t1, d2);
394
0
            if (!sum.ok()) {
395
0
              return ErrorValue::From(sum.status(), context.arena());
396
0
            }
397
0
            return TimestampValue(*sum);
398
0
          })));
399
400
0
  CEL_RETURN_IF_ERROR(registry.Register(
401
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration,
402
0
                            absl::Duration>::CreateDescriptor(builtin::kAdd,
403
0
                                                              false),
404
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration,
405
0
                            absl::Duration>::
406
0
          WrapFunction([](absl::Duration d1, absl::Duration d2,
407
0
                          const Function::InvokeContext& context)
408
0
                           -> absl::StatusOr<Value> {
409
0
            auto sum = cel::internal::CheckedAdd(d1, d2);
410
0
            if (!sum.ok()) {
411
0
              return ErrorValue::From(sum.status(), context.arena());
412
0
            }
413
0
            return DurationValue(*sum);
414
0
          })));
415
416
0
  CEL_RETURN_IF_ERROR(registry.Register(
417
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>::
418
0
          CreateDescriptor(builtin::kSubtract, false),
419
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>::
420
0
          WrapFunction([](absl::Time t1, absl::Duration d2,
421
0
                          const Function::InvokeContext& context)
422
0
                           -> absl::StatusOr<Value> {
423
0
            auto diff = cel::internal::CheckedSub(t1, d2);
424
0
            if (!diff.ok()) {
425
0
              return ErrorValue::From(diff.status(), context.arena());
426
0
            }
427
0
            return TimestampValue(*diff);
428
0
          })));
429
430
0
  CEL_RETURN_IF_ERROR(registry.Register(
431
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time,
432
0
                            absl::Time>::CreateDescriptor(builtin::kSubtract,
433
0
                                                          false),
434
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Time>::
435
0
          WrapFunction([](absl::Time t1, absl::Time t2,
436
0
                          const Function::InvokeContext& context)
437
0
                           -> absl::StatusOr<Value> {
438
0
            auto diff = cel::internal::CheckedSub(t1, t2);
439
0
            if (!diff.ok()) {
440
0
              return ErrorValue::From(diff.status(), context.arena());
441
0
            }
442
0
            return DurationValue(*diff);
443
0
          })));
444
445
0
  CEL_RETURN_IF_ERROR(registry.Register(
446
0
      BinaryFunctionAdapter<
447
0
          absl::StatusOr<Value>, absl::Duration,
448
0
          absl::Duration>::CreateDescriptor(builtin::kSubtract, false),
449
0
      BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration,
450
0
                            absl::Duration>::
451
0
          WrapFunction([](absl::Duration d1, absl::Duration d2,
452
0
                          const Function::InvokeContext& context)
453
0
                           -> absl::StatusOr<Value> {
454
0
            auto diff = cel::internal::CheckedSub(d1, d2);
455
0
            if (!diff.ok()) {
456
0
              return ErrorValue::From(diff.status(), context.arena());
457
0
            }
458
0
            return DurationValue(*diff);
459
0
          })));
460
461
0
  return absl::OkStatus();
462
0
}
463
464
absl::Status RegisterUncheckedTimeArithmeticFunctions(
465
22.7k
    FunctionRegistry& registry) {
466
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
467
22.7k
      BinaryFunctionAdapter<Value, absl::Time,
468
22.7k
                            absl::Duration>::CreateDescriptor(builtin::kAdd,
469
22.7k
                                                              false),
470
22.7k
      BinaryFunctionAdapter<Value, absl::Time, absl::Duration>::WrapFunction(
471
22.7k
          [](absl::Time t1, absl::Duration d2) -> Value {
472
22.7k
            return UnsafeTimestampValue(t1 + d2);
473
22.7k
          })));
474
475
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
476
22.7k
      BinaryFunctionAdapter<Value, absl::Duration,
477
22.7k
                            absl::Time>::CreateDescriptor(builtin::kAdd, false),
478
22.7k
      BinaryFunctionAdapter<Value, absl::Duration, absl::Time>::WrapFunction(
479
22.7k
          [](absl::Duration d2, absl::Time t1) -> Value {
480
22.7k
            return UnsafeTimestampValue(t1 + d2);
481
22.7k
          })));
482
483
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
484
22.7k
      BinaryFunctionAdapter<Value, absl::Duration,
485
22.7k
                            absl::Duration>::CreateDescriptor(builtin::kAdd,
486
22.7k
                                                              false),
487
22.7k
      BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>::
488
22.7k
          WrapFunction([](absl::Duration d1, absl::Duration d2) -> Value {
489
22.7k
            return UnsafeDurationValue(d1 + d2);
490
22.7k
          })));
491
492
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
493
22.7k
      BinaryFunctionAdapter<Value, absl::Time, absl::Duration>::
494
22.7k
          CreateDescriptor(builtin::kSubtract, false),
495
496
22.7k
      BinaryFunctionAdapter<Value, absl::Time, absl::Duration>::WrapFunction(
497
498
22.7k
          [](absl::Time t1, absl::Duration d2) -> Value {
499
22.7k
            return UnsafeTimestampValue(t1 - d2);
500
22.7k
          })));
501
502
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
503
22.7k
      BinaryFunctionAdapter<Value, absl::Time, absl::Time>::CreateDescriptor(
504
22.7k
          builtin::kSubtract, false),
505
22.7k
      BinaryFunctionAdapter<Value, absl::Time, absl::Time>::WrapFunction(
506
507
22.7k
          [](absl::Time t1, absl::Time t2) -> Value {
508
22.7k
            return UnsafeDurationValue(t1 - t2);
509
22.7k
          })));
510
511
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
512
22.7k
      BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>::
513
22.7k
          CreateDescriptor(builtin::kSubtract, false),
514
22.7k
      BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>::
515
22.7k
          WrapFunction([](absl::Duration d1, absl::Duration d2) -> Value {
516
22.7k
            return UnsafeDurationValue(d1 - d2);
517
22.7k
          })));
518
519
22.7k
  return absl::OkStatus();
520
22.7k
}
521
522
22.7k
absl::Status RegisterDurationFunctions(FunctionRegistry& registry) {
523
  // duration breakdown accessor functions
524
22.7k
  using DurationAccessorFunction =
525
22.7k
      UnaryFunctionAdapter<int64_t, absl::Duration>;
526
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
527
22.7k
      DurationAccessorFunction::CreateDescriptor(builtin::kHours, true),
528
22.7k
      DurationAccessorFunction::WrapFunction(
529
22.7k
          [](absl::Duration d) -> int64_t { return absl::ToInt64Hours(d); })));
530
531
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
532
22.7k
      DurationAccessorFunction::CreateDescriptor(builtin::kMinutes, true),
533
22.7k
      DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t {
534
22.7k
        return absl::ToInt64Minutes(d);
535
22.7k
      })));
536
537
22.7k
  CEL_RETURN_IF_ERROR(registry.Register(
538
22.7k
      DurationAccessorFunction::CreateDescriptor(builtin::kSeconds, true),
539
22.7k
      DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t {
540
22.7k
        return absl::ToInt64Seconds(d);
541
22.7k
      })));
542
543
22.7k
  return registry.Register(
544
22.7k
      DurationAccessorFunction::CreateDescriptor(builtin::kMilliseconds, true),
545
22.7k
      DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t {
546
0
        constexpr int64_t millis_per_second = 1000L;
547
0
        return absl::ToInt64Milliseconds(d) % millis_per_second;
548
0
      }));
549
22.7k
}
550
551
}  // namespace
552
553
absl::Status RegisterTimeFunctions(FunctionRegistry& registry,
554
22.7k
                                   const RuntimeOptions& options) {
555
22.7k
  CEL_RETURN_IF_ERROR(RegisterTimestampFunctions(registry, options));
556
22.7k
  CEL_RETURN_IF_ERROR(RegisterDurationFunctions(registry));
557
558
  // Special arithmetic operators for Timestamp and Duration
559
  // TODO(uncreated-issue/37): deprecate unchecked time math functions when clients no
560
  // longer depend on them.
561
22.7k
  if (options.enable_timestamp_duration_overflow_errors) {
562
0
    return RegisterCheckedTimeArithmeticFunctions(registry);
563
0
  }
564
565
22.7k
  return RegisterUncheckedTimeArithmeticFunctions(registry);
566
22.7k
}
567
568
}  // namespace cel