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.
Files changed (118) hide show
  1. relationalai/config/config.py +47 -21
  2. relationalai/config/connections/__init__.py +5 -2
  3. relationalai/config/connections/duckdb.py +2 -2
  4. relationalai/config/connections/local.py +31 -0
  5. relationalai/config/connections/snowflake.py +0 -1
  6. relationalai/config/external/raiconfig_converter.py +235 -0
  7. relationalai/config/external/raiconfig_models.py +202 -0
  8. relationalai/config/external/utils.py +31 -0
  9. relationalai/config/shims.py +1 -0
  10. relationalai/semantics/__init__.py +10 -8
  11. relationalai/semantics/backends/sql/sql_compiler.py +1 -4
  12. relationalai/semantics/experimental/__init__.py +0 -0
  13. relationalai/semantics/experimental/builder.py +295 -0
  14. relationalai/semantics/experimental/builtins.py +154 -0
  15. relationalai/semantics/frontend/base.py +67 -42
  16. relationalai/semantics/frontend/core.py +34 -6
  17. relationalai/semantics/frontend/front_compiler.py +209 -37
  18. relationalai/semantics/frontend/pprint.py +6 -2
  19. relationalai/semantics/metamodel/__init__.py +7 -0
  20. relationalai/semantics/metamodel/metamodel.py +2 -0
  21. relationalai/semantics/metamodel/metamodel_analyzer.py +58 -16
  22. relationalai/semantics/metamodel/pprint.py +6 -1
  23. relationalai/semantics/metamodel/rewriter.py +11 -7
  24. relationalai/semantics/metamodel/typer.py +116 -41
  25. relationalai/semantics/reasoners/__init__.py +11 -0
  26. relationalai/semantics/reasoners/graph/__init__.py +35 -0
  27. relationalai/semantics/reasoners/graph/core.py +9028 -0
  28. relationalai/semantics/std/__init__.py +30 -10
  29. relationalai/semantics/std/aggregates.py +641 -12
  30. relationalai/semantics/std/common.py +146 -13
  31. relationalai/semantics/std/constraints.py +71 -1
  32. relationalai/semantics/std/datetime.py +904 -21
  33. relationalai/semantics/std/decimals.py +143 -2
  34. relationalai/semantics/std/floats.py +57 -4
  35. relationalai/semantics/std/integers.py +98 -4
  36. relationalai/semantics/std/math.py +857 -35
  37. relationalai/semantics/std/numbers.py +216 -20
  38. relationalai/semantics/std/re.py +213 -5
  39. relationalai/semantics/std/strings.py +437 -44
  40. relationalai/shims/executor.py +60 -52
  41. relationalai/shims/fixtures.py +85 -0
  42. relationalai/shims/helpers.py +26 -2
  43. relationalai/shims/hoister.py +28 -9
  44. relationalai/shims/mm2v0.py +204 -173
  45. relationalai/tools/cli/cli.py +192 -10
  46. relationalai/tools/cli/components/progress_reader.py +1 -1
  47. relationalai/tools/cli/docs.py +394 -0
  48. relationalai/tools/debugger.py +11 -4
  49. relationalai/tools/qb_debugger.py +435 -0
  50. relationalai/tools/typer_debugger.py +1 -2
  51. relationalai/util/dataclasses.py +3 -5
  52. relationalai/util/docutils.py +1 -2
  53. relationalai/util/error.py +2 -5
  54. relationalai/util/python.py +23 -0
  55. relationalai/util/runtime.py +1 -2
  56. relationalai/util/schema.py +2 -4
  57. relationalai/util/structures.py +4 -2
  58. relationalai/util/tracing.py +8 -2
  59. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/METADATA +8 -5
  60. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/RECORD +118 -95
  61. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/WHEEL +1 -1
  62. v0/relationalai/__init__.py +1 -1
  63. v0/relationalai/clients/client.py +52 -18
  64. v0/relationalai/clients/exec_txn_poller.py +122 -0
  65. v0/relationalai/clients/local.py +23 -8
  66. v0/relationalai/clients/resources/azure/azure.py +36 -11
  67. v0/relationalai/clients/resources/snowflake/__init__.py +4 -4
  68. v0/relationalai/clients/resources/snowflake/cli_resources.py +12 -1
  69. v0/relationalai/clients/resources/snowflake/direct_access_resources.py +124 -100
  70. v0/relationalai/clients/resources/snowflake/engine_service.py +381 -0
  71. v0/relationalai/clients/resources/snowflake/engine_state_handlers.py +35 -29
  72. v0/relationalai/clients/resources/snowflake/error_handlers.py +43 -2
  73. v0/relationalai/clients/resources/snowflake/snowflake.py +277 -179
  74. v0/relationalai/clients/resources/snowflake/use_index_poller.py +8 -0
  75. v0/relationalai/clients/types.py +5 -0
  76. v0/relationalai/errors.py +19 -1
  77. v0/relationalai/semantics/lqp/algorithms.py +173 -0
  78. v0/relationalai/semantics/lqp/builtins.py +199 -2
  79. v0/relationalai/semantics/lqp/executor.py +68 -37
  80. v0/relationalai/semantics/lqp/ir.py +28 -2
  81. v0/relationalai/semantics/lqp/model2lqp.py +215 -45
  82. v0/relationalai/semantics/lqp/passes.py +13 -658
  83. v0/relationalai/semantics/lqp/rewrite/__init__.py +12 -0
  84. v0/relationalai/semantics/lqp/rewrite/algorithm.py +385 -0
  85. v0/relationalai/semantics/lqp/rewrite/constants_to_vars.py +70 -0
  86. v0/relationalai/semantics/lqp/rewrite/deduplicate_vars.py +104 -0
  87. v0/relationalai/semantics/lqp/rewrite/eliminate_data.py +108 -0
  88. v0/relationalai/semantics/lqp/rewrite/extract_keys.py +25 -3
  89. v0/relationalai/semantics/lqp/rewrite/period_math.py +77 -0
  90. v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +65 -31
  91. v0/relationalai/semantics/lqp/rewrite/unify_definitions.py +317 -0
  92. v0/relationalai/semantics/lqp/utils.py +11 -1
  93. v0/relationalai/semantics/lqp/validators.py +14 -1
  94. v0/relationalai/semantics/metamodel/builtins.py +2 -1
  95. v0/relationalai/semantics/metamodel/compiler.py +2 -1
  96. v0/relationalai/semantics/metamodel/dependency.py +12 -3
  97. v0/relationalai/semantics/metamodel/executor.py +11 -1
  98. v0/relationalai/semantics/metamodel/factory.py +2 -2
  99. v0/relationalai/semantics/metamodel/helpers.py +7 -0
  100. v0/relationalai/semantics/metamodel/ir.py +3 -2
  101. v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +30 -20
  102. v0/relationalai/semantics/metamodel/rewrite/flatten.py +50 -13
  103. v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +9 -3
  104. v0/relationalai/semantics/metamodel/typer/checker.py +6 -4
  105. v0/relationalai/semantics/metamodel/typer/typer.py +4 -3
  106. v0/relationalai/semantics/metamodel/visitor.py +4 -3
  107. v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +1 -1
  108. v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +336 -86
  109. v0/relationalai/semantics/rel/compiler.py +2 -1
  110. v0/relationalai/semantics/rel/executor.py +3 -2
  111. v0/relationalai/semantics/tests/lqp/__init__.py +0 -0
  112. v0/relationalai/semantics/tests/lqp/algorithms.py +345 -0
  113. v0/relationalai/tools/cli.py +339 -186
  114. v0/relationalai/tools/cli_controls.py +216 -67
  115. v0/relationalai/tools/cli_helpers.py +410 -6
  116. v0/relationalai/util/format.py +5 -2
  117. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/entry_points.txt +0 -0
  118. {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 Aggregate, Library, Concept, MetaRef, NumberConcept, Expression, Field, Literal, Variable
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
- For example, date_range(2025-02-01, 2025-03-01, freq='M') and date_range(2025-02-01, 2025-03-31, freq='M') will
147
- compute range_end to be ceil(28*1/(365/12))=1 and ceil(58*1/(365/12))=2.
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
- Literal["ms"],
437
- Literal["s"],
438
- Literal["m"],
439
- Literal["H"],
440
- Literal["D"],
441
- Literal["W"],
442
- Literal["M"],
443
- Literal["Y"],
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,