Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/aniso8601/time.py: 18%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
3# Copyright (c) 2025, Brandon Nielsen
4# All rights reserved.
5#
6# This software may be modified and distributed under the terms
7# of the BSD license. See the LICENSE file for details.
9from aniso8601.builders import TupleBuilder
10from aniso8601.builders.python import PythonTimeBuilder
11from aniso8601.compat import is_string
12from aniso8601.date import parse_date
13from aniso8601.decimalfraction import normalize
14from aniso8601.exceptions import ISOFormatError
15from aniso8601.resolution import TimeResolution
16from aniso8601.timezone import parse_timezone
18TIMEZONE_DELIMITERS = ["Z", "+", "-"]
21def get_time_resolution(isotimestr):
22 # Valid time formats are:
23 #
24 # hh:mm:ss
25 # hhmmss
26 # hh:mm
27 # hhmm
28 # hh
29 # hh:mm:ssZ
30 # hhmmssZ
31 # hh:mmZ
32 # hhmmZ
33 # hhZ
34 # hh:mm:ss±hh:mm
35 # hhmmss±hh:mm
36 # hh:mm±hh:mm
37 # hhmm±hh:mm
38 # hh±hh:mm
39 # hh:mm:ss±hhmm
40 # hhmmss±hhmm
41 # hh:mm±hhmm
42 # hhmm±hhmm
43 # hh±hhmm
44 # hh:mm:ss±hh
45 # hhmmss±hh
46 # hh:mm±hh
47 # hhmm±hh
48 # hh±hh
49 isotimetuple = parse_time(isotimestr, builder=TupleBuilder)
51 return _get_time_resolution(isotimetuple)
54def get_datetime_resolution(isodatetimestr, delimiter="T"):
55 # <date>T<time>
56 #
57 # Time part cannot be omitted so return time resolution
58 isotimetuple = parse_datetime(
59 isodatetimestr, delimiter=delimiter, builder=TupleBuilder
60 ).time
62 return _get_time_resolution(isotimetuple)
65def _get_time_resolution(isotimetuple):
66 if isotimetuple.ss is not None:
67 return TimeResolution.Seconds
69 if isotimetuple.mm is not None:
70 return TimeResolution.Minutes
72 return TimeResolution.Hours
75def parse_time(isotimestr, builder=PythonTimeBuilder):
76 # Given a string in any ISO 8601 time format, return a datetime.time object
77 # that corresponds to the given time. Fixed offset tzdata will be included
78 # if UTC offset is given in the input string. Valid time formats are:
79 #
80 # hh:mm:ss
81 # hhmmss
82 # hh:mm
83 # hhmm
84 # hh
85 # hh:mm:ssZ
86 # hhmmssZ
87 # hh:mmZ
88 # hhmmZ
89 # hhZ
90 # hh:mm:ss±hh:mm
91 # hhmmss±hh:mm
92 # hh:mm±hh:mm
93 # hhmm±hh:mm
94 # hh±hh:mm
95 # hh:mm:ss±hhmm
96 # hhmmss±hhmm
97 # hh:mm±hhmm
98 # hhmm±hhmm
99 # hh±hhmm
100 # hh:mm:ss±hh
101 # hhmmss±hh
102 # hh:mm±hh
103 # hhmm±hh
104 # hh±hh
105 if is_string(isotimestr) is False:
106 raise ValueError("Time must be string.")
108 if len(isotimestr) == 0:
109 raise ISOFormatError('"{0}" is not a valid ISO 8601 time.'.format(isotimestr))
111 timestr = normalize(isotimestr)
113 hourstr = None
114 minutestr = None
115 secondstr = None
116 tzstr = None
118 fractionalstr = None
120 # Split out the timezone
121 for delimiter in TIMEZONE_DELIMITERS:
122 delimiteridx = timestr.find(delimiter)
124 if delimiteridx != -1:
125 tzstr = timestr[delimiteridx:]
126 timestr = timestr[0:delimiteridx]
128 # Split out the fractional component
129 if timestr.find(".") != -1:
130 timestr, fractionalstr = timestr.split(".", 1)
132 if fractionalstr.isdigit() is False:
133 raise ISOFormatError(
134 '"{0}" is not a valid ISO 8601 time.'.format(isotimestr)
135 )
137 if len(timestr) == 2:
138 # hh
139 hourstr = timestr
140 elif len(timestr) == 4 or len(timestr) == 5:
141 # hh:mm
142 # hhmm
143 if timestr.count(":") == 1:
144 hourstr, minutestr = timestr.split(":")
145 else:
146 hourstr = timestr[0:2]
147 minutestr = timestr[2:]
148 elif len(timestr) == 6 or len(timestr) == 8:
149 # hh:mm:ss
150 # hhmmss
151 if timestr.count(":") == 2:
152 hourstr, minutestr, secondstr = timestr.split(":")
153 else:
154 hourstr = timestr[0:2]
155 minutestr = timestr[2:4]
156 secondstr = timestr[4:]
157 else:
158 raise ISOFormatError('"{0}" is not a valid ISO 8601 time.'.format(isotimestr))
160 for componentstr in [hourstr, minutestr, secondstr]:
161 if componentstr is not None and componentstr.isdigit() is False:
162 raise ISOFormatError(
163 '"{0}" is not a valid ISO 8601 time.'.format(isotimestr)
164 )
166 if fractionalstr is not None:
167 if secondstr is not None:
168 secondstr = secondstr + "." + fractionalstr
169 elif minutestr is not None:
170 minutestr = minutestr + "." + fractionalstr
171 else:
172 hourstr = hourstr + "." + fractionalstr
174 if tzstr is None:
175 tz = None
176 else:
177 tz = parse_timezone(tzstr, builder=TupleBuilder)
179 return builder.build_time(hh=hourstr, mm=minutestr, ss=secondstr, tz=tz)
182def parse_datetime(isodatetimestr, delimiter="T", builder=PythonTimeBuilder):
183 # Given a string in ISO 8601 date time format, return a datetime.datetime
184 # object that corresponds to the given date time.
185 # By default, the ISO 8601 specified T delimiter is used to split the
186 # date and time (<date>T<time>). Fixed offset tzdata will be included
187 # if UTC offset is given in the input string.
188 if is_string(isodatetimestr) is False:
189 raise ValueError("Date time must be string.")
191 if delimiter not in isodatetimestr:
192 raise ISOFormatError(
193 'Delimiter "{0}" is not in combined date time '
194 'string "{1}".'.format(delimiter, isodatetimestr)
195 )
197 isodatestr, isotimestr = isodatetimestr.split(delimiter, 1)
199 datepart = parse_date(isodatestr, builder=TupleBuilder)
201 timepart = parse_time(isotimestr, builder=TupleBuilder)
203 return builder.build_datetime(datepart, timepart)