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)