代码之家  ›  专栏  ›  技术社区  ›  user1283776

简化处理当前使用datetime和isodate的时间和持续时间的代码?

  •  1
  • user1283776  · 技术社区  · 6 年前

    下面的代码应该是:

    • 验证持续时间不为空,不为负,不超过10年

    输入字符串示例如下:

    duration_string = "P10W"
    duration_string = "P1Y"
    

    这是密码

        duration = isodate.parse_duration(duration_string)
    
        if isinstance(duration, datetime.timedelta):
            if not duration > datetime.timedelta(0):
                raise Exception('duration invalid')
            if duration > datetime.timedelta(3660):
                raise Exception('duration cannot be longer than 10 years')
        elif isinstance(duration, isodate.Duration):
            if not duration > 0:
                raise Exception('duration invalid')
            if duration > isodate.duration.Duration(0, 0, 0, years=10, months=0):
                log.debug("duration %s isodate %s" % (duration, isodate.duration.Duration(0, 0, 0, years=10, months=0)))
                raise Exception('duration cannot be longer than 10 years')
    

    有没有比我制造的怪物更简单的方法呢?

    除了需要简化,这条线 duration > isodate.duration.Duration(0, 0, 0, years=10, months=0)

    我使用的是python2.7

    2 回复  |  直到 6 年前
        1
  •  1
  •   FHTMitchell    6 年前

    好的,所以如果你必须使用isodate持续时间解析,保持 isodate

    但是,如果您必须使用他们的解析工具,这可能是一个好方法。

    import isodate
    import functools
    
    @functools.total_ordering  # if we implement < ==, will implement <=, >, >=
    class Duration(isodate.Duration):
        # inherit from isodate.Duration -- gives us ==
    
        # constants 
        seconds_in_day = 60**2 * 24
        approx_days_in_month = 30
        approx_days_in_year = 365
    
        def approx_total_seconds(self):
            """approx total seconds in duration"""
            # self.months and self.years are stored as `Decimal`s for some reason...
            return self.tdelta.total_seconds() \
                   + float(self.months) * self.approx_days_in_month *  self.seconds_in_day \
                   + float(self.years) * self.approx_days_in_year * self.seconds_in_day
    
        def __lt__(self, other):
            """defines self < other"""
            if not isinstance(other, Duration):
                return NotImplemented
            return self.approx_total_seconds() < other.approx_total_seconds()
    
        @classmethod
        def parse_duration(cls, datestring):
            """a version of isodate.parse_duration that returns out class"""
    
            iso_dur = isodate.parse_duration(datestring)
    
            # iso_date.parse_duration can return either a Duration or a timedelta...
            if isinstance(iso_dur, isodate.Duration):
                return cls(seconds=iso_dur.tdelta.total_seconds(),
                           months=iso_dur.months, years=iso_dur.years)
            else:
                return cls(seconds=iso_dur.total_seconds())
    
    
    ten_weeks = Duration.parse_duration('P10W')
    one_year = Duration.parse_duration('P1Y')
    
    print(ten_weeks.approx_total_seconds())
    print(one_year.approx_total_seconds())
    
    print(ten_weeks < one_year)
    print(ten_weeks > one_year)
    

    6048000.0
    31536000.0
    True
    False
    

    如果你不需要isodate解析(我猜你不需要),你可以这样做

    @functools.TotalOrdering
    class ApproxTimeDelta:
    
        approx_days_in_week = 7
        approx_days_in_month = 30
        approx_days_in_year = 365
    
        def __init__(self, days, weeks, months, years):
            self.days = days + \
                        weeks * self.approx_days_in_week + \
                        months * self.approx_days_in_month + \
                        years * self.approx_days_in_year
    
        def __eq__(self, other):
            return self.days == other.days
    
        def __lt__(self, other):
            return self.days < other.days
    

        2
  •  0
  •   user1283776    6 年前

    下面是我最终使用的另一种解决方案:

        if isinstance(duration, datetime.timedelta):
            if not duration > 0:
                raise Exception('duration invalid')
            if duration > 3650:
                raise Exception('maximum duration is 3650 days')
        elif isinstance(duration, isodate.Duration):
            if duration.years > 10:
                raise Exception('maximum duration is 10 years')
            if duration.months > 120:
                raise Exception('maximum duration is 120 months')