]> git.proxmox.com Git - ceph.git/blame - ceph/src/python-common/ceph/utils.py
import ceph 15.2.14
[ceph.git] / ceph / src / python-common / ceph / utils.py
CommitLineData
adb31ebb
TL
1import datetime
2import re
3
6d8e3169
FG
4from typing import Optional
5
adb31ebb
TL
6
7def datetime_now() -> datetime.datetime:
8 """
9 Return the current local date and time.
10 :return: Returns an aware datetime object of the current date
11 and time.
12 """
13 return datetime.datetime.now(tz=datetime.timezone.utc)
14
15
16def datetime_to_str(dt: datetime.datetime) -> str:
17 """
18 Convert a datetime object into a ISO 8601 string, e.g.
19 '2019-04-24T17:06:53.039991Z'.
20 :param dt: The datetime object to process.
21 :return: Return a string representing the date in
22 ISO 8601 (timezone=UTC).
23 """
24 return dt.astimezone(tz=datetime.timezone.utc).strftime(
25 '%Y-%m-%dT%H:%M:%S.%fZ')
26
27
28def str_to_datetime(string: str) -> datetime.datetime:
29 """
30 Convert an ISO 8601 string into a datetime object.
31 The following formats are supported:
32
33 - 2020-03-03T09:21:43.636153304Z
34 - 2020-03-03T15:52:30.136257504-0600
35 - 2020-03-03T15:52:30.136257504
36
37 :param string: The string to parse.
38 :return: Returns an aware datetime object of the given date
39 and time string.
40 :raises: :exc:`~exceptions.ValueError` for an unknown
41 datetime string.
42 """
43 fmts = [
44 '%Y-%m-%dT%H:%M:%S.%f',
45 '%Y-%m-%dT%H:%M:%S.%f%z'
46 ]
47
48 # In *all* cases, the 9 digit second precision is too much for
49 # Python's strptime. Shorten it to 6 digits.
50 p = re.compile(r'(\.[\d]{6})[\d]*')
51 string = p.sub(r'\1', string)
52
53 # Replace trailing Z with -0000, since (on Python 3.6.8) it
54 # won't parse.
55 if string and string[-1] == 'Z':
56 string = string[:-1] + '-0000'
57
58 for fmt in fmts:
59 try:
60 dt = datetime.datetime.strptime(string, fmt)
61 # Make sure the datetime object is aware (timezone is set).
62 # If not, then assume the time is in UTC.
63 if dt.tzinfo is None:
64 dt = dt.replace(tzinfo=datetime.timezone.utc)
65 return dt
66 except ValueError:
67 pass
68
69 raise ValueError("Time data {} does not match one of the formats {}".format(
70 string, str(fmts)))
6d8e3169
FG
71
72
73def parse_timedelta(delta: str) -> Optional[datetime.timedelta]:
74 """
75 Returns a timedelta object represents a duration, the difference
76 between two dates or times.
77
78 >>> parse_timedelta('foo')
79
80 >>> parse_timedelta('2d')
81 datetime.timedelta(days=2)
82
83 >>> parse_timedelta("4w")
84 datetime.timedelta(days=28)
85
86 >>> parse_timedelta("5s")
87 datetime.timedelta(seconds=5)
88
89 >>> parse_timedelta("-5s")
90 datetime.timedelta(days=-1, seconds=86395)
91
92 :param delta: The string to process, e.g. '2h', '10d', '30s'.
93 :return: The `datetime.timedelta` object or `None` in case of
94 a parsing error.
95 """
96 parts = re.match(r'(?P<seconds>-?\d+)s|'
97 r'(?P<minutes>-?\d+)m|'
98 r'(?P<hours>-?\d+)h|'
99 r'(?P<days>-?\d+)d|'
100 r'(?P<weeks>-?\d+)w$',
101 delta,
102 re.IGNORECASE)
103 if not parts:
104 return None
105 parts = parts.groupdict() # type: ignore
106 args = {name: int(param) for name, param in parts.items() if param} # type: ignore
107 return datetime.timedelta(**args)