openhab-jrubyscripting 5.0.0.rc2 → 5.0.0.rc3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/openhab/core/items/generic_item.rb +13 -5
- data/lib/openhab/core/items/metadata/hash.rb +17 -34
- data/lib/openhab/core/items/persistence.rb +2 -0
- data/lib/openhab/core/items/semantics/enumerable.rb +6 -4
- data/lib/openhab/core/profile_factory.rb +2 -0
- data/lib/openhab/core/provider.rb +8 -1
- data/lib/openhab/core/rules/provider.rb +25 -0
- data/lib/openhab/core/rules/registry.rb +76 -0
- data/lib/openhab/core/rules/rule.rb +150 -0
- data/lib/openhab/core/rules.rb +25 -0
- data/lib/openhab/core/timer.rb +5 -7
- data/lib/openhab/core/types.rb +1 -1
- data/lib/openhab/core.rb +0 -16
- data/lib/openhab/core_ext/java/list.rb +436 -0
- data/lib/openhab/core_ext/java/map.rb +66 -0
- data/lib/openhab/core_ext/java/zoned_date_time.rb +1 -2
- data/lib/openhab/core_ext/ruby/date.rb +2 -0
- data/lib/openhab/core_ext/ruby/date_time.rb +53 -0
- data/lib/openhab/core_ext/ruby/time.rb +88 -86
- data/lib/openhab/dsl/events/watch_event.rb +1 -1
- data/lib/openhab/dsl/items/builder.rb +8 -3
- data/lib/openhab/dsl/items/ensure.rb +6 -2
- data/lib/openhab/dsl/items/timed_command.rb +10 -11
- data/lib/openhab/dsl/rules/automation_rule.rb +36 -13
- data/lib/openhab/dsl/rules/builder.rb +99 -8
- data/lib/openhab/dsl/rules/name_inference.rb +0 -5
- data/lib/openhab/dsl/rules/terse.rb +1 -2
- data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +17 -53
- data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +0 -3
- data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +1 -1
- data/lib/openhab/dsl/rules.rb +0 -21
- data/lib/openhab/dsl/thread_local.rb +2 -2
- data/lib/openhab/dsl/timer_manager.rb +3 -1
- data/lib/openhab/dsl/version.rb +1 -1
- data/lib/openhab/dsl.rb +12 -105
- data/lib/openhab/log.rb +2 -2
- data/lib/openhab/rspec/example_group.rb +42 -0
- data/lib/openhab/rspec/helpers.rb +31 -8
- data/lib/openhab/rspec/hooks.rb +3 -6
- data/lib/openhab/rspec/karaf.rb +45 -27
- data/lib/openhab/rspec/mocks/synchronous_executor.rb +11 -4
- data/lib/openhab/rspec/mocks/timer.rb +2 -1
- data/lib/openhab/rspec/suspend_rules.rb +4 -2
- metadata +23 -2
@@ -0,0 +1,436 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
module Java::JavaUtil::List # rubocop:disable Style/ClassAndModuleChildren
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :to_a,
|
8
|
+
:&,
|
9
|
+
:*,
|
10
|
+
:|,
|
11
|
+
:bsearch_index,
|
12
|
+
:difference,
|
13
|
+
:flatten,
|
14
|
+
:intersection,
|
15
|
+
:pack,
|
16
|
+
:product,
|
17
|
+
:repeated_combination,
|
18
|
+
:repeated_permutation,
|
19
|
+
:reverse,
|
20
|
+
:rotate,
|
21
|
+
:sample,
|
22
|
+
:shelljoin,
|
23
|
+
:shuffle,
|
24
|
+
:transpose,
|
25
|
+
:union
|
26
|
+
|
27
|
+
def assoc(obj)
|
28
|
+
find { |v| (v.is_a?(Array) || v.is_a?(self.class)) && v[0] == obj }
|
29
|
+
end
|
30
|
+
|
31
|
+
def at(index)
|
32
|
+
self[index]
|
33
|
+
end
|
34
|
+
|
35
|
+
def bsearch(&block)
|
36
|
+
raise NotImplementedError unless block
|
37
|
+
|
38
|
+
r = bsearch_index(&block)
|
39
|
+
self[r] if r
|
40
|
+
end
|
41
|
+
|
42
|
+
def combination(n, &block) # rubocop:disable Naming/MethodParameterName
|
43
|
+
r = to_a.combination(n, &block)
|
44
|
+
block ? self : r
|
45
|
+
end
|
46
|
+
|
47
|
+
def compact
|
48
|
+
reject(&:nil?)
|
49
|
+
end
|
50
|
+
|
51
|
+
def compact!
|
52
|
+
reject!(&:nil?)
|
53
|
+
end
|
54
|
+
|
55
|
+
def concat(*other_arrays)
|
56
|
+
other_arrays.each { |array| add_all(array) }
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def deconstruct
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def delete(obj)
|
65
|
+
last = nil
|
66
|
+
found = false
|
67
|
+
loop do
|
68
|
+
i = index(obj)
|
69
|
+
break if i.nil?
|
70
|
+
|
71
|
+
found = true
|
72
|
+
last = remove(i)
|
73
|
+
end
|
74
|
+
|
75
|
+
return yield(obj) if !found && block_given?
|
76
|
+
|
77
|
+
last
|
78
|
+
end
|
79
|
+
|
80
|
+
def delete_at(index)
|
81
|
+
index = length + index if index.negative?
|
82
|
+
return if index.negative? || index >= length
|
83
|
+
|
84
|
+
remove(index)
|
85
|
+
end
|
86
|
+
|
87
|
+
def delete_if
|
88
|
+
raise NotImplementedError unless block_given?
|
89
|
+
|
90
|
+
it = list_iterator
|
91
|
+
while it.has_next? # rubocop:disable Style/WhileUntilModifier
|
92
|
+
it.remove if yield(it.next)
|
93
|
+
end
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
def dig(index, *identifiers)
|
98
|
+
return self[index] if identifiers.empty?
|
99
|
+
|
100
|
+
self[index]&.dig(*identifiers)
|
101
|
+
end
|
102
|
+
|
103
|
+
def each_index(&block)
|
104
|
+
r = (0...length)
|
105
|
+
return r.each unless block
|
106
|
+
|
107
|
+
r.each(&block)
|
108
|
+
self
|
109
|
+
end
|
110
|
+
|
111
|
+
def fetch(index, *default_value)
|
112
|
+
if default_value.length > 1
|
113
|
+
raise ArgumentError,
|
114
|
+
"wrong number of arguments calling `fetch` (given #{default_value.length - 1}, expected 1..2)"
|
115
|
+
end
|
116
|
+
|
117
|
+
original_index = index
|
118
|
+
index = length + index if index.negative?
|
119
|
+
return self[index] if index >= 0 && index < length
|
120
|
+
|
121
|
+
return default_value.first unless default_value.empty?
|
122
|
+
return yield(original_index) if block_given?
|
123
|
+
|
124
|
+
raise IndexError, "index #{index} out of list"
|
125
|
+
end
|
126
|
+
|
127
|
+
def fill(*args)
|
128
|
+
if block_given?
|
129
|
+
unless (0..2).cover?(args.length)
|
130
|
+
raise ArgumentError,
|
131
|
+
"wrong number of arguments calling `fill` (given #{args.length}, expected 1..3)"
|
132
|
+
end
|
133
|
+
else
|
134
|
+
unless (1..3).cover?(args.length)
|
135
|
+
raise ArgumentError,
|
136
|
+
"wrong number of arguments calling `fill` (given #{args.length}, expected 1..2)"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
obj = args.shift unless block_given?
|
141
|
+
|
142
|
+
if args.length == 1 && args.first.is_a?(Range)
|
143
|
+
range = args.first
|
144
|
+
|
145
|
+
range = Range.new(length + range.begin, range.end, range.exclude_end?) if range.begin.negative?
|
146
|
+
range = Range.new(range.begin, length + range.end, range.exclude_end?) if range.end&.negative?
|
147
|
+
return self if range.begin.negative? || (range.end && range.end < range.begin)
|
148
|
+
else
|
149
|
+
first, count = *args
|
150
|
+
return self if count&.negative?
|
151
|
+
|
152
|
+
first ||= 0
|
153
|
+
|
154
|
+
first = length + first if first.negative?
|
155
|
+
range = count ? first...(first + count) : first..
|
156
|
+
end
|
157
|
+
|
158
|
+
add(nil) while length < range.begin && count
|
159
|
+
|
160
|
+
start = range.begin
|
161
|
+
start = 0 if start.negative?
|
162
|
+
start = length if start > length
|
163
|
+
it = list_iterator(start)
|
164
|
+
|
165
|
+
while range.cover?(it.next_index)
|
166
|
+
break if range.end.nil? && !it.has_next?
|
167
|
+
|
168
|
+
obj = yield(it.next_index) if block_given?
|
169
|
+
if it.has_next?
|
170
|
+
it.next
|
171
|
+
it.set(obj)
|
172
|
+
else
|
173
|
+
it.add(obj)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
self
|
178
|
+
end
|
179
|
+
|
180
|
+
def flatten!(*args)
|
181
|
+
if args.length > 1
|
182
|
+
raise ArgumentError,
|
183
|
+
"wrong number of arguments calling `flatten` (given #{args.length}, expect 0..1)"
|
184
|
+
end
|
185
|
+
|
186
|
+
it = list_iterator
|
187
|
+
|
188
|
+
args = [args.first - 1] unless args.empty?
|
189
|
+
done = args.first == 0 # rubocop:disable Style/NumericPredicate
|
190
|
+
|
191
|
+
changed = false
|
192
|
+
while it.has_next?
|
193
|
+
element = it.next
|
194
|
+
next unless element.respond_to?(:to_ary)
|
195
|
+
|
196
|
+
changed = true
|
197
|
+
it.remove
|
198
|
+
arr = element.to_ary
|
199
|
+
arr = arr.flatten(*args) unless done
|
200
|
+
arr.each do |e|
|
201
|
+
it.add(e)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
changed ? self : nil
|
205
|
+
end
|
206
|
+
|
207
|
+
def insert(index, *objects)
|
208
|
+
return self if objects.empty?
|
209
|
+
|
210
|
+
raise IndexError, "index #{index} too small for list, minimum: #{-length}" if index < -length
|
211
|
+
|
212
|
+
index = length + index + 1 if index.negative?
|
213
|
+
|
214
|
+
add(nil) while length < index
|
215
|
+
add_all(index, objects)
|
216
|
+
self
|
217
|
+
end
|
218
|
+
|
219
|
+
def intersect?(other_ary)
|
220
|
+
!(self & other_ary).empty?
|
221
|
+
end
|
222
|
+
|
223
|
+
def keep_if?
|
224
|
+
raise NotImplementedError unless block_given?
|
225
|
+
|
226
|
+
it = list_iterator
|
227
|
+
while it.has_next? # rubocop:disable Style/WhileUntilModifier
|
228
|
+
it.remove unless yield(it.next)
|
229
|
+
end
|
230
|
+
self
|
231
|
+
end
|
232
|
+
|
233
|
+
def map!(&block)
|
234
|
+
raise NotImplementedError unless block
|
235
|
+
|
236
|
+
replace_all(&block)
|
237
|
+
self
|
238
|
+
end
|
239
|
+
|
240
|
+
def permutation(n, &block) # rubocop:disable Naming/MethodParameterName
|
241
|
+
r = to_a.permutation(n, &block)
|
242
|
+
block ? self : r
|
243
|
+
end
|
244
|
+
|
245
|
+
def pop(*args)
|
246
|
+
if args.length > 1
|
247
|
+
raise ArgumentError,
|
248
|
+
"wrong number of arguments calling `pop` (given #{args.length}, expected 0..1)"
|
249
|
+
end
|
250
|
+
|
251
|
+
if args.empty?
|
252
|
+
return if empty?
|
253
|
+
|
254
|
+
return remove(length - 1)
|
255
|
+
end
|
256
|
+
|
257
|
+
count = args.first
|
258
|
+
start = [length - count, 0].max
|
259
|
+
result = self[start..-1].to_a # rubocop:disable Style/SlicingWithRange
|
260
|
+
it = list_iterator(start)
|
261
|
+
while it.has_next?
|
262
|
+
it.next
|
263
|
+
it.remove
|
264
|
+
end
|
265
|
+
result
|
266
|
+
end
|
267
|
+
|
268
|
+
def push(*objects)
|
269
|
+
add_all(objects)
|
270
|
+
self
|
271
|
+
end
|
272
|
+
alias_method :append, :push
|
273
|
+
|
274
|
+
def rassoc(obj)
|
275
|
+
find { |v| (v.is_a?(Array) || v.is_a?(self.class)) && v[1] == obj }
|
276
|
+
end
|
277
|
+
|
278
|
+
def reject!
|
279
|
+
raise NotImplementedError unless block_given?
|
280
|
+
|
281
|
+
it = list_iterator
|
282
|
+
changed = false
|
283
|
+
while it.has_next
|
284
|
+
if yield(it.next)
|
285
|
+
changed = true
|
286
|
+
it.remove
|
287
|
+
end
|
288
|
+
end
|
289
|
+
self if changed
|
290
|
+
end
|
291
|
+
|
292
|
+
def repeated_combination(n, &block) # rubocop:disable Naming/MethodParameterName
|
293
|
+
r = to_a.repeated_combination(n, &block)
|
294
|
+
block ? self : r
|
295
|
+
end
|
296
|
+
|
297
|
+
def repeated_permutation(n, &block) # rubocop:disable Naming/MethodParameterName
|
298
|
+
r = to_a.repeated_permutation(n, &block)
|
299
|
+
block ? self : r
|
300
|
+
end
|
301
|
+
|
302
|
+
def replace(other_array)
|
303
|
+
clear
|
304
|
+
add_all(other_array)
|
305
|
+
self
|
306
|
+
end
|
307
|
+
|
308
|
+
def reverse!
|
309
|
+
replace(reverse)
|
310
|
+
self
|
311
|
+
end
|
312
|
+
|
313
|
+
def rotate!(count = 1)
|
314
|
+
count = count % length
|
315
|
+
push(*shift(count))
|
316
|
+
self
|
317
|
+
end
|
318
|
+
|
319
|
+
def select!
|
320
|
+
raise NotImplementedError unless block_given?
|
321
|
+
|
322
|
+
it = list_iterator
|
323
|
+
changed = false
|
324
|
+
while it.has_next?
|
325
|
+
unless yield(it.next)
|
326
|
+
changed = true
|
327
|
+
it.remove
|
328
|
+
end
|
329
|
+
end
|
330
|
+
self if changed
|
331
|
+
end
|
332
|
+
|
333
|
+
def shift(*args)
|
334
|
+
if args.length > 1
|
335
|
+
raise ArgumentError,
|
336
|
+
"wrong number of arguments calling `shift` (given #{args.length}, expected 0..1)"
|
337
|
+
end
|
338
|
+
|
339
|
+
if args.empty?
|
340
|
+
return if empty?
|
341
|
+
|
342
|
+
return remove(0)
|
343
|
+
end
|
344
|
+
|
345
|
+
count = args.first
|
346
|
+
result = self[0...count].to_a
|
347
|
+
it = list_iterator
|
348
|
+
count.times do
|
349
|
+
break unless it.has_next?
|
350
|
+
|
351
|
+
it.next
|
352
|
+
it.remove
|
353
|
+
end
|
354
|
+
result
|
355
|
+
end
|
356
|
+
|
357
|
+
def shuffle!(*args)
|
358
|
+
replace(shuffle(*args))
|
359
|
+
end
|
360
|
+
|
361
|
+
def slice(*args)
|
362
|
+
self[*args]
|
363
|
+
end
|
364
|
+
|
365
|
+
def slice!(*args)
|
366
|
+
unless (1..2).cover?(args.length)
|
367
|
+
raise ArgumentError,
|
368
|
+
"wrong number of arguments calling `slice!` (given #{args.length}, expected 1..2)"
|
369
|
+
end
|
370
|
+
|
371
|
+
return delete_at(args.first) if args.length == 1 && !args.first.is_a?(Range)
|
372
|
+
|
373
|
+
start = args.first
|
374
|
+
start = start.begin if start.is_a?(Range)
|
375
|
+
start = length + start if start.negative?
|
376
|
+
return nil if start.negative? || start >= length
|
377
|
+
|
378
|
+
result = slice(*args).to_a
|
379
|
+
|
380
|
+
it = list_iterator(start)
|
381
|
+
result.length.times do
|
382
|
+
it.next
|
383
|
+
it.remove
|
384
|
+
end
|
385
|
+
result
|
386
|
+
end
|
387
|
+
|
388
|
+
def sort_by!
|
389
|
+
raise NotImplementedError unless block_given?
|
390
|
+
|
391
|
+
sort { |a, b| (yield a) <=> (yield b) }
|
392
|
+
self
|
393
|
+
end
|
394
|
+
|
395
|
+
def uniq!
|
396
|
+
seen = Set.new
|
397
|
+
|
398
|
+
it = list_iterator
|
399
|
+
changed = false
|
400
|
+
while it.has_next?
|
401
|
+
n = it.next
|
402
|
+
n = yield(n) if block_given?
|
403
|
+
if seen.include?(n)
|
404
|
+
changed = true
|
405
|
+
it.remove
|
406
|
+
end
|
407
|
+
seen << n
|
408
|
+
end
|
409
|
+
self if changed
|
410
|
+
end
|
411
|
+
|
412
|
+
def unshift(*objects)
|
413
|
+
add_all(0, objects)
|
414
|
+
self
|
415
|
+
end
|
416
|
+
alias_method :prepend, :unshift
|
417
|
+
|
418
|
+
def values_at(*indexes)
|
419
|
+
result = []
|
420
|
+
indexes.each do |index|
|
421
|
+
if index.is_a?(Range)
|
422
|
+
partial_result = self[index]
|
423
|
+
result.concat(partial_result)
|
424
|
+
result.fill(nil, result.length, index.count - partial_result.length)
|
425
|
+
else
|
426
|
+
index = length + index if index.negative?
|
427
|
+
result << if index.negative? || index >= length
|
428
|
+
nil
|
429
|
+
else
|
430
|
+
self[index]
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
result
|
435
|
+
end
|
436
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
module Java::JavaUtil::Map # rubocop:disable Style/ClassAndModuleChildren
|
5
|
+
def compact
|
6
|
+
reject { |_k, v| v.nil? }
|
7
|
+
end
|
8
|
+
|
9
|
+
def compact!
|
10
|
+
reject! { |_k, v| v.nil? }
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def deconstruct_keys
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def except(*keys)
|
19
|
+
reject { |k, _v| keys.include?(k) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def slice(*keys)
|
23
|
+
select { |k, _v| keys.include?(k) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def transform_keys(hash2 = nil)
|
27
|
+
raise NotImplementedError unless hash2 || block_given?
|
28
|
+
|
29
|
+
map do |k, v| # rubocop:disable Style/MapToHash
|
30
|
+
if hash2&.key?(k)
|
31
|
+
[hash2[k], v]
|
32
|
+
elsif block_given?
|
33
|
+
[(yield k), v]
|
34
|
+
else
|
35
|
+
[k, v]
|
36
|
+
end
|
37
|
+
end.to_h
|
38
|
+
end
|
39
|
+
|
40
|
+
def transform_keys!(hash2 = nil)
|
41
|
+
raise NotImplementedError unless hash2 || block_given?
|
42
|
+
|
43
|
+
keys.each do |k|
|
44
|
+
if hash2&.key?(k)
|
45
|
+
self[hash2[k]] = delete(k)
|
46
|
+
elsif block_given?
|
47
|
+
new_k = yield k
|
48
|
+
self[new_k] = delete(k) unless new_k == k
|
49
|
+
end
|
50
|
+
end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def transform_values
|
55
|
+
map do |k, v| # rubocop:disable Style/MapToHash, Style/HashTransformValues
|
56
|
+
[k, (yield v)]
|
57
|
+
end.to_h
|
58
|
+
end
|
59
|
+
|
60
|
+
def transform_values!
|
61
|
+
replace_all do |_k, v|
|
62
|
+
yield v
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
end
|
@@ -25,8 +25,7 @@ module OpenHAB
|
|
25
25
|
# @return [ZonedDateTime] If other is a TemporalAmount
|
26
26
|
def -(other)
|
27
27
|
if other.respond_to?(:to_zoned_date_time)
|
28
|
-
|
29
|
-
(nanos.to_f / 1_000_000_000).seconds
|
28
|
+
java.time.Duration.between(other.to_zoned_date_time, self)
|
30
29
|
elsif other.is_a?(Numeric)
|
31
30
|
minus(other.seconds)
|
32
31
|
else
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
require "forwardable"
|
5
|
+
|
6
|
+
# DateTime inherits from Date, but is more similar to Time semantically.
|
7
|
+
# So it avoid alias_method chain bombs, and to ensure the correct end methods
|
8
|
+
# exist here, we define the important methods from Time here as well.
|
9
|
+
|
10
|
+
# Extensions to DateTime
|
11
|
+
class DateTime < Date
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
# (see Time#plus_with_temporal)
|
15
|
+
def plus_with_temporal(other)
|
16
|
+
return to_zoned_date_time + other if other.is_a?(java.time.temporal.TemporalAmount)
|
17
|
+
|
18
|
+
plus_without_temporal(other)
|
19
|
+
end
|
20
|
+
# alias_method :plus_without_temporal, :+ # already done by Date
|
21
|
+
alias_method :+, :plus_with_temporal
|
22
|
+
|
23
|
+
# (see Time#minus_with_temporal)
|
24
|
+
def minus_with_temporal(other)
|
25
|
+
return to_zoned_date_time - other if other.is_a?(java.time.temporal.TemporalAmount)
|
26
|
+
|
27
|
+
# Exclude subtracting against the same class
|
28
|
+
if other.respond_to?(:to_zoned_date_time) && !other.is_a?(self.class)
|
29
|
+
return to_zoned_date_time - other.to_zoned_date_time
|
30
|
+
end
|
31
|
+
|
32
|
+
minus_without_temporal(other)
|
33
|
+
end
|
34
|
+
# alias_method :minus_without_temporal, :- # already done by Date
|
35
|
+
alias_method :-, :minus_with_temporal
|
36
|
+
|
37
|
+
# @!method to_local_time
|
38
|
+
# @return [LocalTime]
|
39
|
+
def_delegator :to_zoned_date_time, :to_local_time
|
40
|
+
|
41
|
+
# (see Time#to_zoned_date_time)
|
42
|
+
def to_zoned_date_time(context = nil) # rubocop:disable Lint/UnusedMethodArgument
|
43
|
+
to_java(ZonedDateTime)
|
44
|
+
end
|
45
|
+
|
46
|
+
# (see Time#coerce)
|
47
|
+
def coerce(other)
|
48
|
+
return unless other.respond_to?(:to_zoned_date_time)
|
49
|
+
|
50
|
+
zdt = to_zoned_date_time
|
51
|
+
[other.to_zoned_date_time(zdt), zdt]
|
52
|
+
end
|
53
|
+
end
|