value-object-pattern 0.1.0__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.
- value_object_pattern/__init__.py +10 -0
- value_object_pattern/decorators/__init__.py +7 -0
- value_object_pattern/decorators/value_object_process.py +83 -0
- value_object_pattern/decorators/value_object_validation.py +78 -0
- value_object_pattern/models/__init__.py +3 -0
- value_object_pattern/models/value_object.py +383 -0
- value_object_pattern/py.typed +0 -0
- value_object_pattern/usables/__init__.py +54 -0
- value_object_pattern/usables/dates/__init__.py +9 -0
- value_object_pattern/usables/dates/date/__init__.py +7 -0
- value_object_pattern/usables/dates/date/date_value_object.py +162 -0
- value_object_pattern/usables/dates/date/string_date_value_object.py +201 -0
- value_object_pattern/usables/dates/datetime/__init__.py +7 -0
- value_object_pattern/usables/dates/datetime/datetime_value_object.py +193 -0
- value_object_pattern/usables/dates/datetime/string_datetime_value_object.py +237 -0
- value_object_pattern/usables/identifiers/__init__.py +7 -0
- value_object_pattern/usables/identifiers/country_ids/__init__.py +3 -0
- value_object_pattern/usables/identifiers/country_ids/spain/__init__.py +3 -0
- value_object_pattern/usables/identifiers/country_ids/spain/dni_value_object.py +63 -0
- value_object_pattern/usables/identifiers/string_uuid_value_object.py +56 -0
- value_object_pattern/usables/identifiers/uuid_value_object.py +40 -0
- value_object_pattern/usables/internet/__init__.py +38 -0
- value_object_pattern/usables/internet/api_keys/__init__.py +13 -0
- value_object_pattern/usables/internet/api_keys/aws_access_key_id_value_object.py +40 -0
- value_object_pattern/usables/internet/api_keys/aws_secret_access_key_value_object.py +40 -0
- value_object_pattern/usables/internet/api_keys/github_personal_access_token_value_object.py +41 -0
- value_object_pattern/usables/internet/api_keys/openai_api_key_value_object.py +40 -0
- value_object_pattern/usables/internet/api_keys/resend_api_key_value_object.py +40 -0
- value_object_pattern/usables/internet/aws_cloud_region_value_object.py +77 -0
- value_object_pattern/usables/internet/domain_value_object.py +149 -0
- value_object_pattern/usables/internet/host_value_object.py +143 -0
- value_object_pattern/usables/internet/ipv4_address_value_object.py +305 -0
- value_object_pattern/usables/internet/ipv4_network_value_object.py +165 -0
- value_object_pattern/usables/internet/ipv6_address_value_object.py +288 -0
- value_object_pattern/usables/internet/ipv6_network_value_object.py +145 -0
- value_object_pattern/usables/internet/mac_address_value_object.py +390 -0
- value_object_pattern/usables/internet/port_value_object.py +682 -0
- value_object_pattern/usables/internet/uri/__init__.py +11 -0
- value_object_pattern/usables/internet/uri/http_https_url_value_object.py +39 -0
- value_object_pattern/usables/internet/uri/http_url_value_object.py +39 -0
- value_object_pattern/usables/internet/uri/https_url_value_object.py +39 -0
- value_object_pattern/usables/internet/uri/url_value_object.py +396 -0
- value_object_pattern/usables/primitives/__init__.py +45 -0
- value_object_pattern/usables/primitives/boolean/__init__.py +9 -0
- value_object_pattern/usables/primitives/boolean/boolean_value_object.py +36 -0
- value_object_pattern/usables/primitives/boolean/false_value_object.py +37 -0
- value_object_pattern/usables/primitives/boolean/true_value_object.py +37 -0
- value_object_pattern/usables/primitives/bytes/__init__.py +3 -0
- value_object_pattern/usables/primitives/bytes/bytes_value_object.py +36 -0
- value_object_pattern/usables/primitives/float/__init__.py +9 -0
- value_object_pattern/usables/primitives/float/float_value_object.py +36 -0
- value_object_pattern/usables/primitives/float/negative_float_value_object.py +37 -0
- value_object_pattern/usables/primitives/float/positive_float_value_object.py +37 -0
- value_object_pattern/usables/primitives/integer/__init__.py +13 -0
- value_object_pattern/usables/primitives/integer/even_integer_value_object.py +37 -0
- value_object_pattern/usables/primitives/integer/integer_value_object.py +36 -0
- value_object_pattern/usables/primitives/integer/negative_integer_value_object.py +37 -0
- value_object_pattern/usables/primitives/integer/odd_integer_value_object.py +37 -0
- value_object_pattern/usables/primitives/integer/positive_integer_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/__init__.py +21 -0
- value_object_pattern/usables/primitives/string/alpha_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/alphanumeric_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/digit_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/lowercase_string_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/non_empty_string_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/printable_string_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/string_value_object.py +36 -0
- value_object_pattern/usables/primitives/string/trimmed_string_value_object.py +37 -0
- value_object_pattern/usables/primitives/string/uppercase_string_value_object.py +37 -0
- value_object_pattern-0.1.0.dist-info/METADATA +95 -0
- value_object_pattern-0.1.0.dist-info/RECORD +73 -0
- value_object_pattern-0.1.0.dist-info/WHEEL +4 -0
- value_object_pattern-0.1.0.dist-info/licenses/LICENSE.md +21 -0
@@ -0,0 +1,162 @@
|
|
1
|
+
"""
|
2
|
+
DateValueObject value object.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from datetime import UTC, date, datetime
|
6
|
+
|
7
|
+
from dateutil.relativedelta import relativedelta
|
8
|
+
|
9
|
+
from value_object_pattern.decorators import validation
|
10
|
+
from value_object_pattern.models import ValueObject
|
11
|
+
|
12
|
+
|
13
|
+
class DateValueObject(ValueObject[date]):
|
14
|
+
"""
|
15
|
+
DateValueObject value object ensures the provided value is a date.
|
16
|
+
|
17
|
+
Example:
|
18
|
+
```python
|
19
|
+
from datetime import date
|
20
|
+
|
21
|
+
from value_object_pattern.usables.dates import DateValueObject
|
22
|
+
|
23
|
+
now = date(year=1900, month=1, day=1)
|
24
|
+
date_ = DateValueObject(value=now)
|
25
|
+
|
26
|
+
print(repr(date_))
|
27
|
+
# >>> DateValueObject(value=1900-01-01)
|
28
|
+
```
|
29
|
+
"""
|
30
|
+
|
31
|
+
@validation(order=0)
|
32
|
+
def _ensure_value_is_date(self, value: date) -> None:
|
33
|
+
"""
|
34
|
+
Ensures the value object value is a date.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
value (date): Value.
|
38
|
+
|
39
|
+
Raises:
|
40
|
+
TypeError: If the value is not a date.
|
41
|
+
"""
|
42
|
+
if type(value) is not date:
|
43
|
+
raise TypeError(f'DateValueObject value <<<{value}>>> must be a date. Got <<<{type(value).__name__}>>> type.') # noqa: E501 # fmt: skip
|
44
|
+
|
45
|
+
def is_today(self, *, reference_date: date | None = None) -> bool:
|
46
|
+
"""
|
47
|
+
Determines whether the stored date value is today's date.
|
48
|
+
|
49
|
+
Args:
|
50
|
+
reference_date (date | None, optional): The date to compare against. If None, the current date (UTC) is
|
51
|
+
used.
|
52
|
+
|
53
|
+
Raises:
|
54
|
+
TypeError: If the value is not a date.
|
55
|
+
TypeError: If the reference_date is not a date.
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
bool: True if the stored date matches today's date, False otherwise.
|
59
|
+
|
60
|
+
Example:
|
61
|
+
```python
|
62
|
+
from datetime import date
|
63
|
+
|
64
|
+
from value_object_pattern.usables.dates import DateValueObject
|
65
|
+
|
66
|
+
now = date(year=1900, month=1, day=1)
|
67
|
+
today = date(year=1900, month=1, day=1)
|
68
|
+
is_today = DateValueObject(value=now).is_today(reference_date=today)
|
69
|
+
|
70
|
+
print(is_today)
|
71
|
+
# >>> True
|
72
|
+
```
|
73
|
+
"""
|
74
|
+
if reference_date is None:
|
75
|
+
reference_date = datetime.now(tz=UTC).date()
|
76
|
+
|
77
|
+
DateValueObject(value=reference_date)
|
78
|
+
|
79
|
+
return self.value == reference_date
|
80
|
+
|
81
|
+
def is_in_range(self, *, start_date: date, end_date: date) -> bool:
|
82
|
+
"""
|
83
|
+
Determines whether the stored date value falls within the specified date range.
|
84
|
+
|
85
|
+
Args:
|
86
|
+
start_date (date): The beginning of the date range (inclusive).
|
87
|
+
end_date (date): The end of the date range (inclusive).
|
88
|
+
|
89
|
+
Raises:
|
90
|
+
TypeError: If start_date is not a date.
|
91
|
+
TypeError: If end_date is not a date.
|
92
|
+
ValueError: If start_date is later than end_date.
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
bool: True if the stored date is within the range, False otherwise.
|
96
|
+
|
97
|
+
Example:
|
98
|
+
```python
|
99
|
+
from datetime import date
|
100
|
+
|
101
|
+
from value_object_pattern.usables.dates import DateValueObject
|
102
|
+
|
103
|
+
now = date(year=1900, month=1, day=1)
|
104
|
+
start_date = date(year=1899, month=12, day=31)
|
105
|
+
end_date = date(year=1900, month=1, day=2)
|
106
|
+
is_in_range = DateValueObject(
|
107
|
+
value=now,
|
108
|
+
).is_in_range(
|
109
|
+
start_date=start_date,
|
110
|
+
end_date=end_date,
|
111
|
+
)
|
112
|
+
|
113
|
+
print(is_in_range)
|
114
|
+
# >>> True
|
115
|
+
```
|
116
|
+
"""
|
117
|
+
DateValueObject(value=start_date)
|
118
|
+
DateValueObject(value=end_date)
|
119
|
+
|
120
|
+
if start_date > end_date:
|
121
|
+
raise ValueError(f'DateValueObject start_date <<<{start_date.isoformat()}>>> must be earlier than or equal to end_date <<<{end_date.isoformat()}>>>.') # noqa: E501 # fmt: skip
|
122
|
+
|
123
|
+
return start_date <= self.value <= end_date
|
124
|
+
|
125
|
+
def calculate_age(self, *, reference_date: date | None = None) -> int:
|
126
|
+
"""
|
127
|
+
Calculates the age of the stored date value.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
reference_date (date | None, optional): The date to calculate the age against. If None, the current date
|
131
|
+
(UTC) is used.
|
132
|
+
|
133
|
+
Raises:
|
134
|
+
TypeError: If the reference_date is not a date.
|
135
|
+
ValueError: If the stored date is later than the reference_date.
|
136
|
+
|
137
|
+
Returns:
|
138
|
+
int: The age in years of the stored date.
|
139
|
+
|
140
|
+
Example:
|
141
|
+
```python
|
142
|
+
from datetime import date
|
143
|
+
|
144
|
+
from value_object_pattern.usables.dates import DateValueObject
|
145
|
+
|
146
|
+
now = date(year=2000, month=1, day=1)
|
147
|
+
today = date(year=2000, month=1, day=1)
|
148
|
+
age = DateValueObject(value=now).calculate_age(reference_date=today)
|
149
|
+
|
150
|
+
print(age)
|
151
|
+
# >>> 100
|
152
|
+
```
|
153
|
+
"""
|
154
|
+
if reference_date is None:
|
155
|
+
reference_date = datetime.now(tz=UTC).date()
|
156
|
+
|
157
|
+
DateValueObject(value=reference_date)
|
158
|
+
|
159
|
+
if self.value > reference_date:
|
160
|
+
raise ValueError(f'DateValueObject value <<<{self.value.isoformat()}>>> must be earlier than or equal to reference_date <<<{reference_date.isoformat()}>>>.') # noqa: E501 # fmt: skip
|
161
|
+
|
162
|
+
return relativedelta(dt1=reference_date, dt2=self.value).years
|
@@ -0,0 +1,201 @@
|
|
1
|
+
"""
|
2
|
+
StringDateValueObject value object.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from datetime import UTC, date, datetime
|
6
|
+
|
7
|
+
from dateutil.parser import ParserError, parse
|
8
|
+
from dateutil.relativedelta import relativedelta
|
9
|
+
|
10
|
+
from value_object_pattern.decorators import process, validation
|
11
|
+
from value_object_pattern.usables import NotEmptyStringValueObject, TrimmedStringValueObject
|
12
|
+
|
13
|
+
from .date_value_object import DateValueObject
|
14
|
+
|
15
|
+
|
16
|
+
class StringDateValueObject(NotEmptyStringValueObject, TrimmedStringValueObject):
|
17
|
+
"""
|
18
|
+
StringDateValueObject value object ensures the provided value is a valid date.
|
19
|
+
|
20
|
+
Example:
|
21
|
+
```python
|
22
|
+
from value_object_pattern.usables.dates import StringDateValueObject
|
23
|
+
|
24
|
+
now = '1900-01-01'
|
25
|
+
date = StringDateValueObject(value=now)
|
26
|
+
|
27
|
+
print(repr(date))
|
28
|
+
# >>> StringDateValueObject(value=1900-01-01)
|
29
|
+
```
|
30
|
+
"""
|
31
|
+
|
32
|
+
@process(order=0)
|
33
|
+
def _ensure_value_is_normalized(self, value: str) -> str:
|
34
|
+
"""
|
35
|
+
Ensures the value object value is normalized date string (ISO 8601, YYYY-MM-DD).
|
36
|
+
|
37
|
+
Args:
|
38
|
+
value (str): Value.
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
str: Value with the normalized date string.
|
42
|
+
"""
|
43
|
+
return self._date_normalize(value=value).isoformat()
|
44
|
+
|
45
|
+
@validation(order=0)
|
46
|
+
def _ensure_value_is_date(self, value: str) -> None:
|
47
|
+
"""
|
48
|
+
Ensures the value object value is a date.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
value (str): Value.
|
52
|
+
|
53
|
+
Raises:
|
54
|
+
ValueError: If the value is not a date.
|
55
|
+
"""
|
56
|
+
self._date_normalize(value=value)
|
57
|
+
|
58
|
+
@classmethod
|
59
|
+
def _date_normalize(cls, value: str) -> date:
|
60
|
+
"""
|
61
|
+
Normalizes the given date.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
value (str): Date.
|
65
|
+
|
66
|
+
Raises:
|
67
|
+
TypeError: If the value is not a string.
|
68
|
+
ValueError: If the value is not a valid date.
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
str: Normalized date.
|
72
|
+
"""
|
73
|
+
if type(value) is not str:
|
74
|
+
raise TypeError(f'StringDateValueObject value <<<{value}>>> must be a string. Got <<<{type(value).__name__}>>> type.') # noqa: E501 # fmt: skip
|
75
|
+
|
76
|
+
try:
|
77
|
+
return parse(timestr=value).date()
|
78
|
+
|
79
|
+
except ParserError as error:
|
80
|
+
raise ValueError(f'StringDateValueObject value <<<{value}>>> is not a valid date.') from error
|
81
|
+
|
82
|
+
def is_today(self, *, reference_date: date | None = None) -> bool:
|
83
|
+
"""
|
84
|
+
Determines whether the stored date value is today's date.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
reference_date (date | None, optional): The date to compare against. If None, the current date (UTC) is
|
88
|
+
used.
|
89
|
+
|
90
|
+
Raises:
|
91
|
+
TypeError: If the reference_date is not a date.
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
bool: True if the stored date matches today's date, False otherwise.
|
95
|
+
|
96
|
+
Example:
|
97
|
+
```python
|
98
|
+
from datetime import date
|
99
|
+
|
100
|
+
from value_object_pattern.usables.dates import StringDateValueObject
|
101
|
+
|
102
|
+
now = '1900-01-01'
|
103
|
+
today = date(year=1900, month=1, day=1)
|
104
|
+
is_today = StringDateValueObject(value=now).is_today(reference_date=today)
|
105
|
+
|
106
|
+
print(is_today)
|
107
|
+
# >>> True
|
108
|
+
```
|
109
|
+
"""
|
110
|
+
if reference_date is None:
|
111
|
+
reference_date = datetime.now(tz=UTC).date()
|
112
|
+
|
113
|
+
date_value = self._date_normalize(value=self.value)
|
114
|
+
DateValueObject(value=reference_date)
|
115
|
+
|
116
|
+
return date_value == reference_date
|
117
|
+
|
118
|
+
def is_in_range(self, *, start_date: date, end_date: date) -> bool:
|
119
|
+
"""
|
120
|
+
Determines whether the stored date value falls within the specified date range.
|
121
|
+
|
122
|
+
Args:
|
123
|
+
start_date (date): The beginning of the date range (inclusive).
|
124
|
+
end_date (date): The end of the date range (inclusive).
|
125
|
+
|
126
|
+
Raises:
|
127
|
+
TypeError: If start_date is not a date.
|
128
|
+
TypeError: If end_date is not a date.
|
129
|
+
ValueError: If start_date is later than end_date.
|
130
|
+
|
131
|
+
Returns:
|
132
|
+
bool: True if the stored date is within the range, False otherwise.
|
133
|
+
|
134
|
+
Example:
|
135
|
+
```python
|
136
|
+
from datetime import date
|
137
|
+
|
138
|
+
from value_object_pattern.usables.dates import StringDateValueObject
|
139
|
+
|
140
|
+
now = '1900-01-01'
|
141
|
+
start_date = date(year=1899, month=12, day=31)
|
142
|
+
end_date = date(year=1900, month=1, day=2)
|
143
|
+
is_in_range = StringDateValueObject(
|
144
|
+
value=now,
|
145
|
+
).is_in_range(
|
146
|
+
start_date=start_date,
|
147
|
+
end_date=end_date,
|
148
|
+
)
|
149
|
+
|
150
|
+
print(is_in_range)
|
151
|
+
# >>> True
|
152
|
+
```
|
153
|
+
"""
|
154
|
+
date_value = self._date_normalize(value=self.value)
|
155
|
+
DateValueObject(value=start_date)
|
156
|
+
DateValueObject(value=end_date)
|
157
|
+
|
158
|
+
if start_date > end_date:
|
159
|
+
raise ValueError(f'StringDateValueObject start_date <<<{start_date.isoformat()}>>> must be earlier than or equal to end_date <<<{end_date.isoformat()}>>>.') # noqa: E501 # fmt: skip
|
160
|
+
|
161
|
+
return start_date <= date_value <= end_date
|
162
|
+
|
163
|
+
def calculate_age(self, *, reference_date: date | None = None) -> int:
|
164
|
+
"""
|
165
|
+
Calculates the age of the stored date value.
|
166
|
+
|
167
|
+
Args:
|
168
|
+
reference_date (date | None, optional): The date to calculate the age from. If None, the current date (UTC)
|
169
|
+
is used.
|
170
|
+
|
171
|
+
Raises:
|
172
|
+
TypeError: If the reference_date is not a date.
|
173
|
+
ValueError: If the stored date is later than the reference_date.
|
174
|
+
|
175
|
+
Returns:
|
176
|
+
int: The age in years of the stored date.
|
177
|
+
|
178
|
+
Example:
|
179
|
+
```python
|
180
|
+
from datetime import date
|
181
|
+
|
182
|
+
from value_object_pattern.usables.dates import StringDateValueObject
|
183
|
+
|
184
|
+
now = '1900-01-01'
|
185
|
+
today = date(year=2000, month=1, day=1)
|
186
|
+
age = StringDateValueObject(value=now).calculate_age(reference_date=today)
|
187
|
+
|
188
|
+
print(age)
|
189
|
+
# >>> 100
|
190
|
+
```
|
191
|
+
"""
|
192
|
+
if reference_date is None:
|
193
|
+
reference_date = datetime.now(tz=UTC).date()
|
194
|
+
|
195
|
+
date_value = self._date_normalize(value=self.value)
|
196
|
+
DateValueObject(value=reference_date)
|
197
|
+
|
198
|
+
if date_value > reference_date:
|
199
|
+
raise ValueError(f'StringDateValueObject value <<<{date_value.isoformat()}>>> must be earlier than or equal to reference_date <<<{reference_date.isoformat()}>>>.') # noqa: E501 # fmt: skip
|
200
|
+
|
201
|
+
return relativedelta(dt1=reference_date, dt2=date_value).years
|
@@ -0,0 +1,193 @@
|
|
1
|
+
"""
|
2
|
+
DatetimeValueObject value object.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from datetime import UTC, datetime
|
6
|
+
|
7
|
+
from dateutil.relativedelta import relativedelta
|
8
|
+
|
9
|
+
from value_object_pattern.decorators import validation
|
10
|
+
from value_object_pattern.models import ValueObject
|
11
|
+
|
12
|
+
|
13
|
+
class DatetimeValueObject(ValueObject[datetime]):
|
14
|
+
"""
|
15
|
+
DatetimeValueObject value object ensures the provided value is a datetime.
|
16
|
+
|
17
|
+
Example:
|
18
|
+
```python
|
19
|
+
from datetime import UTC, datetime
|
20
|
+
|
21
|
+
from value_object_pattern.usables.dates import DatetimeValueObject
|
22
|
+
|
23
|
+
now = datetime(year=1900, month=1, day=1, hour=0, minute=0, second=0, tzinfo=UTC)
|
24
|
+
date = DatetimeValueObject(value=now)
|
25
|
+
|
26
|
+
print(repr(date))
|
27
|
+
# >>> DatetimeValueObject(value=1900-01-01T00:00:00+00:00)
|
28
|
+
```
|
29
|
+
"""
|
30
|
+
|
31
|
+
@validation(order=0)
|
32
|
+
def _ensure_value_is_datetime(self, value: datetime) -> None:
|
33
|
+
"""
|
34
|
+
Ensures the value object value is a datetime.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
value (datetime): Value.
|
38
|
+
|
39
|
+
Raises:
|
40
|
+
TypeError: If the value is not a datetime.
|
41
|
+
"""
|
42
|
+
if type(value) is not datetime:
|
43
|
+
raise TypeError(f'DatetimeValueObject value <<<{value}>>> must be a datetime. Got <<<{type(value).__name__}>>> type.') # noqa: E501 # fmt: skip
|
44
|
+
|
45
|
+
def is_now(self, *, reference_datetime: datetime | None = None) -> bool:
|
46
|
+
"""
|
47
|
+
Determines whether the stored datetime value matches the current datetime.
|
48
|
+
|
49
|
+
Args:
|
50
|
+
reference_datetime (datetime | None, optional): The datetime to compare against. If None, the current
|
51
|
+
datetime (UTC) is used.
|
52
|
+
|
53
|
+
Raises:
|
54
|
+
TypeError: If the reference_datetime is not a datetime.
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
bool: True if the stored datetime matches the current datetime, False otherwise.
|
58
|
+
|
59
|
+
Example:
|
60
|
+
```python
|
61
|
+
from datetime import UTC, datetime
|
62
|
+
|
63
|
+
from value_object_pattern.usables.dates import DatetimeValueObject
|
64
|
+
|
65
|
+
now = datetime(year=1900, month=1, day=1, hour=8, minute=30, second=0, tzinfo=UTC)
|
66
|
+
today = datetime(year=1900, month=1, day=1, hour=0, minute=0, second=0, tzinfo=UTC)
|
67
|
+
is_now = DatetimeValueObject(value=now).is_now(reference_datetime=today)
|
68
|
+
|
69
|
+
print(is_now)
|
70
|
+
# >>> False
|
71
|
+
```
|
72
|
+
"""
|
73
|
+
if reference_datetime is None:
|
74
|
+
reference_datetime = datetime.now(tz=UTC)
|
75
|
+
|
76
|
+
DatetimeValueObject(value=reference_datetime)
|
77
|
+
|
78
|
+
return self.value == reference_datetime
|
79
|
+
|
80
|
+
def is_today(self, *, reference_datetime: datetime | None = None) -> bool:
|
81
|
+
"""
|
82
|
+
Determines whether the stored datetime value is today's datetime.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
reference_datetime (datetime | None, optional): The datetime to compare against. If None, the current
|
86
|
+
datetime (UTC) is used.
|
87
|
+
|
88
|
+
Raises:
|
89
|
+
TypeError: If the reference_datetime is not a datetime.
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
bool: True if the stored datetime matches today's datetime, False otherwise.
|
93
|
+
|
94
|
+
Example:
|
95
|
+
```python
|
96
|
+
from datetime import UTC, datetime
|
97
|
+
|
98
|
+
from value_object_pattern.usables.dates import DatetimeValueObject
|
99
|
+
|
100
|
+
now = datetime(year=1900, month=1, day=1, hour=8, minute=30, second=0, tzinfo=UTC)
|
101
|
+
today = datetime(year=1900, month=1, day=1, hour=0, minute=0, second=0, tzinfo=UTC)
|
102
|
+
is_today = DatetimeValueObject(value=now).is_today(reference_datetime=today)
|
103
|
+
|
104
|
+
print(is_today)
|
105
|
+
# >>> True
|
106
|
+
```
|
107
|
+
"""
|
108
|
+
if reference_datetime is None:
|
109
|
+
reference_datetime = datetime.now(tz=UTC)
|
110
|
+
|
111
|
+
DatetimeValueObject(value=reference_datetime)
|
112
|
+
|
113
|
+
return self.value.date() == reference_datetime.date()
|
114
|
+
|
115
|
+
def is_in_range(self, *, start_datetime: datetime, end_datetime: datetime) -> bool:
|
116
|
+
"""
|
117
|
+
Determines whether the stored datetime value falls within the specified datetime range.
|
118
|
+
|
119
|
+
Args:
|
120
|
+
start_datetime (datetime): The beginning of the datetime range (inclusive).
|
121
|
+
end_datetime (datetime): The end of the datetime range (inclusive).
|
122
|
+
|
123
|
+
Raises:
|
124
|
+
TypeError: If start_datetime is not a datetime.
|
125
|
+
TypeError: If end_datetime is not a datetime.
|
126
|
+
ValueError: If start_datetime is later than end_datetime.
|
127
|
+
|
128
|
+
Returns:
|
129
|
+
bool: True if the stored datetime is within the range, False otherwise.
|
130
|
+
|
131
|
+
Example:
|
132
|
+
```python
|
133
|
+
from datetime import UTC, datetime
|
134
|
+
|
135
|
+
from value_object_pattern.usables.dates import DatetimeValueObject
|
136
|
+
|
137
|
+
now = datetime(year=1900, month=1, day=1, hour=0, minute=0, second=0, tzinfo=UTC)
|
138
|
+
start_datetime = datetime(year=1899, month=12, day=31, hour=23, minute=59, second=59, tzinfo=UTC)
|
139
|
+
end_datetime = datetime(year=1900, month=1, day=2, hour=00, minute=00, second=00, tzinfo=UTC)
|
140
|
+
is_in_range = DatetimeValueObject(
|
141
|
+
value=now,
|
142
|
+
).is_in_range(
|
143
|
+
start_datetime=start_datetime,
|
144
|
+
end_datetime=end_datetime,
|
145
|
+
)
|
146
|
+
|
147
|
+
print(is_in_range)
|
148
|
+
# >>> True
|
149
|
+
```
|
150
|
+
"""
|
151
|
+
DatetimeValueObject(value=start_datetime)
|
152
|
+
DatetimeValueObject(value=end_datetime)
|
153
|
+
|
154
|
+
if start_datetime > end_datetime:
|
155
|
+
raise ValueError(f'DatetimeValueObject start_datetime <<<{start_datetime.isoformat()}>>> must be earlier than or equal to end_datetime <<<{end_datetime.isoformat()}>>>.') # noqa: E501 # fmt: skip
|
156
|
+
|
157
|
+
return start_datetime <= self.value <= end_datetime
|
158
|
+
|
159
|
+
def calculate_age(self, *, reference_datetime: datetime | None = None) -> int:
|
160
|
+
"""
|
161
|
+
Calculates the age of a given datetime.
|
162
|
+
|
163
|
+
Args:
|
164
|
+
reference_datetime (datetime | None, optional): The datetime to calculate the age against. If None, the
|
165
|
+
current datetime (UTC) is used.
|
166
|
+
|
167
|
+
Raises:
|
168
|
+
TypeError: If the reference_datetime is not a datetime.
|
169
|
+
ValueError: If the stored datetime is later than the reference_datetime.
|
170
|
+
|
171
|
+
Returns:
|
172
|
+
int: The age in years of the given datetime.
|
173
|
+
|
174
|
+
Example:
|
175
|
+
```python
|
176
|
+
from datetime import UTC, datetime
|
177
|
+
|
178
|
+
from value_object_pattern.usables.dates import DatetimeValueObject
|
179
|
+
|
180
|
+
now = datetime(year=1900, month=1, day=1, hour=0, minute=0, second=0, tzinfo=UTC)
|
181
|
+
today = datetime(year=2000, month=1, day=1, hour=0, minute=0, second=0, tzinfo=UTC)
|
182
|
+
age = DatetimeValueObject(value=now).calculate_age(reference_datetime=today)
|
183
|
+
|
184
|
+
print(age)
|
185
|
+
# >>> 100
|
186
|
+
```
|
187
|
+
"""
|
188
|
+
if reference_datetime is None:
|
189
|
+
reference_datetime = datetime.now(tz=UTC)
|
190
|
+
|
191
|
+
DatetimeValueObject(value=reference_datetime)
|
192
|
+
|
193
|
+
return relativedelta(dt1=reference_datetime, dt2=self.value).years
|