mercurial/utils/dateutil.py
changeset 46641 15c2f9220ae8
parent 46419 6894c9ef4dcd
child 48875 6000f5b25c9b
equal deleted inserted replaced
46640:e571fec5b606 46641:15c2f9220ae8
    15 from .. import (
    15 from .. import (
    16     encoding,
    16     encoding,
    17     error,
    17     error,
    18     pycompat,
    18     pycompat,
    19 )
    19 )
       
    20 
       
    21 if pycompat.TYPE_CHECKING:
       
    22     from typing import (
       
    23         Callable,
       
    24         Dict,
       
    25         Iterable,
       
    26         Optional,
       
    27         Tuple,
       
    28         Union,
       
    29     )
       
    30 
       
    31     hgdate = Tuple[float, int]  # (unixtime, offset)
    20 
    32 
    21 # used by parsedate
    33 # used by parsedate
    22 defaultdateformats = (
    34 defaultdateformats = (
    23     b'%Y-%m-%dT%H:%M:%S',  # the 'real' ISO8601
    35     b'%Y-%m-%dT%H:%M:%S',  # the 'real' ISO8601
    24     b'%Y-%m-%dT%H:%M',  #   without seconds
    36     b'%Y-%m-%dT%H:%M',  #   without seconds
    60     b"%b %Y",
    72     b"%b %Y",
    61 )
    73 )
    62 
    74 
    63 
    75 
    64 def makedate(timestamp=None):
    76 def makedate(timestamp=None):
       
    77     # type: (Optional[float]) -> hgdate
    65     """Return a unix timestamp (or the current time) as a (unixtime,
    78     """Return a unix timestamp (or the current time) as a (unixtime,
    66     offset) tuple based off the local timezone."""
    79     offset) tuple based off the local timezone."""
    67     if timestamp is None:
    80     if timestamp is None:
    68         timestamp = time.time()
    81         timestamp = time.time()
    69     if timestamp < 0:
    82     if timestamp < 0:
    77     tz = delta.days * 86400 + delta.seconds
    90     tz = delta.days * 86400 + delta.seconds
    78     return timestamp, tz
    91     return timestamp, tz
    79 
    92 
    80 
    93 
    81 def datestr(date=None, format=b'%a %b %d %H:%M:%S %Y %1%2'):
    94 def datestr(date=None, format=b'%a %b %d %H:%M:%S %Y %1%2'):
       
    95     # type: (Optional[hgdate], bytes) -> bytes
    82     """represent a (unixtime, offset) tuple as a localized time.
    96     """represent a (unixtime, offset) tuple as a localized time.
    83     unixtime is seconds since the epoch, and offset is the time zone's
    97     unixtime is seconds since the epoch, and offset is the time zone's
    84     number of seconds away from UTC.
    98     number of seconds away from UTC.
    85 
    99 
    86     >>> datestr((0, 0))
   100     >>> datestr((0, 0))
   114     s = encoding.strtolocal(t.strftime(encoding.strfromlocal(format)))
   128     s = encoding.strtolocal(t.strftime(encoding.strfromlocal(format)))
   115     return s
   129     return s
   116 
   130 
   117 
   131 
   118 def shortdate(date=None):
   132 def shortdate(date=None):
       
   133     # type: (Optional[hgdate]) -> bytes
   119     """turn (timestamp, tzoff) tuple into iso 8631 date."""
   134     """turn (timestamp, tzoff) tuple into iso 8631 date."""
   120     return datestr(date, format=b'%Y-%m-%d')
   135     return datestr(date, format=b'%Y-%m-%d')
   121 
   136 
   122 
   137 
   123 def parsetimezone(s):
   138 def parsetimezone(s):
       
   139     # type: (bytes) -> Tuple[Optional[int], bytes]
   124     """find a trailing timezone, if any, in string, and return a
   140     """find a trailing timezone, if any, in string, and return a
   125     (offset, remainder) pair"""
   141     (offset, remainder) pair"""
   126     s = pycompat.bytestr(s)
   142     s = pycompat.bytestr(s)
   127 
   143 
   128     if s.endswith(b"GMT") or s.endswith(b"UTC"):
   144     if s.endswith(b"GMT") or s.endswith(b"UTC"):
   154 
   170 
   155     return None, s
   171     return None, s
   156 
   172 
   157 
   173 
   158 def strdate(string, format, defaults=None):
   174 def strdate(string, format, defaults=None):
       
   175     # type: (bytes, bytes, Optional[Dict[bytes, Tuple[bytes, bytes]]]) -> hgdate
   159     """parse a localized time string and return a (unixtime, offset) tuple.
   176     """parse a localized time string and return a (unixtime, offset) tuple.
   160     if the string cannot be parsed, ValueError is raised."""
   177     if the string cannot be parsed, ValueError is raised."""
   161     if defaults is None:
   178     if defaults is None:
   162         defaults = {}
   179         defaults = {}
   163 
   180 
   196         unixtime = localunixtime + offset
   213         unixtime = localunixtime + offset
   197     return unixtime, offset
   214     return unixtime, offset
   198 
   215 
   199 
   216 
   200 def parsedate(date, formats=None, bias=None):
   217 def parsedate(date, formats=None, bias=None):
       
   218     # type: (Union[bytes, hgdate], Optional[Iterable[bytes]], Optional[Dict[bytes, bytes]]) -> hgdate
   201     """parse a localized date/time and return a (unixtime, offset) tuple.
   219     """parse a localized date/time and return a (unixtime, offset) tuple.
   202 
   220 
   203     The date may be a "unixtime offset" string or in one of the specified
   221     The date may be a "unixtime offset" string or in one of the specified
   204     formats. If the date already is a (unixtime, offset) tuple, it is returned.
   222     formats. If the date already is a (unixtime, offset) tuple, it is returned.
   205 
   223 
   221     """
   239     """
   222     if bias is None:
   240     if bias is None:
   223         bias = {}
   241         bias = {}
   224     if not date:
   242     if not date:
   225         return 0, 0
   243         return 0, 0
   226     if isinstance(date, tuple) and len(date) == 2:
   244     if isinstance(date, tuple):
   227         return date
   245         if len(date) == 2:
       
   246             return date
       
   247         else:
       
   248             raise error.ProgrammingError(b"invalid date format")
   228     if not formats:
   249     if not formats:
   229         formats = defaultdateformats
   250         formats = defaultdateformats
   230     date = date.strip()
   251     date = date.strip()
   231 
   252 
   232     if date == b'now' or date == _(b'now'):
   253     if date == b'now' or date == _(b'now'):
   282         raise error.ParseError(_(b'impossible time zone offset: %d') % offset)
   303         raise error.ParseError(_(b'impossible time zone offset: %d') % offset)
   283     return when, offset
   304     return when, offset
   284 
   305 
   285 
   306 
   286 def matchdate(date):
   307 def matchdate(date):
       
   308     # type: (bytes) -> Callable[[float], bool]
   287     """Return a function that matches a given date match specifier
   309     """Return a function that matches a given date match specifier
   288 
   310 
   289     Formats include:
   311     Formats include:
   290 
   312 
   291     '{date}' match a given date to the accuracy provided
   313     '{date}' match a given date to the accuracy provided
   311     >>> f(p5[0])
   333     >>> f(p5[0])
   312     False
   334     False
   313     """
   335     """
   314 
   336 
   315     def lower(date):
   337     def lower(date):
       
   338         # type: (bytes) -> float
   316         d = {b'mb': b"1", b'd': b"1"}
   339         d = {b'mb': b"1", b'd': b"1"}
   317         return parsedate(date, extendeddateformats, d)[0]
   340         return parsedate(date, extendeddateformats, d)[0]
   318 
   341 
   319     def upper(date):
   342     def upper(date):
       
   343         # type: (bytes) -> float
   320         d = {b'mb': b"12", b'HI': b"23", b'M': b"59", b'S': b"59"}
   344         d = {b'mb': b"12", b'HI': b"23", b'M': b"59", b'S': b"59"}
   321         for days in (b"31", b"30", b"29"):
   345         for days in (b"31", b"30", b"29"):
   322             try:
   346             try:
   323                 d[b"d"] = days
   347                 d[b"d"] = days
   324                 return parsedate(date, extendeddateformats, d)[0]
   348                 return parsedate(date, extendeddateformats, d)[0]