Changeset 1570:2043671d14fa


Ignore:
Timestamp:
Oct 4, 2014, 4:59:05 PM (7 years ago)
Author:
Stefan Schwarzer <sschwarzer@…>
Branch:
default
Message:
Handle invalid datetime components and datetimes before the epoch
(see ticket #83).

If a component of a parsed datetime is invalid (for example, day is
32), raise a `ParserError`.

If the datetime is before the epoch, set the float value for the last
modification time to 0.0 .
File:
1 edited

Legend:

Unmodified
Added
Removed
  • ftputil/stat.py

    r1568 r1570  
    1010from __future__ import unicode_literals
    1111
     12import datetime
    1213import math
    1314import re
     
    149150        return st_mode
    150151
     152    def _mktime(self, mktime_tuple):
     153        """
     154        Return a float value like `time.mktime` does, but ...
     155
     156        - Raise a `ParserError` if parts of `mktime_tuple` are
     157          invalid (say, a day is 32).
     158
     159        - If the resulting float value would be smaller than 0.0
     160          (indicating a time before the "epoch") return a sentinel
     161          value of 0.0. Do this also if the native `mktime`
     162          implementation would raise an `OverflowError`.
     163        """
     164        datetime_tuple = mktime_tuple[:6]
     165        try:
     166            # Only for sanity checks, we're not interested in the
     167            # return value.
     168            datetime.datetime(*datetime_tuple)
     169        # For example, day == 32. Not all implementations of `mktime`
     170        # catch this kind of error.
     171        except ValueError:
     172            invalid_datetime = (
     173              "{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}".format(
     174              datetime_tuple))
     175            raise ParserError("invalid datetime {0!r}".
     176                              format(invalid_datetime))
     177        try:
     178            time_float = time.mktime(mktime_tuple)
     179        except (OverflowError, ValueError):
     180            # Sentinel for times before the Epoch, see ticket #83.
     181            time_float = 0.0
     182        # Don't allow float values smaller than 0.0 because, according
     183        # to https://docs.python.org/3.4/library/time.html#module-time ,
     184        # these might be undefined for some platforms.
     185        return max(0.0, time_float)
     186
    151187    def parse_unix_time(self, month_abbreviation, day, year_or_time,
    152188                        time_shift, with_precision=False):
     
    188224            # `year_or_time` is really a year.
    189225            year, hour, minute = int(year_or_time), 0, 0
    190             st_mtime = time.mktime( (year, month, day,
    191                                      hour, minute, 0, 0, 0, -1) )
     226            st_mtime = self._mktime( (year, month, day,
     227                                      hour, minute, 0, 0, 0, -1) )
    192228            # Precise up to a day.
    193229            st_mtime_precision = 24 * 60 * 60
     
    198234            # Try the current year
    199235            year = time.localtime()[0]
    200             st_mtime = time.mktime( (year, month, day,
    201                                      hour, minute, 0, 0, 0, -1) )
     236            st_mtime = self._mktime( (year, month, day,
     237                                      hour, minute, 0, 0, 0, -1) )
    202238            # Times are precise up to a minute.
    203239            st_mtime_precision = 60
     
    216252            if st_mtime > time.time() + time_shift + st_mtime_precision:
    217253                # If it's in the future, use previous year.
    218                 st_mtime = time.mktime( (year-1, month, day,
    219                                          hour, minute, 0, 0, 0, -1) )
     254                st_mtime = self._mktime( (year-1, month, day,
     255                                          hour, minute, 0, 0, 0, -1) )
    220256        if with_precision:
    221257            return st_mtime, st_mtime_precision
Note: See TracChangeset for help on using the changeset viewer.