Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/isodate/isotzinfo.py: 25%

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

44 statements  

1"""This module provides an ISO 8601:2004 time zone info parser. 

2 

3It offers a function to parse the time zone offset as specified by ISO 8601. 

4""" 

5 

6import re 

7from datetime import datetime, tzinfo 

8from typing import Union 

9 

10from isodate.isoerror import ISO8601Error 

11from isodate.tzinfo import UTC, ZERO, FixedOffset, Utc 

12 

13TZ_REGEX = r"(?P<tzname>(Z|(?P<tzsign>[+-])" r"(?P<tzhour>[0-9]{2})(:?(?P<tzmin>[0-9]{2}))?)?)" 

14 

15TZ_RE = re.compile(TZ_REGEX) 

16 

17 

18def build_tzinfo( 

19 tzname: Union[str, None], tzsign: str = "+", tzhour: float = 0, tzmin: float = 0 

20) -> Union[FixedOffset, Utc, None]: 

21 """ 

22 create a tzinfo instance according to given parameters. 

23 

24 tzname: 

25 'Z' ... return UTC 

26 '' | None ... return None 

27 other ... return FixedOffset 

28 """ 

29 if tzname is None or tzname == "": 

30 return None 

31 if tzname == "Z": 

32 return UTC 

33 tzsignum = ((tzsign == "-") and -1) or 1 

34 return FixedOffset(tzsignum * tzhour, tzsignum * tzmin, tzname) 

35 

36 

37def parse_tzinfo(tzstring: str) -> Union[tzinfo, None]: 

38 """Parses ISO 8601 time zone designators to tzinfo objects. 

39 

40 A time zone designator can be in the following format: 

41 no designator indicates local time zone 

42 Z UTC 

43 +-hhmm basic hours and minutes 

44 +-hh:mm extended hours and minutes 

45 +-hh hours 

46 """ 

47 match = TZ_RE.match(tzstring) 

48 if match: 

49 groups = match.groupdict() 

50 return build_tzinfo( 

51 groups["tzname"], 

52 groups["tzsign"], 

53 int(groups["tzhour"] or 0), 

54 int(groups["tzmin"] or 0), 

55 ) 

56 raise ISO8601Error("%s not a valid time zone info" % tzstring) 

57 

58 

59def tz_isoformat(dt: datetime, format: str = "%Z") -> str: 

60 """Return time zone offset ISO 8601 formatted. 

61 

62 The various ISO formats can be chosen with the format parameter. 

63 

64 if tzinfo is None returns '' 

65 if tzinfo is UTC returns 'Z' 

66 else the offset is rendered to the given format. 

67 format: 

68 %h ... +-HH 

69 %z ... +-HHMM 

70 %Z ... +-HH:MM 

71 """ 

72 tzinfo = dt.tzinfo 

73 if (tzinfo is None) or (tzinfo.utcoffset(dt) is None): 

74 return "" 

75 if tzinfo.utcoffset(dt) == ZERO and tzinfo.dst(dt) == ZERO: 

76 return "Z" 

77 tdelta = tzinfo.utcoffset(dt) 

78 if tdelta is None: 

79 return "" 

80 seconds = tdelta.days * 24 * 60 * 60 + tdelta.seconds 

81 sign = ((seconds < 0) and "-") or "+" 

82 seconds = abs(seconds) 

83 minutes, seconds = divmod(seconds, 60) 

84 hours, minutes = divmod(minutes, 60) 

85 if hours > 99: 

86 raise OverflowError("can not handle differences > 99 hours") 

87 if format == "%Z": 

88 return "%s%02d:%02d" % (sign, hours, minutes) 

89 elif format == "%z": 

90 return "%s%02d%02d" % (sign, hours, minutes) 

91 elif format == "%h": 

92 return "%s%02d" % (sign, hours) 

93 raise ValueError('unknown format string "%s"' % format)