annotate sat/tools/xmpp_datetime.py @ 3976:db45d49518f6

plugin XEP-0384: log `import_error` when import is failing
author Goffi <goffi@goffi.org>
date Thu, 10 Nov 2022 15:16:43 +0100
parents cecf45416403
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
3911
8289ac1b34f4 plugin XEP-0384: Fully reworked to adjust to the reworked python-omemo:
Syndace <me@syndace.dev>
parents: 3879
diff changeset
23 from sat.core import exceptions
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",
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
32 "parse_time"
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
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
54 value = value[:match.start()] + value[match.end():]
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
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
58 microsecond = int(match.group(1)[:6].ljust(6, '0'))
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(
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
95 value: Optional[datetime] = None,
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
96 include_microsecond: bool = False
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
97 ) -> str:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
98 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
99 @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
100 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
101 @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
102 @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
103 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
104 leaking geographical information of the sender.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
105 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
106 # CCYY-MM-DDThh:mm:ss[.sss]TZD
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
107
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
108 # 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
109 # 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
110 # 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
111 if value is not None:
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
112 if value.tzinfo is None:
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
113 raise exceptions.InternalError(
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
114 "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
115 )
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
116 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
117 else:
32087d7c25d4 tools (datetime, utils): fix incorrect use of naive object:
Goffi <goffi@goffi.org>
parents: 3877
diff changeset
118 value = datetime.now(timezone.utc)
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
119
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
120 if include_microsecond:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
121 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
122
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
123 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
124
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
125
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
126 def parse_datetime(value: str) -> datetime:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
127 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
128 @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
129 DateTime profile specified in XEP-0082.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
130 @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
131 @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
132 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
133 # CCYY-MM-DDThh:mm:ss[.sss]TZD
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
134
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
135 value, microsecond = __parse_fraction_of_a_second(value)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
136
3933
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
137 try:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
138 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
139 except ValueError as e:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
140 raise exceptions.ParsingError() from e
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
141
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
142 if microsecond is not None:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
143 result = result.replace(microsecond=microsecond)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
144
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
145 return result
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
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
148 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
149 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
150 @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
151 @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
152 @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
153
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
154 @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
155 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
156 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
157 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
158 in UTC if possible.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
159 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
160 # hh:mm:ss[.sss][TZD]
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
161
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
162 if value is None:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
163 # 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
164 # 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
165 value = datetime.now(timezone.utc).timetz()
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
166
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
167 # 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
168 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
169
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
170
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
171 def parse_time(value: str) -> time:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
172 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
173 @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
174 profile specified in XEP-0082.
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
175 @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
176 @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
177 """
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
178 # hh:mm:ss[.sss][TZD]
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
179
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
180 value, microsecond = __parse_fraction_of_a_second(value)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
181
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
182 # 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
183 # 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
184 # 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
185 # 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
186 try:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
187 result = time.fromisoformat(value.replace('Z', "+00:00"))
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
188 except ValueError as e:
cecf45416403 plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM:
Syndace <me@syndace.dev>
parents: 3911
diff changeset
189 raise exceptions.ParsingError() from e
3877
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
190
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
191 if microsecond is not None:
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
192 result = result.replace(microsecond=microsecond)
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
193
00212260f659 plugin XEP-0420: Implementation of Stanza Content Encryption:
Syndace <me@syndace.dev>
parents:
diff changeset
194 return result