Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/isodate/isotime.py: 24%
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"""
2This modules provides a method to parse an ISO 8601:2004 time string to a
3Python datetime.time instance.
5It supports all basic and extended formats including time zone specifications
6as described in the ISO standard.
7"""
9import re
10from datetime import time
11from decimal import ROUND_FLOOR, Decimal
13from isodate.isoerror import ISO8601Error
14from isodate.isostrf import TIME_EXT_COMPLETE, TZ_EXT, strftime
15from isodate.isotzinfo import TZ_REGEX, build_tzinfo
17TIME_REGEX_CACHE = []
18# used to cache regular expressions to parse ISO time strings.
21def build_time_regexps():
22 """
23 Build regular expressions to parse ISO time string.
25 The regular expressions are compiled and stored in TIME_REGEX_CACHE
26 for later reuse.
27 """
28 if not TIME_REGEX_CACHE:
29 # ISO 8601 time representations allow decimal fractions on least
30 # significant time component. Command and Full Stop are both valid
31 # fraction separators.
32 # The letter 'T' is allowed as time designator in front of a time
33 # expression.
34 # Immediately after a time expression, a time zone definition is
35 # allowed.
36 # a TZ may be missing (local time), be a 'Z' for UTC or a string of
37 # +-hh:mm where the ':mm' part can be skipped.
38 # TZ information patterns:
39 # ''
40 # Z
41 # +-hh:mm
42 # +-hhmm
43 # +-hh =>
44 # isotzinfo.TZ_REGEX
45 def add_re(regex_text):
46 TIME_REGEX_CACHE.append(re.compile(r"\A" + regex_text + TZ_REGEX + r"\Z"))
48 # 1. complete time:
49 # hh:mm:ss.ss ... extended format
50 add_re(
51 r"T?(?P<hour>[0-9]{2}):"
52 r"(?P<minute>[0-9]{2}):"
53 r"(?P<second>[0-9]{2}"
54 r"([,.][0-9]+)?)"
55 )
56 # hhmmss.ss ... basic format
57 add_re(
58 r"T?(?P<hour>[0-9]{2})"
59 r"(?P<minute>[0-9]{2})"
60 r"(?P<second>[0-9]{2}"
61 r"([,.][0-9]+)?)"
62 )
63 # 2. reduced accuracy:
64 # hh:mm.mm ... extended format
65 add_re(r"T?(?P<hour>[0-9]{2}):" r"(?P<minute>[0-9]{2}" r"([,.][0-9]+)?)")
66 # hhmm.mm ... basic format
67 add_re(r"T?(?P<hour>[0-9]{2})" r"(?P<minute>[0-9]{2}" r"([,.][0-9]+)?)")
68 # hh.hh ... basic format
69 add_re(r"T?(?P<hour>[0-9]{2}" r"([,.][0-9]+)?)")
70 return TIME_REGEX_CACHE
73def parse_time(timestring):
74 """
75 Parses ISO 8601 times into datetime.time objects.
77 Following ISO 8601 formats are supported:
78 (as decimal separator a ',' or a '.' is allowed)
79 hhmmss.ssTZD basic complete time
80 hh:mm:ss.ssTZD extended complete time
81 hhmm.mmTZD basic reduced accuracy time
82 hh:mm.mmTZD extended reduced accuracy time
83 hh.hhTZD basic reduced accuracy time
84 TZD is the time zone designator which can be in the following format:
85 no designator indicates local time zone
86 Z UTC
87 +-hhmm basic hours and minutes
88 +-hh:mm extended hours and minutes
89 +-hh hours
90 """
91 isotimes = build_time_regexps()
92 for pattern in isotimes:
93 match = pattern.match(timestring)
94 if match:
95 groups = match.groupdict()
96 for key, value in groups.items():
97 if value is not None:
98 groups[key] = value.replace(",", ".")
99 tzinfo = build_tzinfo(
100 groups["tzname"],
101 groups["tzsign"],
102 int(groups["tzhour"] or 0),
103 int(groups["tzmin"] or 0),
104 )
105 if "second" in groups:
106 second = Decimal(groups["second"]).quantize(
107 Decimal(".000001"), rounding=ROUND_FLOOR
108 )
109 microsecond = (second - int(second)) * int(1e6)
110 # int(...) ... no rounding
111 # to_integral() ... rounding
112 return time(
113 int(groups["hour"]),
114 int(groups["minute"]),
115 int(second),
116 int(microsecond.to_integral()),
117 tzinfo,
118 )
119 if "minute" in groups:
120 minute = Decimal(groups["minute"])
121 second = Decimal((minute - int(minute)) * 60).quantize(
122 Decimal(".000001"), rounding=ROUND_FLOOR
123 )
124 microsecond = (second - int(second)) * int(1e6)
125 return time(
126 int(groups["hour"]),
127 int(minute),
128 int(second),
129 int(microsecond.to_integral()),
130 tzinfo,
131 )
132 else:
133 microsecond, second, minute = 0, 0, 0
134 hour = Decimal(groups["hour"])
135 minute = (hour - int(hour)) * 60
136 second = (minute - int(minute)) * 60
137 microsecond = (second - int(second)) * int(1e6)
138 return time(
139 int(hour),
140 int(minute),
141 int(second),
142 int(microsecond.to_integral()),
143 tzinfo,
144 )
145 raise ISO8601Error("Unrecognised ISO 8601 time format: %r" % timestring)
148def time_isoformat(ttime, format=TIME_EXT_COMPLETE + TZ_EXT):
149 """
150 Format time strings.
152 This method is just a wrapper around isodate.isostrf.strftime and uses
153 Time-Extended-Complete with extended time zone as default format.
154 """
155 return strftime(ttime, format)