Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/utils/dateutil.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | d4d2c567bb72 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
18 pycompat, | 18 pycompat, |
19 ) | 19 ) |
20 | 20 |
21 # used by parsedate | 21 # used by parsedate |
22 defaultdateformats = ( | 22 defaultdateformats = ( |
23 '%Y-%m-%dT%H:%M:%S', # the 'real' ISO8601 | 23 '%Y-%m-%dT%H:%M:%S', # the 'real' ISO8601 |
24 '%Y-%m-%dT%H:%M', # without seconds | 24 '%Y-%m-%dT%H:%M', # without seconds |
25 '%Y-%m-%dT%H%M%S', # another awful but legal variant without : | 25 '%Y-%m-%dT%H%M%S', # another awful but legal variant without : |
26 '%Y-%m-%dT%H%M', # without seconds | 26 '%Y-%m-%dT%H%M', # without seconds |
27 '%Y-%m-%d %H:%M:%S', # our common legal variant | 27 '%Y-%m-%d %H:%M:%S', # our common legal variant |
28 '%Y-%m-%d %H:%M', # without seconds | 28 '%Y-%m-%d %H:%M', # without seconds |
29 '%Y-%m-%d %H%M%S', # without : | 29 '%Y-%m-%d %H%M%S', # without : |
30 '%Y-%m-%d %H%M', # without seconds | 30 '%Y-%m-%d %H%M', # without seconds |
31 '%Y-%m-%d %I:%M:%S%p', | 31 '%Y-%m-%d %I:%M:%S%p', |
32 '%Y-%m-%d %H:%M', | 32 '%Y-%m-%d %H:%M', |
33 '%Y-%m-%d %I:%M%p', | 33 '%Y-%m-%d %I:%M%p', |
34 '%Y-%m-%d', | 34 '%Y-%m-%d', |
35 '%m-%d', | 35 '%m-%d', |
36 '%m/%d', | 36 '%m/%d', |
37 '%m/%d/%y', | 37 '%m/%d/%y', |
38 '%m/%d/%Y', | 38 '%m/%d/%Y', |
39 '%a %b %d %H:%M:%S %Y', | 39 '%a %b %d %H:%M:%S %Y', |
40 '%a %b %d %I:%M:%S%p %Y', | 40 '%a %b %d %I:%M:%S%p %Y', |
41 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822" | 41 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822" |
42 '%b %d %H:%M:%S %Y', | 42 '%b %d %H:%M:%S %Y', |
43 '%b %d %I:%M:%S%p %Y', | 43 '%b %d %I:%M:%S%p %Y', |
44 '%b %d %H:%M:%S', | 44 '%b %d %H:%M:%S', |
45 '%b %d %I:%M:%S%p', | 45 '%b %d %I:%M:%S%p', |
46 '%b %d %H:%M', | 46 '%b %d %H:%M', |
51 '%I:%M:%S%p', | 51 '%I:%M:%S%p', |
52 '%H:%M', | 52 '%H:%M', |
53 '%I:%M%p', | 53 '%I:%M%p', |
54 ) | 54 ) |
55 | 55 |
56 extendeddateformats = defaultdateformats + ( | 56 extendeddateformats = defaultdateformats + ("%Y", "%Y-%m", "%b", "%b %Y",) |
57 "%Y", | 57 |
58 "%Y-%m", | |
59 "%b", | |
60 "%b %Y", | |
61 ) | |
62 | 58 |
63 def makedate(timestamp=None): | 59 def makedate(timestamp=None): |
64 '''Return a unix timestamp (or the current time) as a (unixtime, | 60 '''Return a unix timestamp (or the current time) as a (unixtime, |
65 offset) tuple based off the local timezone.''' | 61 offset) tuple based off the local timezone.''' |
66 if timestamp is None: | 62 if timestamp is None: |
67 timestamp = time.time() | 63 timestamp = time.time() |
68 if timestamp < 0: | 64 if timestamp < 0: |
69 hint = _("check your clock") | 65 hint = _("check your clock") |
70 raise error.Abort(_("negative timestamp: %d") % timestamp, hint=hint) | 66 raise error.Abort(_("negative timestamp: %d") % timestamp, hint=hint) |
71 delta = (datetime.datetime.utcfromtimestamp(timestamp) - | 67 delta = datetime.datetime.utcfromtimestamp( |
72 datetime.datetime.fromtimestamp(timestamp)) | 68 timestamp |
69 ) - datetime.datetime.fromtimestamp(timestamp) | |
73 tz = delta.days * 86400 + delta.seconds | 70 tz = delta.days * 86400 + delta.seconds |
74 return timestamp, tz | 71 return timestamp, tz |
72 | |
75 | 73 |
76 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'): | 74 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'): |
77 """represent a (unixtime, offset) tuple as a localized time. | 75 """represent a (unixtime, offset) tuple as a localized time. |
78 unixtime is seconds since the epoch, and offset is the time zone's | 76 unixtime is seconds since the epoch, and offset is the time zone's |
79 number of seconds away from UTC. | 77 number of seconds away from UTC. |
96 q, r = divmod(minutes, 60) | 94 q, r = divmod(minutes, 60) |
97 format = format.replace("%z", "%1%2") | 95 format = format.replace("%z", "%1%2") |
98 format = format.replace("%1", "%c%02d" % (sign, q)) | 96 format = format.replace("%1", "%c%02d" % (sign, q)) |
99 format = format.replace("%2", "%02d" % r) | 97 format = format.replace("%2", "%02d" % r) |
100 d = t - tz | 98 d = t - tz |
101 if d > 0x7fffffff: | 99 if d > 0x7FFFFFFF: |
102 d = 0x7fffffff | 100 d = 0x7FFFFFFF |
103 elif d < -0x80000000: | 101 elif d < -0x80000000: |
104 d = -0x80000000 | 102 d = -0x80000000 |
105 # Never use time.gmtime() and datetime.datetime.fromtimestamp() | 103 # Never use time.gmtime() and datetime.datetime.fromtimestamp() |
106 # because they use the gmtime() system call which is buggy on Windows | 104 # because they use the gmtime() system call which is buggy on Windows |
107 # for negative values. | 105 # for negative values. |
108 t = datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=d) | 106 t = datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=d) |
109 s = encoding.strtolocal(t.strftime(encoding.strfromlocal(format))) | 107 s = encoding.strtolocal(t.strftime(encoding.strfromlocal(format))) |
110 return s | 108 return s |
111 | 109 |
110 | |
112 def shortdate(date=None): | 111 def shortdate(date=None): |
113 """turn (timestamp, tzoff) tuple into iso 8631 date.""" | 112 """turn (timestamp, tzoff) tuple into iso 8631 date.""" |
114 return datestr(date, format='%Y-%m-%d') | 113 return datestr(date, format='%Y-%m-%d') |
114 | |
115 | 115 |
116 def parsetimezone(s): | 116 def parsetimezone(s): |
117 """find a trailing timezone, if any, in string, and return a | 117 """find a trailing timezone, if any, in string, and return a |
118 (offset, remainder) pair""" | 118 (offset, remainder) pair""" |
119 s = pycompat.bytestr(s) | 119 s = pycompat.bytestr(s) |
131 # ISO8601 trailing Z | 131 # ISO8601 trailing Z |
132 if s.endswith("Z") and s[-2:-1].isdigit(): | 132 if s.endswith("Z") and s[-2:-1].isdigit(): |
133 return 0, s[:-1] | 133 return 0, s[:-1] |
134 | 134 |
135 # ISO8601-style [+-]hh:mm | 135 # ISO8601-style [+-]hh:mm |
136 if (len(s) >= 6 and s[-6] in "+-" and s[-3] == ":" and | 136 if ( |
137 s[-5:-3].isdigit() and s[-2:].isdigit()): | 137 len(s) >= 6 |
138 and s[-6] in "+-" | |
139 and s[-3] == ":" | |
140 and s[-5:-3].isdigit() | |
141 and s[-2:].isdigit() | |
142 ): | |
138 sign = (s[-6] == "+") and 1 or -1 | 143 sign = (s[-6] == "+") and 1 or -1 |
139 hours = int(s[-5:-3]) | 144 hours = int(s[-5:-3]) |
140 minutes = int(s[-2:]) | 145 minutes = int(s[-2:]) |
141 return -sign * (hours * 60 + minutes) * 60, s[:-6] | 146 return -sign * (hours * 60 + minutes) * 60, s[:-6] |
142 | 147 |
143 return None, s | 148 return None, s |
149 | |
144 | 150 |
145 def strdate(string, format, defaults=None): | 151 def strdate(string, format, defaults=None): |
146 """parse a localized time string and return a (unixtime, offset) tuple. | 152 """parse a localized time string and return a (unixtime, offset) tuple. |
147 if the string cannot be parsed, ValueError is raised.""" | 153 if the string cannot be parsed, ValueError is raised.""" |
148 if defaults is None: | 154 if defaults is None: |
150 | 156 |
151 # NOTE: unixtime = localunixtime + offset | 157 # NOTE: unixtime = localunixtime + offset |
152 offset, date = parsetimezone(string) | 158 offset, date = parsetimezone(string) |
153 | 159 |
154 # add missing elements from defaults | 160 # add missing elements from defaults |
155 usenow = False # default to using biased defaults | 161 usenow = False # default to using biased defaults |
156 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity | 162 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity |
157 part = pycompat.bytestr(part) | 163 part = pycompat.bytestr(part) |
158 found = [True for p in part if ("%"+p) in format] | 164 found = [True for p in part if ("%" + p) in format] |
159 if not found: | 165 if not found: |
160 date += "@" + defaults[part][usenow] | 166 date += "@" + defaults[part][usenow] |
161 format += "@%" + part[0] | 167 format += "@%" + part[0] |
162 else: | 168 else: |
163 # We've found a specific time element, less specific time | 169 # We've found a specific time element, less specific time |
164 # elements are relative to today | 170 # elements are relative to today |
165 usenow = True | 171 usenow = True |
166 | 172 |
167 timetuple = time.strptime(encoding.strfromlocal(date), | 173 timetuple = time.strptime( |
168 encoding.strfromlocal(format)) | 174 encoding.strfromlocal(date), encoding.strfromlocal(format) |
175 ) | |
169 localunixtime = int(calendar.timegm(timetuple)) | 176 localunixtime = int(calendar.timegm(timetuple)) |
170 if offset is None: | 177 if offset is None: |
171 # local timezone | 178 # local timezone |
172 unixtime = int(time.mktime(timetuple)) | 179 unixtime = int(time.mktime(timetuple)) |
173 offset = unixtime - localunixtime | 180 offset = unixtime - localunixtime |
174 else: | 181 else: |
175 unixtime = localunixtime + offset | 182 unixtime = localunixtime + offset |
176 return unixtime, offset | 183 return unixtime, offset |
184 | |
177 | 185 |
178 def parsedate(date, formats=None, bias=None): | 186 def parsedate(date, formats=None, bias=None): |
179 """parse a localized date/time and return a (unixtime, offset) tuple. | 187 """parse a localized date/time and return a (unixtime, offset) tuple. |
180 | 188 |
181 The date may be a "unixtime offset" string or in one of the specified | 189 The date may be a "unixtime offset" string or in one of the specified |
209 return makedate() | 217 return makedate() |
210 if date == 'today' or date == _('today'): | 218 if date == 'today' or date == _('today'): |
211 date = datetime.date.today().strftime(r'%b %d') | 219 date = datetime.date.today().strftime(r'%b %d') |
212 date = encoding.strtolocal(date) | 220 date = encoding.strtolocal(date) |
213 elif date == 'yesterday' or date == _('yesterday'): | 221 elif date == 'yesterday' or date == _('yesterday'): |
214 date = (datetime.date.today() - | 222 date = (datetime.date.today() - datetime.timedelta(days=1)).strftime( |
215 datetime.timedelta(days=1)).strftime(r'%b %d') | 223 r'%b %d' |
224 ) | |
216 date = encoding.strtolocal(date) | 225 date = encoding.strtolocal(date) |
217 | 226 |
218 try: | 227 try: |
219 when, offset = map(int, date.split(' ')) | 228 when, offset = map(int, date.split(' ')) |
220 except ValueError: | 229 except ValueError: |
242 pass | 251 pass |
243 else: | 252 else: |
244 break | 253 break |
245 else: | 254 else: |
246 raise error.ParseError( | 255 raise error.ParseError( |
247 _('invalid date: %r') % pycompat.bytestr(date)) | 256 _('invalid date: %r') % pycompat.bytestr(date) |
257 ) | |
248 # validate explicit (probably user-specified) date and | 258 # validate explicit (probably user-specified) date and |
249 # time zone offset. values must fit in signed 32 bits for | 259 # time zone offset. values must fit in signed 32 bits for |
250 # current 32-bit linux runtimes. timezones go from UTC-12 | 260 # current 32-bit linux runtimes. timezones go from UTC-12 |
251 # to UTC+14 | 261 # to UTC+14 |
252 if when < -0x80000000 or when > 0x7fffffff: | 262 if when < -0x80000000 or when > 0x7FFFFFFF: |
253 raise error.ParseError(_('date exceeds 32 bits: %d') % when) | 263 raise error.ParseError(_('date exceeds 32 bits: %d') % when) |
254 if offset < -50400 or offset > 43200: | 264 if offset < -50400 or offset > 43200: |
255 raise error.ParseError(_('impossible time zone offset: %d') % offset) | 265 raise error.ParseError(_('impossible time zone offset: %d') % offset) |
256 return when, offset | 266 return when, offset |
267 | |
257 | 268 |
258 def matchdate(date): | 269 def matchdate(date): |
259 """Return a function that matches a given date match specifier | 270 """Return a function that matches a given date match specifier |
260 | 271 |
261 Formats include: | 272 Formats include: |
317 try: | 328 try: |
318 days = int(date[1:]) | 329 days = int(date[1:]) |
319 except ValueError: | 330 except ValueError: |
320 raise error.Abort(_("invalid day spec: %s") % date[1:]) | 331 raise error.Abort(_("invalid day spec: %s") % date[1:]) |
321 if days < 0: | 332 if days < 0: |
322 raise error.Abort(_("%s must be nonnegative (see 'hg help dates')") | 333 raise error.Abort( |
323 % date[1:]) | 334 _("%s must be nonnegative (see 'hg help dates')") % date[1:] |
335 ) | |
324 when = makedate()[0] - days * 3600 * 24 | 336 when = makedate()[0] - days * 3600 * 24 |
325 return lambda x: x >= when | 337 return lambda x: x >= when |
326 elif b" to " in date: | 338 elif b" to " in date: |
327 a, b = date.split(b" to ") | 339 a, b = date.split(b" to ") |
328 start, stop = lower(a), upper(b) | 340 start, stop = lower(a), upper(b) |