relationalai 1.0.0a3__py3-none-any.whl → 1.0.0a5__py3-none-any.whl
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.
- relationalai/config/config.py +47 -21
- relationalai/config/connections/__init__.py +5 -2
- relationalai/config/connections/duckdb.py +2 -2
- relationalai/config/connections/local.py +31 -0
- relationalai/config/connections/snowflake.py +0 -1
- relationalai/config/external/raiconfig_converter.py +235 -0
- relationalai/config/external/raiconfig_models.py +202 -0
- relationalai/config/external/utils.py +31 -0
- relationalai/config/shims.py +1 -0
- relationalai/semantics/__init__.py +10 -8
- relationalai/semantics/backends/sql/sql_compiler.py +1 -4
- relationalai/semantics/experimental/__init__.py +0 -0
- relationalai/semantics/experimental/builder.py +295 -0
- relationalai/semantics/experimental/builtins.py +154 -0
- relationalai/semantics/frontend/base.py +67 -42
- relationalai/semantics/frontend/core.py +34 -6
- relationalai/semantics/frontend/front_compiler.py +209 -37
- relationalai/semantics/frontend/pprint.py +6 -2
- relationalai/semantics/metamodel/__init__.py +7 -0
- relationalai/semantics/metamodel/metamodel.py +2 -0
- relationalai/semantics/metamodel/metamodel_analyzer.py +58 -16
- relationalai/semantics/metamodel/pprint.py +6 -1
- relationalai/semantics/metamodel/rewriter.py +11 -7
- relationalai/semantics/metamodel/typer.py +116 -41
- relationalai/semantics/reasoners/__init__.py +11 -0
- relationalai/semantics/reasoners/graph/__init__.py +35 -0
- relationalai/semantics/reasoners/graph/core.py +9028 -0
- relationalai/semantics/std/__init__.py +30 -10
- relationalai/semantics/std/aggregates.py +641 -12
- relationalai/semantics/std/common.py +146 -13
- relationalai/semantics/std/constraints.py +71 -1
- relationalai/semantics/std/datetime.py +904 -21
- relationalai/semantics/std/decimals.py +143 -2
- relationalai/semantics/std/floats.py +57 -4
- relationalai/semantics/std/integers.py +98 -4
- relationalai/semantics/std/math.py +857 -35
- relationalai/semantics/std/numbers.py +216 -20
- relationalai/semantics/std/re.py +213 -5
- relationalai/semantics/std/strings.py +437 -44
- relationalai/shims/executor.py +60 -52
- relationalai/shims/fixtures.py +85 -0
- relationalai/shims/helpers.py +26 -2
- relationalai/shims/hoister.py +28 -9
- relationalai/shims/mm2v0.py +204 -173
- relationalai/tools/cli/cli.py +192 -10
- relationalai/tools/cli/components/progress_reader.py +1 -1
- relationalai/tools/cli/docs.py +394 -0
- relationalai/tools/debugger.py +11 -4
- relationalai/tools/qb_debugger.py +435 -0
- relationalai/tools/typer_debugger.py +1 -2
- relationalai/util/dataclasses.py +3 -5
- relationalai/util/docutils.py +1 -2
- relationalai/util/error.py +2 -5
- relationalai/util/python.py +23 -0
- relationalai/util/runtime.py +1 -2
- relationalai/util/schema.py +2 -4
- relationalai/util/structures.py +4 -2
- relationalai/util/tracing.py +8 -2
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/METADATA +8 -5
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/RECORD +118 -95
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/WHEEL +1 -1
- v0/relationalai/__init__.py +1 -1
- v0/relationalai/clients/client.py +52 -18
- v0/relationalai/clients/exec_txn_poller.py +122 -0
- v0/relationalai/clients/local.py +23 -8
- v0/relationalai/clients/resources/azure/azure.py +36 -11
- v0/relationalai/clients/resources/snowflake/__init__.py +4 -4
- v0/relationalai/clients/resources/snowflake/cli_resources.py +12 -1
- v0/relationalai/clients/resources/snowflake/direct_access_resources.py +124 -100
- v0/relationalai/clients/resources/snowflake/engine_service.py +381 -0
- v0/relationalai/clients/resources/snowflake/engine_state_handlers.py +35 -29
- v0/relationalai/clients/resources/snowflake/error_handlers.py +43 -2
- v0/relationalai/clients/resources/snowflake/snowflake.py +277 -179
- v0/relationalai/clients/resources/snowflake/use_index_poller.py +8 -0
- v0/relationalai/clients/types.py +5 -0
- v0/relationalai/errors.py +19 -1
- v0/relationalai/semantics/lqp/algorithms.py +173 -0
- v0/relationalai/semantics/lqp/builtins.py +199 -2
- v0/relationalai/semantics/lqp/executor.py +68 -37
- v0/relationalai/semantics/lqp/ir.py +28 -2
- v0/relationalai/semantics/lqp/model2lqp.py +215 -45
- v0/relationalai/semantics/lqp/passes.py +13 -658
- v0/relationalai/semantics/lqp/rewrite/__init__.py +12 -0
- v0/relationalai/semantics/lqp/rewrite/algorithm.py +385 -0
- v0/relationalai/semantics/lqp/rewrite/constants_to_vars.py +70 -0
- v0/relationalai/semantics/lqp/rewrite/deduplicate_vars.py +104 -0
- v0/relationalai/semantics/lqp/rewrite/eliminate_data.py +108 -0
- v0/relationalai/semantics/lqp/rewrite/extract_keys.py +25 -3
- v0/relationalai/semantics/lqp/rewrite/period_math.py +77 -0
- v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +65 -31
- v0/relationalai/semantics/lqp/rewrite/unify_definitions.py +317 -0
- v0/relationalai/semantics/lqp/utils.py +11 -1
- v0/relationalai/semantics/lqp/validators.py +14 -1
- v0/relationalai/semantics/metamodel/builtins.py +2 -1
- v0/relationalai/semantics/metamodel/compiler.py +2 -1
- v0/relationalai/semantics/metamodel/dependency.py +12 -3
- v0/relationalai/semantics/metamodel/executor.py +11 -1
- v0/relationalai/semantics/metamodel/factory.py +2 -2
- v0/relationalai/semantics/metamodel/helpers.py +7 -0
- v0/relationalai/semantics/metamodel/ir.py +3 -2
- v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +30 -20
- v0/relationalai/semantics/metamodel/rewrite/flatten.py +50 -13
- v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +9 -3
- v0/relationalai/semantics/metamodel/typer/checker.py +6 -4
- v0/relationalai/semantics/metamodel/typer/typer.py +4 -3
- v0/relationalai/semantics/metamodel/visitor.py +4 -3
- v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +1 -1
- v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +336 -86
- v0/relationalai/semantics/rel/compiler.py +2 -1
- v0/relationalai/semantics/rel/executor.py +3 -2
- v0/relationalai/semantics/tests/lqp/__init__.py +0 -0
- v0/relationalai/semantics/tests/lqp/algorithms.py +345 -0
- v0/relationalai/tools/cli.py +339 -186
- v0/relationalai/tools/cli_controls.py +216 -67
- v0/relationalai/tools/cli_helpers.py +410 -6
- v0/relationalai/util/format.py +5 -2
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/entry_points.txt +0 -0
- {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/top_level.txt +0 -0
|
@@ -1,16 +1,30 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Date and time manipulation functions.
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive date and datetime operations including:
|
|
5
|
+
- Date construction, parsing, and formatting
|
|
6
|
+
- DateTime construction, parsing, and formatting
|
|
7
|
+
- Date and time component extraction (year, month, day, hour, minute, second)
|
|
8
|
+
- Date and time arithmetic (add, subtract)
|
|
9
|
+
- Date and time ranges
|
|
10
|
+
- Time period constructors (days, hours, minutes, seconds, etc.)
|
|
11
|
+
- ISO format constants for standardized formatting
|
|
12
|
+
"""
|
|
1
13
|
from __future__ import annotations
|
|
2
14
|
|
|
3
|
-
from relationalai.semantics.std import floats
|
|
4
15
|
|
|
5
16
|
from . import StringValue, IntegerValue, DateValue, DateTimeValue, math, common
|
|
6
|
-
from ..frontend.base import
|
|
17
|
+
from ..frontend.base import Library, MetaRef, Expression, Field, Variable
|
|
7
18
|
from ..frontend.core import Float, Number, String, Integer, Date, DateTime
|
|
8
19
|
from ..frontend import core
|
|
9
20
|
from .. import select
|
|
21
|
+
from relationalai.util.docutils import include_in_docs
|
|
10
22
|
|
|
11
|
-
from typing import Union, Literal
|
|
23
|
+
from typing import Union, Literal as LiteralType
|
|
12
24
|
import datetime as dt
|
|
13
25
|
|
|
26
|
+
__include_in_docs__ = True
|
|
27
|
+
|
|
14
28
|
# the front-end library object
|
|
15
29
|
library = Library("datetime")
|
|
16
30
|
|
|
@@ -19,7 +33,32 @@ library = Library("datetime")
|
|
|
19
33
|
# Format String Constants
|
|
20
34
|
#--------------------------------------------------
|
|
21
35
|
|
|
36
|
+
@include_in_docs
|
|
22
37
|
class ISO:
|
|
38
|
+
"""
|
|
39
|
+
ISO format string constants for date and datetime formatting.
|
|
40
|
+
|
|
41
|
+
Attributes
|
|
42
|
+
----------
|
|
43
|
+
DATE : str
|
|
44
|
+
Date format: "yyyy-mm-dd"
|
|
45
|
+
HOURS : str
|
|
46
|
+
Datetime with hours: "yyyy-mm-ddTHH"
|
|
47
|
+
HOURS_TZ : str
|
|
48
|
+
Datetime with hours and timezone: "yyyy-mm-ddTHHz"
|
|
49
|
+
MINUTES : str
|
|
50
|
+
Datetime with minutes: "yyyy-mm-ddTHH:MM"
|
|
51
|
+
MINUTES_TZ : str
|
|
52
|
+
Datetime with minutes and timezone: "yyyy-mm-ddTHH:MMz"
|
|
53
|
+
SECONDS : str
|
|
54
|
+
Datetime with seconds: "yyyy-mm-ddTHH:MM:SS"
|
|
55
|
+
SECONDS_TZ : str
|
|
56
|
+
Datetime with seconds and timezone: "yyyy-mm-ddTHH:MM:SSz"
|
|
57
|
+
MILLIS : str
|
|
58
|
+
Datetime with milliseconds: "yyyy-mm-ddTHH:MM:SS.s"
|
|
59
|
+
MILLIS_TZ : str
|
|
60
|
+
Datetime with milliseconds and timezone: "yyyy-mm-ddTHH:MM:SS.sz"
|
|
61
|
+
"""
|
|
23
62
|
DATE = "yyyy-mm-dd"
|
|
24
63
|
HOURS = "yyyy-mm-ddTHH"
|
|
25
64
|
HOURS_TZ = "yyyy-mm-ddTHHz"
|
|
@@ -70,86 +109,349 @@ _date_subtract = library.Relation("date_subtract", [Field.input("date", Date), F
|
|
|
70
109
|
# _date_range_from_start = library.Relation("date_range_from_start", [Field.input("start", Date), Field.input("periods", Integer), Field.input("frequency", String), Field("date", Date)])
|
|
71
110
|
# _date_range_from_end = library.Relation("date_range_from_end", [Field.input("end", Date), Field.input("periods", Integer), Field.input("frequency", String), Field("date", Date)])
|
|
72
111
|
|
|
112
|
+
@include_in_docs
|
|
73
113
|
class date:
|
|
114
|
+
"""
|
|
115
|
+
Construct a date from year, month, and day.
|
|
116
|
+
|
|
117
|
+
When you construct a date using this class, it returns an `Expression` and not a `date`
|
|
118
|
+
object. All of the methods on this class are class methods that operate on date
|
|
119
|
+
expressions.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
year: IntegerValue
|
|
124
|
+
The year.
|
|
125
|
+
month: IntegerValue
|
|
126
|
+
The month (1-12).
|
|
127
|
+
day: IntegerValue
|
|
128
|
+
The day of the month.
|
|
129
|
+
|
|
130
|
+
Examples
|
|
131
|
+
--------
|
|
132
|
+
Construct dates:
|
|
133
|
+
|
|
134
|
+
>>> datetime.date(2024, 1, 15)
|
|
135
|
+
>>> datetime.date(Employee.hire_year, Employee.hire_month, Employee.hire_day)
|
|
136
|
+
"""
|
|
137
|
+
|
|
74
138
|
def __new__(cls, year: IntegerValue, month: IntegerValue, day: IntegerValue) -> Expression:
|
|
75
139
|
return _construct_date(year, month, day)
|
|
76
140
|
|
|
141
|
+
def __init__(self, year: IntegerValue, month: IntegerValue, day: IntegerValue):
|
|
142
|
+
pass
|
|
143
|
+
|
|
77
144
|
@classmethod
|
|
145
|
+
@include_in_docs
|
|
78
146
|
def year(cls, date: DateValue) -> Expression:
|
|
147
|
+
"""
|
|
148
|
+
Extract the year from a date.
|
|
149
|
+
|
|
150
|
+
Parameters
|
|
151
|
+
----------
|
|
152
|
+
date: DateValue
|
|
153
|
+
The date to extract from.
|
|
154
|
+
|
|
155
|
+
Returns
|
|
156
|
+
-------
|
|
157
|
+
Expression
|
|
158
|
+
An `Expression` computing the year. Returns `Integer`.
|
|
159
|
+
|
|
160
|
+
Examples
|
|
161
|
+
--------
|
|
162
|
+
Extract year from dates:
|
|
163
|
+
|
|
164
|
+
>>> datetime.date.year(Event.start_date)
|
|
165
|
+
>>> select(Person.name).where(datetime.date.year(Person.birth_date) == 2000)
|
|
166
|
+
"""
|
|
79
167
|
return _date_year(date)
|
|
80
168
|
|
|
81
169
|
@classmethod
|
|
170
|
+
@include_in_docs
|
|
82
171
|
def quarter(cls, date: DateValue) -> Expression:
|
|
172
|
+
"""
|
|
173
|
+
Extract the quarter (1-4) from a date.
|
|
174
|
+
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
date: DateValue
|
|
178
|
+
The date to extract from.
|
|
179
|
+
|
|
180
|
+
Returns
|
|
181
|
+
-------
|
|
182
|
+
Expression
|
|
183
|
+
An `Expression` computing the quarter. Returns `Integer`.
|
|
184
|
+
"""
|
|
83
185
|
return _date_quarter(date)
|
|
84
186
|
|
|
85
187
|
@classmethod
|
|
188
|
+
@include_in_docs
|
|
86
189
|
def month(cls, date: DateValue) -> Expression:
|
|
190
|
+
"""
|
|
191
|
+
Extract the month (1-12) from a date.
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
----------
|
|
195
|
+
date: DateValue
|
|
196
|
+
The date to extract from.
|
|
197
|
+
|
|
198
|
+
Returns
|
|
199
|
+
-------
|
|
200
|
+
Expression
|
|
201
|
+
An `Expression` computing the month. Returns `Integer`.
|
|
202
|
+
"""
|
|
87
203
|
return _date_month(date)
|
|
88
204
|
|
|
89
205
|
@classmethod
|
|
206
|
+
@include_in_docs
|
|
90
207
|
def week(cls, date: DateValue) -> Expression:
|
|
208
|
+
"""
|
|
209
|
+
Extract the ISO week number from a date.
|
|
210
|
+
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
date: DateValue
|
|
214
|
+
The date to extract from.
|
|
215
|
+
|
|
216
|
+
Returns
|
|
217
|
+
-------
|
|
218
|
+
Expression
|
|
219
|
+
An `Expression` computing the week number. Returns `Integer`.
|
|
220
|
+
"""
|
|
91
221
|
return _date_week(date)
|
|
92
222
|
|
|
93
223
|
@classmethod
|
|
224
|
+
@include_in_docs
|
|
94
225
|
def day(cls, date: DateValue) -> Expression:
|
|
226
|
+
"""
|
|
227
|
+
Extract the day of the month from a date.
|
|
228
|
+
|
|
229
|
+
Parameters
|
|
230
|
+
----------
|
|
231
|
+
date: DateValue
|
|
232
|
+
The date to extract from.
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
Expression
|
|
237
|
+
An `Expression` computing the day. Returns `Integer`.
|
|
238
|
+
"""
|
|
95
239
|
return _date_day(date)
|
|
96
240
|
|
|
97
241
|
@classmethod
|
|
242
|
+
@include_in_docs
|
|
98
243
|
def dayofyear(cls, date: DateValue) -> Expression:
|
|
244
|
+
"""
|
|
245
|
+
Extract the day of the year (1-366) from a date.
|
|
246
|
+
|
|
247
|
+
Parameters
|
|
248
|
+
----------
|
|
249
|
+
date: DateValue
|
|
250
|
+
The date to extract from.
|
|
251
|
+
|
|
252
|
+
Returns
|
|
253
|
+
-------
|
|
254
|
+
Expression
|
|
255
|
+
An `Expression` computing the day of year. Returns `Integer`.
|
|
256
|
+
"""
|
|
99
257
|
return _date_dayofyear(date)
|
|
100
258
|
|
|
101
259
|
@classmethod
|
|
260
|
+
@include_in_docs
|
|
102
261
|
def isoweekday(cls, date: DateValue) -> Expression:
|
|
103
262
|
"""
|
|
104
263
|
Return the ISO weekday as an integer, where Monday is 1, and Sunday is 7.
|
|
264
|
+
|
|
265
|
+
Parameters
|
|
266
|
+
----------
|
|
267
|
+
date: DateValue
|
|
268
|
+
The date to extract from.
|
|
269
|
+
|
|
270
|
+
Returns
|
|
271
|
+
-------
|
|
272
|
+
Expression
|
|
273
|
+
An `Expression` computing the ISO weekday (1=Monday...7=Sunday). Returns `Integer`.
|
|
105
274
|
"""
|
|
106
275
|
return _date_weekday(date)
|
|
107
276
|
|
|
108
277
|
@classmethod
|
|
278
|
+
@include_in_docs
|
|
109
279
|
def weekday(cls, date: DateValue) -> Expression:
|
|
280
|
+
"""
|
|
281
|
+
Return the weekday as an integer, where Monday is 0, and Sunday is 6.
|
|
282
|
+
|
|
283
|
+
Parameters
|
|
284
|
+
----------
|
|
285
|
+
date: DateValue
|
|
286
|
+
The date to extract from.
|
|
287
|
+
|
|
288
|
+
Returns
|
|
289
|
+
-------
|
|
290
|
+
Expression
|
|
291
|
+
An `Expression` computing the weekday (0=Monday...6=Sunday). Returns `Integer`.
|
|
292
|
+
"""
|
|
110
293
|
return cls.isoweekday(date) - 1 # Convert ISO weekday (1=Mon..7=Sun) to weekday (0=Mon..6=Sun)
|
|
111
294
|
|
|
112
295
|
@classmethod
|
|
296
|
+
@include_in_docs
|
|
113
297
|
def fromordinal(cls, ordinal: IntegerValue) -> Expression:
|
|
298
|
+
"""
|
|
299
|
+
Construct a date from a proleptic Gregorian ordinal.
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
ordinal: IntegerValue
|
|
304
|
+
The ordinal (day 1 is 0001-01-01).
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
Expression
|
|
309
|
+
An `Expression` computing the date. Returns `Date`.
|
|
310
|
+
"""
|
|
114
311
|
# ordinal 1 = '0001-01-01'. Minus 1 day since we can't declare date 0000-00-00
|
|
115
312
|
return cls.add(Date(dt.date(1, 1, 1)), days(ordinal - 1))
|
|
116
313
|
|
|
117
314
|
@classmethod
|
|
315
|
+
@include_in_docs
|
|
118
316
|
def to_datetime(cls, date: DateValue, hour: int = 0, minute: int = 0, second: int = 0, millisecond: int = 0, tz: str = "UTC") -> Expression:
|
|
317
|
+
"""
|
|
318
|
+
Convert a date to a datetime with specified time components.
|
|
319
|
+
|
|
320
|
+
Parameters
|
|
321
|
+
----------
|
|
322
|
+
date: DateValue
|
|
323
|
+
The date to convert.
|
|
324
|
+
hour: int
|
|
325
|
+
The hour (0-23). Default: 0.
|
|
326
|
+
minute: int
|
|
327
|
+
The minute (0-59). Default: 0.
|
|
328
|
+
second: int
|
|
329
|
+
The second (0-59). Default: 0.
|
|
330
|
+
millisecond: int
|
|
331
|
+
The millisecond (0-999). Default: 0.
|
|
332
|
+
tz: str
|
|
333
|
+
The timezone string. Default: "UTC".
|
|
334
|
+
|
|
335
|
+
Returns
|
|
336
|
+
-------
|
|
337
|
+
Expression
|
|
338
|
+
An `Expression` computing the datetime. Returns `DateTime`.
|
|
339
|
+
"""
|
|
119
340
|
_year = cls.year(date)
|
|
120
341
|
_month = cls.month(date)
|
|
121
342
|
_day = cls.day(date)
|
|
122
343
|
return _construct_datetime_ms_tz(_year, _month, _day, hour, minute, second, millisecond, tz)
|
|
123
344
|
|
|
124
345
|
@classmethod
|
|
346
|
+
@include_in_docs
|
|
125
347
|
def format(cls, date: DateValue, format: StringValue) -> Expression:
|
|
348
|
+
"""
|
|
349
|
+
Format a date as a string.
|
|
350
|
+
|
|
351
|
+
Parameters
|
|
352
|
+
----------
|
|
353
|
+
date: DateValue
|
|
354
|
+
The date to format.
|
|
355
|
+
format: StringValue
|
|
356
|
+
The format string.
|
|
357
|
+
|
|
358
|
+
Returns
|
|
359
|
+
-------
|
|
360
|
+
Expression
|
|
361
|
+
An `Expression` computing the formatted date string. Returns `String`.
|
|
362
|
+
"""
|
|
126
363
|
return _date_format(date, format)
|
|
127
364
|
|
|
128
365
|
@classmethod
|
|
366
|
+
@include_in_docs
|
|
129
367
|
def add(cls, date: DateValue, period: Variable) -> Expression:
|
|
368
|
+
"""
|
|
369
|
+
Add a period to a date.
|
|
370
|
+
|
|
371
|
+
Parameters
|
|
372
|
+
----------
|
|
373
|
+
date: DateValue
|
|
374
|
+
The date to add to.
|
|
375
|
+
period: Variable
|
|
376
|
+
The period to add (use `days()`, `weeks()`, `months()`, `years()`).
|
|
377
|
+
|
|
378
|
+
Returns
|
|
379
|
+
-------
|
|
380
|
+
Expression
|
|
381
|
+
An `Expression` computing the resulting date. Returns `Date`. Returns `Date`.
|
|
382
|
+
|
|
383
|
+
Examples
|
|
384
|
+
--------
|
|
385
|
+
Add periods to dates:
|
|
386
|
+
|
|
387
|
+
>>> datetime.date.add(Order.order_date, datetime.days(7))
|
|
388
|
+
>>> datetime.date.add(Project.start_date, datetime.weeks(Contract.duration_weeks))
|
|
389
|
+
>>> datetime.date.add(Subscription.start_date, datetime.months(12))
|
|
390
|
+
"""
|
|
130
391
|
return _date_add(date, period)
|
|
131
392
|
|
|
132
393
|
@classmethod
|
|
394
|
+
@include_in_docs
|
|
133
395
|
def subtract(cls, date: DateValue, period: Variable) -> Expression:
|
|
396
|
+
"""
|
|
397
|
+
Subtract a period from a date.
|
|
398
|
+
|
|
399
|
+
Parameters
|
|
400
|
+
----------
|
|
401
|
+
date: DateValue
|
|
402
|
+
The date to subtract from.
|
|
403
|
+
period: Variable
|
|
404
|
+
The period to subtract (use `days()`, `weeks()`, `months()`, `years()`).
|
|
405
|
+
|
|
406
|
+
Returns
|
|
407
|
+
-------
|
|
408
|
+
Expression
|
|
409
|
+
An `Expression` computing the resulting date. Returns `Date`.
|
|
410
|
+
"""
|
|
134
411
|
return _date_subtract(date, period)
|
|
135
412
|
|
|
136
413
|
@classmethod
|
|
414
|
+
@include_in_docs
|
|
137
415
|
def range(cls, start: DateValue | None = None, end: DateValue | None = None, periods: IntegerValue = 1, freq: Frequency = "D") -> Variable:
|
|
416
|
+
"""
|
|
417
|
+
Generate a range of dates.
|
|
418
|
+
|
|
419
|
+
Parameters
|
|
420
|
+
----------
|
|
421
|
+
start: DateValue | None
|
|
422
|
+
The start date. If None, computes from end.
|
|
423
|
+
end: DateValue | None
|
|
424
|
+
The end date (inclusive). If None, uses periods.
|
|
425
|
+
periods: IntegerValue
|
|
426
|
+
Number of periods to generate. Default: 1.
|
|
427
|
+
freq: Frequency
|
|
428
|
+
Frequency: "D" (day), "W" (week), "M" (month), "Y" (year). Default: "D".
|
|
429
|
+
|
|
430
|
+
Returns
|
|
431
|
+
-------
|
|
432
|
+
Variable
|
|
433
|
+
A `Variable` representing the date range. Returns `Date`.
|
|
434
|
+
|
|
435
|
+
Raises
|
|
436
|
+
------
|
|
437
|
+
ValueError
|
|
438
|
+
If neither start nor end is provided, or if freq is invalid.
|
|
439
|
+
"""
|
|
138
440
|
if start is None and end is None:
|
|
139
441
|
raise ValueError("Invalid start/end date for date.range. Must provide at least start date or end date")
|
|
140
442
|
if freq not in _days.keys():
|
|
141
443
|
raise ValueError(f"Frequency '{freq}' is not allowed for date_range. List of allowed frequencies: {list(_days.keys())}")
|
|
142
|
-
"""
|
|
143
|
-
Note on date_ranges and datetime_range: The way the computation works is that it first overapproximates the
|
|
144
|
-
number of periods.
|
|
145
444
|
|
|
146
|
-
|
|
147
|
-
|
|
445
|
+
# Note on date_ranges and datetime_range: The way the computation works is that it first overapproximates the
|
|
446
|
+
# number of periods.
|
|
447
|
+
|
|
448
|
+
# For example, date_range(2025-02-01, 2025-03-01, freq='M') and date_range(2025-02-01, 2025-03-31, freq='M') will
|
|
449
|
+
# compute range_end to be ceil(28*1/(365/12))=1 and ceil(58*1/(365/12))=2.
|
|
450
|
+
|
|
451
|
+
# Then, the computation fetches range_end+1 items into _date, which is the right number in the first case but
|
|
452
|
+
# one too many in the second case. That's why a filter end >= _date (or variant of) is applied, to remove any
|
|
453
|
+
# extra item. The result is two items in both cases.
|
|
148
454
|
|
|
149
|
-
Then, the computation fetches range_end+1 items into _date, which is the right number in the first case but
|
|
150
|
-
one too many in the second case. That's why a filter end >= _date (or variant of) is applied, to remove any
|
|
151
|
-
extra item. The result is two items in both cases.
|
|
152
|
-
"""
|
|
153
455
|
# TODO - this transformation is currently LQP-focused. Eventually we will want to
|
|
154
456
|
# move it into the LQP stack and have something general here.
|
|
155
457
|
date_func = cls.add
|
|
@@ -179,11 +481,41 @@ class date:
|
|
|
179
481
|
|
|
180
482
|
|
|
181
483
|
@classmethod
|
|
484
|
+
@include_in_docs
|
|
182
485
|
def period_days(cls, start: DateValue, end: DateValue) -> Expression:
|
|
486
|
+
"""
|
|
487
|
+
Compute the number of days between two dates.
|
|
488
|
+
|
|
489
|
+
Parameters
|
|
490
|
+
----------
|
|
491
|
+
start: DateValue
|
|
492
|
+
The start date.
|
|
493
|
+
end: DateValue
|
|
494
|
+
The end date.
|
|
495
|
+
|
|
496
|
+
Returns
|
|
497
|
+
-------
|
|
498
|
+
Expression
|
|
499
|
+
An `Expression` computing the number of days. Returns `Integer`.
|
|
500
|
+
"""
|
|
183
501
|
return _dates_period_days(start, end)
|
|
184
502
|
|
|
185
503
|
@classmethod
|
|
504
|
+
@include_in_docs
|
|
186
505
|
def fromisoformat(cls, date_string: StringValue) -> Expression:
|
|
506
|
+
"""
|
|
507
|
+
Parse a date from ISO format string (yyyy-mm-dd).
|
|
508
|
+
|
|
509
|
+
Parameters
|
|
510
|
+
----------
|
|
511
|
+
date_string: StringValue
|
|
512
|
+
The ISO format date string.
|
|
513
|
+
|
|
514
|
+
Returns
|
|
515
|
+
-------
|
|
516
|
+
Expression
|
|
517
|
+
An `Expression` computing the parsed date. Returns `Date`.
|
|
518
|
+
"""
|
|
187
519
|
return _parse_date(date_string, ISO.DATE)
|
|
188
520
|
|
|
189
521
|
#--------------------------------------------------
|
|
@@ -225,7 +557,42 @@ _datetime_subtract = library.Relation("datetime_subtract", [Field.input("datetim
|
|
|
225
557
|
# _datetime_range_from_start = library.Relation("datetime_range_from_start", [Field.input("start", DateTime), Field.input("periods", Integer), Field.input("frequency", String), Field("datetime", DateTime)])
|
|
226
558
|
# _datetime_range_from_end = library.Relation("datetime_range_from_end", [Field.input("end", DateTime), Field.input("periods", Integer), Field.input("frequency", String), Field("datetime", DateTime)])
|
|
227
559
|
|
|
560
|
+
@include_in_docs
|
|
228
561
|
class datetime:
|
|
562
|
+
"""
|
|
563
|
+
Construct a datetime from components.
|
|
564
|
+
|
|
565
|
+
When you construct a datetime using this class, it returns an `Expression` and not a
|
|
566
|
+
`datetime` object. All of the methods on this class are class methods that operate on
|
|
567
|
+
datetime expressions.
|
|
568
|
+
|
|
569
|
+
Parameters
|
|
570
|
+
----------
|
|
571
|
+
year: IntegerValue
|
|
572
|
+
The year.
|
|
573
|
+
month: IntegerValue
|
|
574
|
+
The month (1-12).
|
|
575
|
+
day: IntegerValue
|
|
576
|
+
The day of the month.
|
|
577
|
+
hour: IntegerValue
|
|
578
|
+
The hour (0-23). Default: 0.
|
|
579
|
+
minute: IntegerValue
|
|
580
|
+
The minute (0-59). Default: 0.
|
|
581
|
+
second: IntegerValue
|
|
582
|
+
The second (0-59). Default: 0.
|
|
583
|
+
millisecond: IntegerValue
|
|
584
|
+
The millisecond (0-999). Default: 0.
|
|
585
|
+
tz: dt.tzinfo | StringValue
|
|
586
|
+
The timezone. Default: "UTC".
|
|
587
|
+
|
|
588
|
+
Examples
|
|
589
|
+
--------
|
|
590
|
+
Construct datetimes:
|
|
591
|
+
|
|
592
|
+
>>> datetime.datetime(2024, 1, 15, 14, 30, 0)
|
|
593
|
+
>>> datetime.datetime(2024, 1, 1, 6, 30, 45, 0, 'America/New_York')
|
|
594
|
+
>>> datetime.datetime(Event.year, Event.month, Event.day, Event.hour, Event.minute)
|
|
595
|
+
"""
|
|
229
596
|
|
|
230
597
|
def __new__(cls, year: IntegerValue, month: IntegerValue, day: IntegerValue, hour: IntegerValue = 0, minute: IntegerValue = 0,
|
|
231
598
|
second: IntegerValue = 0, millisecond: IntegerValue = 0, tz: dt.tzinfo|StringValue = "UTC") -> Expression:
|
|
@@ -233,97 +600,410 @@ class datetime:
|
|
|
233
600
|
tz = str(tz)
|
|
234
601
|
return _construct_datetime_ms_tz(year, month, day, hour, minute, second, millisecond, tz)
|
|
235
602
|
|
|
603
|
+
def __init__(self, year: IntegerValue, month: IntegerValue, day: IntegerValue, hour: IntegerValue = 0, minute: IntegerValue = 0,
|
|
604
|
+
second: IntegerValue = 0, millisecond: IntegerValue = 0, tz: dt.tzinfo|StringValue = "UTC"):
|
|
605
|
+
pass
|
|
606
|
+
|
|
236
607
|
@classmethod
|
|
608
|
+
@include_in_docs
|
|
237
609
|
def now(cls) -> Expression:
|
|
610
|
+
"""
|
|
611
|
+
Get the current datetime.
|
|
612
|
+
|
|
613
|
+
Returns
|
|
614
|
+
-------
|
|
615
|
+
Expression
|
|
616
|
+
An `Expression` computing the current datetime. Returns `DateTime`.
|
|
617
|
+
"""
|
|
238
618
|
return _datetime_now()
|
|
239
619
|
|
|
240
620
|
@classmethod
|
|
621
|
+
@include_in_docs
|
|
241
622
|
def year(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
623
|
+
"""
|
|
624
|
+
Extract the year from a datetime.
|
|
625
|
+
|
|
626
|
+
Parameters
|
|
627
|
+
----------
|
|
628
|
+
datetime: DateTimeValue
|
|
629
|
+
The datetime to extract from.
|
|
630
|
+
tz: dt.tzinfo | StringValue | None
|
|
631
|
+
The timezone for extraction. Default: None (uses datetime's timezone or UTC).
|
|
632
|
+
|
|
633
|
+
Returns
|
|
634
|
+
-------
|
|
635
|
+
Expression
|
|
636
|
+
An Expression computing the year.
|
|
637
|
+
"""
|
|
242
638
|
tz = _extract_tz(datetime, tz)
|
|
243
639
|
return _datetime_year(datetime, tz)
|
|
244
640
|
|
|
245
641
|
@classmethod
|
|
642
|
+
@include_in_docs
|
|
246
643
|
def quarter(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
644
|
+
"""
|
|
645
|
+
Extract the quarter (1-4) from a datetime.
|
|
646
|
+
|
|
647
|
+
Parameters
|
|
648
|
+
----------
|
|
649
|
+
datetime: DateTimeValue
|
|
650
|
+
The datetime to extract from.
|
|
651
|
+
tz: dt.tzinfo | StringValue | None
|
|
652
|
+
The timezone for extraction. Default: None.
|
|
653
|
+
|
|
654
|
+
Returns
|
|
655
|
+
-------
|
|
656
|
+
Expression
|
|
657
|
+
An `Expression` computing the quarter. Returns `Integer`.
|
|
658
|
+
"""
|
|
247
659
|
tz = _extract_tz(datetime, tz)
|
|
248
660
|
return _datetime_quarter(datetime, tz)
|
|
249
661
|
|
|
250
662
|
@classmethod
|
|
663
|
+
@include_in_docs
|
|
251
664
|
def month(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
665
|
+
"""
|
|
666
|
+
Extract the month (1-12) from a datetime.
|
|
667
|
+
|
|
668
|
+
Parameters
|
|
669
|
+
----------
|
|
670
|
+
datetime: DateTimeValue
|
|
671
|
+
The datetime to extract from.
|
|
672
|
+
tz: dt.tzinfo | StringValue | None
|
|
673
|
+
The timezone for extraction. Default: None.
|
|
674
|
+
|
|
675
|
+
Returns
|
|
676
|
+
-------
|
|
677
|
+
Expression
|
|
678
|
+
An `Expression` computing the month. Returns `Integer`.
|
|
679
|
+
"""
|
|
252
680
|
tz = _extract_tz(datetime, tz)
|
|
253
681
|
return _datetime_month(datetime, tz)
|
|
254
682
|
|
|
255
683
|
@classmethod
|
|
684
|
+
@include_in_docs
|
|
256
685
|
def week(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
686
|
+
"""
|
|
687
|
+
Extract the ISO week number from a datetime.
|
|
688
|
+
|
|
689
|
+
Parameters
|
|
690
|
+
----------
|
|
691
|
+
datetime: DateTimeValue
|
|
692
|
+
The datetime to extract from.
|
|
693
|
+
tz: dt.tzinfo | StringValue | None
|
|
694
|
+
The timezone for extraction. Default: None.
|
|
695
|
+
|
|
696
|
+
Returns
|
|
697
|
+
-------
|
|
698
|
+
Expression
|
|
699
|
+
An `Expression` computing the week number. Returns `Integer`.
|
|
700
|
+
"""
|
|
257
701
|
tz = _extract_tz(datetime, tz)
|
|
258
702
|
return _datetime_week(datetime, tz)
|
|
259
703
|
|
|
260
704
|
@classmethod
|
|
705
|
+
@include_in_docs
|
|
261
706
|
def day(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
707
|
+
"""
|
|
708
|
+
Extract the day of the month from a datetime.
|
|
709
|
+
|
|
710
|
+
Parameters
|
|
711
|
+
----------
|
|
712
|
+
datetime: DateTimeValue
|
|
713
|
+
The datetime to extract from.
|
|
714
|
+
tz: dt.tzinfo | StringValue | None
|
|
715
|
+
The timezone for extraction. Default: None.
|
|
716
|
+
|
|
717
|
+
Returns
|
|
718
|
+
-------
|
|
719
|
+
Expression
|
|
720
|
+
An `Expression` computing the day. Returns `Integer`.
|
|
721
|
+
"""
|
|
262
722
|
tz = _extract_tz(datetime, tz)
|
|
263
723
|
return _datetime_day(datetime, tz)
|
|
264
724
|
|
|
265
725
|
@classmethod
|
|
726
|
+
@include_in_docs
|
|
266
727
|
def dayofyear(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
728
|
+
"""
|
|
729
|
+
Extract the day of the year (1-366) from a datetime.
|
|
730
|
+
|
|
731
|
+
Parameters
|
|
732
|
+
----------
|
|
733
|
+
datetime: DateTimeValue
|
|
734
|
+
The datetime to extract from.
|
|
735
|
+
tz: dt.tzinfo | StringValue | None
|
|
736
|
+
The timezone for extraction. Default: None.
|
|
737
|
+
|
|
738
|
+
Returns
|
|
739
|
+
-------
|
|
740
|
+
Expression
|
|
741
|
+
An `Expression` computing the day of year. Returns `Integer`.
|
|
742
|
+
"""
|
|
267
743
|
tz = _extract_tz(datetime, tz)
|
|
268
744
|
return _datetime_dayofyear(datetime, tz)
|
|
269
745
|
|
|
270
746
|
@classmethod
|
|
747
|
+
@include_in_docs
|
|
271
748
|
def hour(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
749
|
+
"""
|
|
750
|
+
Extract the hour (0-23) from a datetime.
|
|
751
|
+
|
|
752
|
+
Parameters
|
|
753
|
+
----------
|
|
754
|
+
datetime: DateTimeValue
|
|
755
|
+
The datetime to extract from.
|
|
756
|
+
tz: dt.tzinfo | StringValue | None
|
|
757
|
+
The timezone for extraction. Default: None.
|
|
758
|
+
|
|
759
|
+
Returns
|
|
760
|
+
-------
|
|
761
|
+
Expression
|
|
762
|
+
An `Expression` computing the hour. Returns `Integer`.
|
|
763
|
+
"""
|
|
272
764
|
tz = _extract_tz(datetime, tz)
|
|
273
765
|
return _datetime_hour(datetime, tz)
|
|
274
766
|
|
|
275
767
|
@classmethod
|
|
768
|
+
@include_in_docs
|
|
276
769
|
def minute(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
770
|
+
"""
|
|
771
|
+
Extract the minute (0-59) from a datetime.
|
|
772
|
+
|
|
773
|
+
Parameters
|
|
774
|
+
----------
|
|
775
|
+
datetime: DateTimeValue
|
|
776
|
+
The datetime to extract from.
|
|
777
|
+
tz: dt.tzinfo | StringValue | None
|
|
778
|
+
The timezone for extraction. Default: None.
|
|
779
|
+
|
|
780
|
+
Returns
|
|
781
|
+
-------
|
|
782
|
+
Expression
|
|
783
|
+
An `Expression` computing the minute. Returns `Integer`.
|
|
784
|
+
"""
|
|
277
785
|
tz = _extract_tz(datetime, tz)
|
|
278
786
|
return _datetime_minute(datetime, tz)
|
|
279
787
|
|
|
280
788
|
@classmethod
|
|
789
|
+
@include_in_docs
|
|
281
790
|
def second(cls, datetime: DateTimeValue) -> Expression:
|
|
791
|
+
"""
|
|
792
|
+
Extract the second (0-59) from a datetime.
|
|
793
|
+
|
|
794
|
+
Parameters
|
|
795
|
+
----------
|
|
796
|
+
datetime: DateTimeValue
|
|
797
|
+
The datetime to extract from.
|
|
798
|
+
|
|
799
|
+
Returns
|
|
800
|
+
-------
|
|
801
|
+
Expression
|
|
802
|
+
An `Expression` computing the second. Returns `Integer`.
|
|
803
|
+
"""
|
|
282
804
|
return _datetime_second(datetime)
|
|
283
805
|
|
|
284
806
|
@classmethod
|
|
807
|
+
@include_in_docs
|
|
285
808
|
def isoweekday(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
286
809
|
"""
|
|
287
810
|
Return the ISO weekday as an integer, where Monday is 1, and Sunday is 7.
|
|
811
|
+
|
|
812
|
+
Parameters
|
|
813
|
+
----------
|
|
814
|
+
datetime: DateTimeValue
|
|
815
|
+
The datetime to extract from.
|
|
816
|
+
tz: dt.tzinfo | StringValue | None
|
|
817
|
+
The timezone for extraction. Default: None.
|
|
818
|
+
|
|
819
|
+
Returns
|
|
820
|
+
-------
|
|
821
|
+
Expression
|
|
822
|
+
An `Expression` computing the ISO weekday (1=Monday...7=Sunday). Returns `Integer`.
|
|
288
823
|
"""
|
|
289
824
|
tz = _extract_tz(datetime, tz)
|
|
290
825
|
return _datetime_weekday(datetime, tz)
|
|
291
826
|
|
|
292
827
|
@classmethod
|
|
828
|
+
@include_in_docs
|
|
293
829
|
def weekday(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
830
|
+
"""
|
|
831
|
+
Return the weekday as an integer, where Monday is 0, and Sunday is 6.
|
|
832
|
+
|
|
833
|
+
Parameters
|
|
834
|
+
----------
|
|
835
|
+
datetime: DateTimeValue
|
|
836
|
+
The datetime to extract from.
|
|
837
|
+
tz: dt.tzinfo | StringValue | None
|
|
838
|
+
The timezone for extraction. Default: None.
|
|
839
|
+
|
|
840
|
+
Returns
|
|
841
|
+
-------
|
|
842
|
+
Expression
|
|
843
|
+
An `Expression` computing the weekday (0=Monday...6=Sunday). Returns `Integer`.
|
|
844
|
+
"""
|
|
294
845
|
return cls.isoweekday(datetime, tz) - 1 # Convert ISO weekday (1=Mon..7=Sun) to weekday (0=Mon..6=Sun)
|
|
295
846
|
|
|
296
847
|
@classmethod
|
|
848
|
+
@include_in_docs
|
|
297
849
|
def fromordinal(cls, ordinal: IntegerValue) -> Expression:
|
|
850
|
+
"""
|
|
851
|
+
Construct a datetime from a proleptic Gregorian ordinal.
|
|
852
|
+
|
|
853
|
+
Parameters
|
|
854
|
+
----------
|
|
855
|
+
ordinal: IntegerValue
|
|
856
|
+
The ordinal (day 1 is 0001-01-01).
|
|
857
|
+
|
|
858
|
+
Returns
|
|
859
|
+
-------
|
|
860
|
+
Expression
|
|
861
|
+
An `Expression` computing the datetime at midnight UTC. Returns `DateTime`.
|
|
862
|
+
"""
|
|
298
863
|
# Convert ordinal to milliseconds, since ordinals in Python are days
|
|
299
864
|
# Minus 1 day since we can't declare date 0000-00-00
|
|
300
865
|
ordinal_milliseconds = (ordinal - 1) * 86400000 # 24 * 60 * 60 * 1000
|
|
301
866
|
return cls.add(DateTime(dt.datetime(1, 1, 1, 0, 0, 0)), milliseconds(ordinal_milliseconds))
|
|
302
867
|
|
|
303
868
|
@classmethod
|
|
869
|
+
@include_in_docs
|
|
304
870
|
def strptime(cls, date_str: StringValue, format: StringValue) -> Expression:
|
|
871
|
+
"""
|
|
872
|
+
Parse a datetime from a string using a format string.
|
|
873
|
+
|
|
874
|
+
Parameters
|
|
875
|
+
----------
|
|
876
|
+
date_str: StringValue
|
|
877
|
+
The datetime string to parse.
|
|
878
|
+
format: StringValue
|
|
879
|
+
The format string.
|
|
880
|
+
|
|
881
|
+
Returns
|
|
882
|
+
-------
|
|
883
|
+
Expression
|
|
884
|
+
An `Expression` computing the parsed datetime. Returns `DateTime`.
|
|
885
|
+
"""
|
|
305
886
|
return _parse_datetime(date_str, format)
|
|
306
887
|
|
|
307
888
|
@classmethod
|
|
889
|
+
@include_in_docs
|
|
308
890
|
def to_date(cls, datetime: DateTimeValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
891
|
+
"""
|
|
892
|
+
Convert a datetime to a date.
|
|
893
|
+
|
|
894
|
+
Parameters
|
|
895
|
+
----------
|
|
896
|
+
datetime: DateTimeValue
|
|
897
|
+
The datetime to convert.
|
|
898
|
+
tz: dt.tzinfo | StringValue | None
|
|
899
|
+
The timezone for conversion. Default: None.
|
|
900
|
+
|
|
901
|
+
Returns
|
|
902
|
+
-------
|
|
903
|
+
Expression
|
|
904
|
+
An `Expression` computing the date. Returns `Date`.
|
|
905
|
+
"""
|
|
309
906
|
tz = _extract_tz(datetime, tz)
|
|
310
907
|
return _construct_date_from_datetime(datetime, tz)
|
|
311
908
|
|
|
312
909
|
@classmethod
|
|
910
|
+
@include_in_docs
|
|
313
911
|
def format(cls, date: DateTimeValue, format: StringValue, tz: dt.tzinfo|StringValue|None = None) -> Expression:
|
|
912
|
+
"""
|
|
913
|
+
Format a datetime as a string.
|
|
914
|
+
|
|
915
|
+
Parameters
|
|
916
|
+
----------
|
|
917
|
+
date: DateTimeValue
|
|
918
|
+
The datetime to format.
|
|
919
|
+
format: StringValue
|
|
920
|
+
The format string.
|
|
921
|
+
tz: dt.tzinfo | StringValue | None
|
|
922
|
+
The timezone for formatting. Default: None.
|
|
923
|
+
|
|
924
|
+
Returns
|
|
925
|
+
-------
|
|
926
|
+
Expression
|
|
927
|
+
An `Expression` computing the formatted datetime string. Returns `String`.
|
|
928
|
+
"""
|
|
314
929
|
tz = _extract_tz(date, tz)
|
|
315
930
|
return _datetime_format(date, format, tz)
|
|
316
931
|
|
|
317
932
|
@classmethod
|
|
933
|
+
@include_in_docs
|
|
318
934
|
def add(cls, date: DateTimeValue, period: Variable) -> Expression:
|
|
935
|
+
"""
|
|
936
|
+
Add a period to a datetime.
|
|
937
|
+
|
|
938
|
+
Parameters
|
|
939
|
+
----------
|
|
940
|
+
date: DateTimeValue
|
|
941
|
+
The datetime to add to.
|
|
942
|
+
period: Variable
|
|
943
|
+
The period to add (use `milliseconds()`, `seconds()`, `minutes()`, `hours()`, `days()`, etc.).
|
|
944
|
+
|
|
945
|
+
Returns
|
|
946
|
+
-------
|
|
947
|
+
Expression
|
|
948
|
+
An `Expression` computing the resulting datetime. Returns `DateTime`. Returns `DateTime`.
|
|
949
|
+
|
|
950
|
+
Examples
|
|
951
|
+
--------
|
|
952
|
+
Add periods to datetimes:
|
|
953
|
+
|
|
954
|
+
>>> datetime.datetime.add(Event.start_time, datetime.hours(2))
|
|
955
|
+
>>> datetime.datetime.add(Appointment.scheduled_at, datetime.minutes(30))
|
|
956
|
+
>>> datetime.datetime.add(Task.created_at, datetime.days(7))
|
|
957
|
+
"""
|
|
319
958
|
return _datetime_add(date, period)
|
|
320
959
|
|
|
321
960
|
@classmethod
|
|
961
|
+
@include_in_docs
|
|
322
962
|
def subtract(cls, date: DateTimeValue, period: Variable) -> Expression:
|
|
963
|
+
"""
|
|
964
|
+
Subtract a period from a datetime.
|
|
965
|
+
|
|
966
|
+
Parameters
|
|
967
|
+
----------
|
|
968
|
+
date: DateTimeValue
|
|
969
|
+
The datetime to subtract from.
|
|
970
|
+
period: Variable
|
|
971
|
+
The period to subtract (use `milliseconds()`, `seconds()`, `minutes()`, `hours()`, `days()`, etc.).
|
|
972
|
+
|
|
973
|
+
Returns
|
|
974
|
+
-------
|
|
975
|
+
Expression
|
|
976
|
+
An `Expression` computing the resulting datetime. Returns `DateTime`.
|
|
977
|
+
"""
|
|
323
978
|
return _datetime_subtract(date, period)
|
|
324
979
|
|
|
325
980
|
@classmethod
|
|
981
|
+
@include_in_docs
|
|
326
982
|
def range(cls, start: DateTimeValue | None = None, end: DateTimeValue | None = None, periods: IntegerValue = 1, freq: Frequency = "D") -> Variable:
|
|
983
|
+
"""
|
|
984
|
+
Generate a range of datetimes.
|
|
985
|
+
|
|
986
|
+
Parameters
|
|
987
|
+
----------
|
|
988
|
+
start: DateTimeValue | None
|
|
989
|
+
The start datetime. If None, computes from end.
|
|
990
|
+
end: DateTimeValue | None
|
|
991
|
+
The end datetime (inclusive). If None, uses periods.
|
|
992
|
+
periods: IntegerValue
|
|
993
|
+
Number of periods to generate. Default: 1.
|
|
994
|
+
freq: Frequency
|
|
995
|
+
Frequency: "ms", "s", "m" (minute), "H", "D", "W", "M", "Y". Default: "D".
|
|
996
|
+
|
|
997
|
+
Returns
|
|
998
|
+
-------
|
|
999
|
+
Variable
|
|
1000
|
+
A `Variable` representing the datetime range. Returns `DateTime`.
|
|
1001
|
+
|
|
1002
|
+
Raises
|
|
1003
|
+
------
|
|
1004
|
+
ValueError
|
|
1005
|
+
If neither start nor end is provided.
|
|
1006
|
+
"""
|
|
327
1007
|
if start is None and end is None:
|
|
328
1008
|
raise ValueError("Invalid start/end date for datetime.range. Must provide at least start date or end date")
|
|
329
1009
|
# TODO - this transformation is currently LQP-focused. Eventually we will want to
|
|
@@ -365,7 +1045,23 @@ class datetime:
|
|
|
365
1045
|
|
|
366
1046
|
|
|
367
1047
|
@classmethod
|
|
1048
|
+
@include_in_docs
|
|
368
1049
|
def period_milliseconds(cls, start: DateTimeValue, end: DateTimeValue) -> Expression:
|
|
1050
|
+
"""
|
|
1051
|
+
Compute the number of milliseconds between two datetimes.
|
|
1052
|
+
|
|
1053
|
+
Parameters
|
|
1054
|
+
----------
|
|
1055
|
+
start: DateTimeValue
|
|
1056
|
+
The start datetime.
|
|
1057
|
+
end: DateTimeValue
|
|
1058
|
+
The end datetime.
|
|
1059
|
+
|
|
1060
|
+
Returns
|
|
1061
|
+
-------
|
|
1062
|
+
Expression
|
|
1063
|
+
An Expression computing the number of milliseconds.
|
|
1064
|
+
"""
|
|
369
1065
|
return _datetimes_period_milliseconds(start, end)
|
|
370
1066
|
|
|
371
1067
|
|
|
@@ -401,47 +1097,234 @@ _week = library.Relation("week", [Field.input("weeks", Integer), Field("period",
|
|
|
401
1097
|
_month = library.Relation("month", [Field.input("months", Integer), Field("period", Months)])
|
|
402
1098
|
_year = library.Relation("year", [Field.input("years", Integer), Field("period", Years)])
|
|
403
1099
|
|
|
1100
|
+
@include_in_docs
|
|
404
1101
|
def nanoseconds(period: IntegerValue) -> Expression:
|
|
1102
|
+
"""
|
|
1103
|
+
Create a nanoseconds period.
|
|
1104
|
+
|
|
1105
|
+
Parameters
|
|
1106
|
+
----------
|
|
1107
|
+
period: IntegerValue
|
|
1108
|
+
The number of nanoseconds.
|
|
1109
|
+
|
|
1110
|
+
Returns
|
|
1111
|
+
-------
|
|
1112
|
+
Expression
|
|
1113
|
+
An `Expression` computing the period.
|
|
1114
|
+
"""
|
|
405
1115
|
return _nanosecond(period)
|
|
406
1116
|
|
|
1117
|
+
@include_in_docs
|
|
407
1118
|
def microseconds(period: IntegerValue) -> Expression:
|
|
1119
|
+
"""
|
|
1120
|
+
Create a microseconds period.
|
|
1121
|
+
|
|
1122
|
+
Parameters
|
|
1123
|
+
----------
|
|
1124
|
+
period: IntegerValue
|
|
1125
|
+
The number of microseconds.
|
|
1126
|
+
|
|
1127
|
+
Returns
|
|
1128
|
+
-------
|
|
1129
|
+
Expression
|
|
1130
|
+
An `Expression` computing the period.
|
|
1131
|
+
"""
|
|
408
1132
|
return _microsecond(period)
|
|
409
1133
|
|
|
1134
|
+
@include_in_docs
|
|
410
1135
|
def milliseconds(period: IntegerValue) -> Expression:
|
|
1136
|
+
"""
|
|
1137
|
+
Create a milliseconds period.
|
|
1138
|
+
|
|
1139
|
+
Parameters
|
|
1140
|
+
----------
|
|
1141
|
+
period: IntegerValue
|
|
1142
|
+
The number of milliseconds.
|
|
1143
|
+
|
|
1144
|
+
Returns
|
|
1145
|
+
-------
|
|
1146
|
+
Expression
|
|
1147
|
+
An `Expression` computing the period.
|
|
1148
|
+
"""
|
|
411
1149
|
return _millisecond(period)
|
|
412
1150
|
|
|
1151
|
+
@include_in_docs
|
|
413
1152
|
def seconds(period: IntegerValue) -> Expression:
|
|
1153
|
+
"""
|
|
1154
|
+
Create a seconds period.
|
|
1155
|
+
|
|
1156
|
+
Parameters
|
|
1157
|
+
----------
|
|
1158
|
+
period: IntegerValue
|
|
1159
|
+
The number of seconds.
|
|
1160
|
+
|
|
1161
|
+
Returns
|
|
1162
|
+
-------
|
|
1163
|
+
Expression
|
|
1164
|
+
An `Expression` computing the period.
|
|
1165
|
+
"""
|
|
414
1166
|
return _second(period)
|
|
415
1167
|
|
|
1168
|
+
@include_in_docs
|
|
416
1169
|
def minutes(period: IntegerValue) -> Expression:
|
|
1170
|
+
"""
|
|
1171
|
+
Create a minutes period.
|
|
1172
|
+
|
|
1173
|
+
Parameters
|
|
1174
|
+
----------
|
|
1175
|
+
period: IntegerValue
|
|
1176
|
+
The number of minutes.
|
|
1177
|
+
|
|
1178
|
+
Returns
|
|
1179
|
+
-------
|
|
1180
|
+
Expression
|
|
1181
|
+
An `Expression` computing the period.
|
|
1182
|
+
"""
|
|
417
1183
|
return _minute(period)
|
|
418
1184
|
|
|
1185
|
+
@include_in_docs
|
|
419
1186
|
def hours(period: IntegerValue) -> Expression:
|
|
1187
|
+
"""
|
|
1188
|
+
Create an hours period.
|
|
1189
|
+
|
|
1190
|
+
Parameters
|
|
1191
|
+
----------
|
|
1192
|
+
period: IntegerValue
|
|
1193
|
+
The number of hours.
|
|
1194
|
+
|
|
1195
|
+
Returns
|
|
1196
|
+
-------
|
|
1197
|
+
Expression
|
|
1198
|
+
An `Expression` computing the period.
|
|
1199
|
+
|
|
1200
|
+
Examples
|
|
1201
|
+
--------
|
|
1202
|
+
Create hour periods:
|
|
1203
|
+
|
|
1204
|
+
>>> datetime.hours(24)
|
|
1205
|
+
>>> datetime.hours(Flight.duration_hours)
|
|
1206
|
+
"""
|
|
420
1207
|
return _hour(period)
|
|
421
1208
|
|
|
1209
|
+
@include_in_docs
|
|
422
1210
|
def days(period: IntegerValue) -> Expression:
|
|
1211
|
+
"""
|
|
1212
|
+
Create a days period.
|
|
1213
|
+
|
|
1214
|
+
Parameters
|
|
1215
|
+
----------
|
|
1216
|
+
period: IntegerValue
|
|
1217
|
+
The number of days.
|
|
1218
|
+
|
|
1219
|
+
Returns
|
|
1220
|
+
-------
|
|
1221
|
+
Expression
|
|
1222
|
+
An `Expression` computing the period.
|
|
1223
|
+
|
|
1224
|
+
Examples
|
|
1225
|
+
--------
|
|
1226
|
+
Create day periods:
|
|
1227
|
+
|
|
1228
|
+
>>> datetime.days(7)
|
|
1229
|
+
>>> datetime.days(Order.shipping_days)
|
|
1230
|
+
"""
|
|
423
1231
|
return _day(period)
|
|
424
1232
|
|
|
1233
|
+
@include_in_docs
|
|
425
1234
|
def weeks(period: IntegerValue) -> Expression:
|
|
1235
|
+
"""
|
|
1236
|
+
Create a weeks period.
|
|
1237
|
+
|
|
1238
|
+
Parameters
|
|
1239
|
+
----------
|
|
1240
|
+
period: IntegerValue
|
|
1241
|
+
The number of weeks.
|
|
1242
|
+
|
|
1243
|
+
Returns
|
|
1244
|
+
-------
|
|
1245
|
+
Expression
|
|
1246
|
+
An `Expression` computing the period.
|
|
1247
|
+
"""
|
|
426
1248
|
return _week(period)
|
|
427
1249
|
|
|
1250
|
+
@include_in_docs
|
|
428
1251
|
def months(period: IntegerValue) -> Expression:
|
|
1252
|
+
"""
|
|
1253
|
+
Create a months period.
|
|
1254
|
+
|
|
1255
|
+
Parameters
|
|
1256
|
+
----------
|
|
1257
|
+
period: IntegerValue
|
|
1258
|
+
The number of months.
|
|
1259
|
+
|
|
1260
|
+
Returns
|
|
1261
|
+
-------
|
|
1262
|
+
Expression
|
|
1263
|
+
An `Expression` computing the period.
|
|
1264
|
+
|
|
1265
|
+
Examples
|
|
1266
|
+
--------
|
|
1267
|
+
Create month periods:
|
|
1268
|
+
|
|
1269
|
+
>>> datetime.months(6)
|
|
1270
|
+
>>> datetime.months(Lease.duration_months)
|
|
1271
|
+
"""
|
|
429
1272
|
return _month(period)
|
|
430
1273
|
|
|
1274
|
+
@include_in_docs
|
|
431
1275
|
def years(period: IntegerValue) -> Expression:
|
|
1276
|
+
"""
|
|
1277
|
+
Create a years period.
|
|
1278
|
+
|
|
1279
|
+
Parameters
|
|
1280
|
+
----------
|
|
1281
|
+
period: IntegerValue
|
|
1282
|
+
The number of years.
|
|
1283
|
+
|
|
1284
|
+
Returns
|
|
1285
|
+
-------
|
|
1286
|
+
Expression
|
|
1287
|
+
An `Expression` computing the period.
|
|
1288
|
+
"""
|
|
432
1289
|
return _year(period)
|
|
433
1290
|
|
|
434
|
-
|
|
435
1291
|
Frequency = Union[
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
1292
|
+
LiteralType["ms"],
|
|
1293
|
+
LiteralType["s"],
|
|
1294
|
+
LiteralType["m"],
|
|
1295
|
+
LiteralType["H"],
|
|
1296
|
+
LiteralType["D"],
|
|
1297
|
+
LiteralType["W"],
|
|
1298
|
+
LiteralType["M"],
|
|
1299
|
+
LiteralType["Y"],
|
|
444
1300
|
]
|
|
1301
|
+
"""
|
|
1302
|
+
Type alias for time frequency strings used in date and datetime range operations.
|
|
1303
|
+
|
|
1304
|
+
Valid frequency strings:
|
|
1305
|
+
- `"ms"`: milliseconds
|
|
1306
|
+
- `"s"`: seconds
|
|
1307
|
+
- `"m"`: minutes (lowercase m)
|
|
1308
|
+
- `"H"`: hours
|
|
1309
|
+
- `"D"`: days
|
|
1310
|
+
- `"W"`: weeks
|
|
1311
|
+
- `"M"`: months (uppercase M)
|
|
1312
|
+
- `"Y"`: years
|
|
1313
|
+
|
|
1314
|
+
Examples
|
|
1315
|
+
--------
|
|
1316
|
+
Use frequency strings in date ranges:
|
|
1317
|
+
|
|
1318
|
+
>>> datetime.date.range(start_date, end_date, freq="D") # Daily
|
|
1319
|
+
>>> datetime.date.range(start_date, end_date, freq="W") # Weekly
|
|
1320
|
+
>>> datetime.date.range(start_date, end_date, freq="M") # Monthly
|
|
1321
|
+
|
|
1322
|
+
Use frequency strings in datetime ranges:
|
|
1323
|
+
|
|
1324
|
+
>>> datetime.datetime.range(start_dt, end_dt, freq="H") # Hourly
|
|
1325
|
+
>>> datetime.datetime.range(start_dt, end_dt, freq="m") # Every minute
|
|
1326
|
+
>>> datetime.datetime.range(start_dt, end_dt, freq="ms") # Milliseconds
|
|
1327
|
+
"""
|
|
445
1328
|
|
|
446
1329
|
_periods = {
|
|
447
1330
|
"ms": milliseconds,
|