annotate libervia/backend/tools/xmpp_datetime.py @ 4306:94e0968987cd

plugin XEP-0033: code modernisation, improve delivery, data validation: - Code has been rewritten using Pydantic models and `async` coroutines for data validation and cleaner element parsing/generation. - Delivery has been completely rewritten. It now works even if server doesn't support multicast, and send to local multicast service first. Delivering to local multicast service first is due to bad support of XEP-0033 in server (notably Prosody which has an incomplete implementation), and the current impossibility to detect if a sub-domain service handles fully multicast or only for local domains. This is a workaround to have a good balance between backward compatilibity and use of bandwith, and to make it work with the incoming email gateway implementation (the gateway will only deliver to entities of its own domain). - disco feature checking now uses `async` corountines. `host` implementation still use Deferred return values for compatibility with legacy code. rel 450
author Goffi <goffi@goffi.org>
date Thu, 26 Sep 2024 16:12:01 +0200
parents 0d7bb4df2343
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
1 #!/usr/bin/env python3
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
2
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
3 # Libervia: XMPP Date and Time profiles as per XEP-0082
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
4 # Copyright (C) 2022-2022 Tim Henkes (me@syndace.dev)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
5
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
6 # This program is free software: you can redistribute it and/or modify
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
7 # it under the terms of the GNU Affero General Public License as published by
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
8 # the Free Software Foundation, either version 3 of the License, or
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
9 # (at your option) any later version.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
10
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
11 # This program is distributed in the hope that it will be useful,
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
14 # GNU Affero General Public License for more details.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
15
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
16 # You should have received a copy of the GNU Affero General Public License
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
18
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
19 from datetime import date, datetime, time, timezone
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
20 import re
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
21 from typing import Optional, Tuple
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
22
4071
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 3933
diff changeset
23 from libervia.backend.core import exceptions
3911
8289ac1b34f4 plugin XEP-0384: Fully reworked to adjust to the reworked python-omemo:
Syndace <me@syndace.dev>
parents: 3879
diff changeset
24
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
25
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
26 __all__ = [ # pylint: disable=unused-variable
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
27 "format_date",
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
28 "parse_date",
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
29 "format_datetime",
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
30 "parse_datetime",
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
31 "format_time",
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
32 "parse_time",
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
33 ]
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
34
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
35
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
36 def __parse_fraction_of_a_second(value: str) -> Tuple[str, Optional[int]]:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
37 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
38 datetime's strptime only supports up to six digits of the fraction of a seconds, while
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
39 the XEP-0082 specification allows for any number of digits. This function parses and
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
40 removes the optional fraction of a second from the input string.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
41
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
42 @param value: The input string, containing a section of the format [.sss].
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
43 @return: The input string with the fraction of a second removed, and the fraction of a
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
44 second parsed with microsecond resolution. Returns the unaltered input string and
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
45 ``None`` if no fraction of a second was found in the input string.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
46 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
47
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
48 # The following regex matches the optional fraction of a seconds for manual
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
49 # processing.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
50 match = re.search(r"\.(\d*)", value)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
51 microsecond: Optional[int] = None
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
52 if match is not None:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
53 # Remove the fraction of a second from the input string
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
54 value = value[: match.start()] + value[match.end() :]
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
55
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
56 # datetime supports microsecond resolution for the fraction of a second, thus
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
57 # limit/pad the parsed fraction of a second to six digits
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
58 microsecond = int(match.group(1)[:6].ljust(6, "0"))
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
59
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
60 return value, microsecond
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
61
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
62
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
63 def format_date(value: Optional[date] = None) -> str:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
64 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
65 @param value: The date for format. Defaults to the current date in the UTC timezone.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
66 @return: The date formatted according to the Date profile specified in XEP-0082.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
67
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
68 @warning: Formatting of the current date in the local timezone may leak geographical
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
69 information of the sender. Thus, it is advised to only format the current date in
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
70 UTC.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
71 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
72 # CCYY-MM-DD
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
73
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
74 # The Date profile of XEP-0082 is equal to the ISO 8601 format.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
75 return (datetime.now(timezone.utc).date() if value is None else value).isoformat()
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
76
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
77
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
78 def parse_date(value: str) -> date:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
79 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
80 @param value: A string containing date information formatted according to the Date
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
81 profile specified in XEP-0082.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
82 @return: The date parsed from the input string.
3933
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
83 @raise exceptions.ParsingError: if the input string is not correctly formatted.
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
84 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
85 # CCYY-MM-DD
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
86
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
87 # The Date profile of XEP-0082 is equal to the ISO 8601 format.
3933
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
88 try:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
89 return date.fromisoformat(value)
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
90 except ValueError as e:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
91 raise exceptions.ParsingError() from e
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
92
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
93
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
94 def format_datetime(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
95 value: Optional[datetime] = None, include_microsecond: bool = False
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
96 ) -> str:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
97 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
98 @param value: The datetime to format. Defaults to the current datetime.
3878
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
99 must be an aware datetime object (timezone must be specified)
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
100 @param include_microsecond: Include the microsecond of the datetime in the output.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
101 @return: The datetime formatted according to the DateTime profile specified in
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
102 XEP-0082. The datetime is always converted to UTC before formatting to avoid
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
103 leaking geographical information of the sender.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
104 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
105 # CCYY-MM-DDThh:mm:ss[.sss]TZD
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
106
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
107 # We format the time in UTC, since the %z formatter of strftime doesn't include colons
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
108 # to separate hours and minutes which is required by XEP-0082. UTC allows us to put a
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
109 # simple letter 'Z' as the time zone definition.
3878
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
110 if value is not None:
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
111 if value.tzinfo is None:
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
112 raise exceptions.InternalError(
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
113 "an aware datetime object must be used, but a naive one has been provided"
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
114 )
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
115 value = value.astimezone(timezone.utc) # pylint: disable=no-member
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
116 else:
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
117 value = datetime.now(timezone.utc)
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
118
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
119 if include_microsecond:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
120 return value.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
121
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
122 return value.strftime("%Y-%m-%dT%H:%M:%SZ")
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
123
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
124
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
125 def parse_datetime(value: str) -> datetime:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
126 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
127 @param value: A string containing datetime information formatted according to the
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
128 DateTime profile specified in XEP-0082.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
129 @return: The datetime parsed from the input string.
3933
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
130 @raise exceptions.ParsingError: if the input string is not correctly formatted.
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
131 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
132 # CCYY-MM-DDThh:mm:ss[.sss]TZD
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
133
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
134 value, microsecond = __parse_fraction_of_a_second(value)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
135
3933
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
136 try:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
137 result = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S%z")
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
138 except ValueError as e:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
139 raise exceptions.ParsingError() from e
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
140
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
141 if microsecond is not None:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
142 result = result.replace(microsecond=microsecond)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
143
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
144 return result
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
145
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
146
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
147 def format_time(value: Optional[time] = None, include_microsecond: bool = False) -> str:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
148 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
149 @param value: The time to format. Defaults to the current time in the UTC timezone.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
150 @param include_microsecond: Include the microsecond of the time in the output.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
151 @return: The time formatted according to the Time profile specified in XEP-0082.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
152
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
153 @warning: Since accurate timezone conversion requires the date to be known, this
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
154 function cannot convert input times to UTC before formatting. This means that
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
155 geographical information of the sender may be leaked if a time in local timezone
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
156 is formatted. Thus, when passing a time to format, it is advised to pass the time
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
157 in UTC if possible.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
158 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
159 # hh:mm:ss[.sss][TZD]
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
160
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
161 if value is None:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
162 # There is no time.now() method as one might expect, but the current time can be
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
163 # extracted from a datetime object including time zone information.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
164 value = datetime.now(timezone.utc).timetz()
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
165
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
166 # The format created by time.isoformat complies with the XEP-0082 Time profile.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
167 return value.isoformat("auto" if include_microsecond else "seconds")
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
168
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
169
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
170 def parse_time(value: str) -> time:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
171 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
172 @param value: A string containing time information formatted according to the Time
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
173 profile specified in XEP-0082.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
174 @return: The time parsed from the input string.
3933
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
175 @raise exceptions.ParsingError: if the input string is not correctly formatted.
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
176 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
177 # hh:mm:ss[.sss][TZD]
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
178
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
179 value, microsecond = __parse_fraction_of_a_second(value)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
180
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
181 # The format parsed by time.fromisoformat mostly complies with the XEP-0082 Time
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
182 # profile, except that it doesn't handle the letter Z as time zone information for
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
183 # UTC. This can be fixed with a simple string replacement of 'Z' with "+00:00", which
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
184 # is another way to represent UTC.
3933
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
185 try:
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
186 result = time.fromisoformat(value.replace("Z", "+00:00"))
3933
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
187 except ValueError as e:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
188 raise exceptions.ParsingError() from e
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
189
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
190 if microsecond is not None:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
191 result = result.replace(microsecond=microsecond)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
192
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
193 return result