【问题标题】:User-friendly time format in Python?Python中用户友好的时间格式?
【发布时间】:2009-10-11 18:28:45
【问题描述】:

Python:我需要以“1 天前”、“2 小时前”的格式显示文件修改时间。

有什么可以做的吗?应该是英文的。

【问题讨论】:

    标签: python datetime date time formatting


    【解决方案1】:

    代码最初发表在一篇博文“Python Pretty Date function”(http://evaisse.com/post/93417709/python-pretty-date-function)上

    由于博客帐户已被暂停,页面不再可用,因此在此转载。

    def pretty_date(time=False):
        """
        Get a datetime object or a int() Epoch timestamp and return a
        pretty string like 'an hour ago', 'Yesterday', '3 months ago',
        'just now', etc
        """
        from datetime import datetime
        now = datetime.now()
        if type(time) is int:
            diff = now - datetime.fromtimestamp(time)
        elif isinstance(time, datetime):
            diff = now - time
        elif not time:
            diff = 0
        second_diff = diff.seconds
        day_diff = diff.days
    
        if day_diff < 0:
            return ''
    
        if day_diff == 0:
            if second_diff < 10:
                return "just now"
            if second_diff < 60:
                return str(second_diff) + " seconds ago"
            if second_diff < 120:
                return "a minute ago"
            if second_diff < 3600:
                return str(second_diff // 60) + " minutes ago"
            if second_diff < 7200:
                return "an hour ago"
            if second_diff < 86400:
                return str(second_diff // 3600) + " hours ago"
        if day_diff == 1:
            return "Yesterday"
        if day_diff < 7:
            return str(day_diff) + " days ago"
        if day_diff < 31:
            return str(day_diff // 7) + " weeks ago"
        if day_diff < 365:
            return str(day_diff // 30) + " months ago"
        return str(day_diff // 365) + " years ago"
    

    【讨论】:

    • 这是根据我的确切需求量身定制的。谢谢!
    • 链接已不存在,并给予禁止。此处需要永久链接或将内容移到此帖子中。
    • @Chris:感谢提醒,它仍在 Google 缓存中,所以我抓住了它。
    • 这对我不起作用。我收到此错误:为什么在赋值之前引用了局部变量 'diff'?
    【解决方案2】:

    如果您碰巧使用Django,那么 1.4 版中的新功能是naturaltime 模板过滤器。

    要使用它,首先将'django.contrib.humanize' 添加到settings.py 中的INSTALLED_APPS 设置,然后将{% load humanize %} 添加到您使用过滤器的模板中。

    然后,在您的模板中,如果您有一个日期时间变量my_date,您可以使用{{ my_date|naturaltime }} 打印它与现在的距离,它将呈现为4 minutes ago 之类的东西。

    Other new things in Django 1.4.

    Documentation for naturaltime and other filters in the django.contrib.humanize set.

    【讨论】:

    • 真的有必要将它添加到 INSTALLED_APPS 吗?虽然我在 python 中使用了过滤器,而不是模板
    • 我可以使用这个内部视图
    【解决方案3】:

    在寻找具有处理未来日期的附加要求的相同内容时,我发现了这一点: http://pypi.python.org/pypi/py-pretty/1

    示例代码(来自网站):

    from datetime import datetime, timedelta
    now = datetime.now()
    hrago = now - timedelta(hours=1)
    yesterday = now - timedelta(days=1)
    tomorrow = now + timedelta(days=1)
    dayafter = now + timedelta(days=2)
    
    import pretty
    print pretty.date(now)                      # 'now'
    print pretty.date(hrago)                    # 'an hour ago'
    print pretty.date(hrago, short=True)        # '1h ago'
    print pretty.date(hrago, asdays=True)       # 'today'
    print pretty.date(yesterday, short=True)    # 'yest'
    print pretty.date(tomorrow)                 # 'tomorrow'
    

    【讨论】:

    • 不幸的是 py-pretty 似乎不允许 i18n。
    【解决方案4】:

    您也可以使用 arrow 包来做到这一点

    来自github page

    >>> import arrow
    >>> utc = arrow.utcnow()
    >>> utc = utc.shift(hours=-1)
    >>> utc.humanize()
    'an hour ago'
    

    【讨论】:

      【解决方案5】:

      humanize package

      >>> from datetime import datetime, timedelta
      >>> import humanize # $ pip install humanize
      >>> humanize.naturaltime(datetime.now() - timedelta(days=1))
      'a day ago'
      >>> humanize.naturaltime(datetime.now() - timedelta(hours=2))
      '2 hours ago'
      

      支持本地化,国际化

      >>> _ = humanize.i18n.activate('ru_RU')
      >>> print humanize.naturaltime(datetime.now() - timedelta(days=1))
      день назад
      >>> print humanize.naturaltime(datetime.now() - timedelta(hours=2))
      2 часа назад
      

      【讨论】:

      • 请注意humanize 不支持时区感知日期时间;您必须使用 dt.astimezone().replace(tzinfo=None) 将这些 via 转换为幼稚的(在当地时区)。
      【解决方案6】:

      Jed Smith 链接的答案很好,我用了一年左右,但我认为它可以在几个方面进行改进:

      • 很高兴能够根据前面的单位定义每个时间单位,而不是像 3600、86400 等“魔法”常量散布在整个代码中。
      • 用了很多次之后,我发现我并不想那么急切地去下一个单元。示例:7 天和 13 天都将显示为“1 周”;我宁愿看到“7 天”或“13 天”。

      这是我想出的:

      def PrettyRelativeTime(time_diff_secs):
          # Each tuple in the sequence gives the name of a unit, and the number of
          # previous units which go into it.
          weeks_per_month = 365.242 / 12 / 7
          intervals = [('minute', 60), ('hour', 60), ('day', 24), ('week', 7),
                       ('month', weeks_per_month), ('year', 12)]
      
          unit, number = 'second', abs(time_diff_secs)
          for new_unit, ratio in intervals:
              new_number = float(number) / ratio
              # If the new number is too small, don't go to the next unit.
              if new_number < 2:
                  break
              unit, number = new_unit, new_number
          shown_num = int(number)
          return '{} {}'.format(shown_num, unit + ('' if shown_num == 1 else 's'))
      

      注意intervals 中的每个元组如何易于解释和检查:'minute'60 秒; 'hour'60 分钟;等等。唯一的软糖是将weeks_per_month设置为其平均值;鉴于应用程序,那应该没问题。 (请注意,最后三个常数一目了然,乘以 365.242,即每年的天数。)

      我的函数的一个缺点是它不执行“## 单位”模式之外的任何操作:“昨天”、“刚刚”等。再说一次,原始发帖人并没有要求这些花哨的术语,所以我更喜欢我的函数,因为它的简洁性和数值常数的可读性。 :)

      【讨论】:

      • 不错的解决方案。保持简单允许更多的重用。例如,可以使用后缀表示相对时间 value + " ago" 或持续时间 value + " left"
      【解决方案7】:

      ago 包提供了这一点。在 datetime 对象上调用 human 以获得人类可读的差异描述。

      from ago import human
      from datetime import datetime
      from datetime import timedelta
      
      ts = datetime.now() - timedelta(days=1, hours=5)
      
      print(human(ts))
      # 1 day, 5 hours ago
      
      print(human(ts, precision=1))
      # 1 day ago
      

      【讨论】:

        【解决方案8】:

        将日期时间对象与 tzinfo 一起使用:

        def time_elapsed(etime):
            # need to add tzinfo to datetime.utcnow
            now = datetime.utcnow().replace(tzinfo=etime.tzinfo)
            opened_for = (now - etime).total_seconds()
            names = ["seconds","minutes","hours","days","weeks","months"]
            modulos = [ 1,60,3600,3600*24,3600*24*7,3660*24*30]
            values = []
            for m in modulos[::-1]:
                values.append(int(opened_for / m))
                opened_for -= values[-1]*m
            pretty = [] 
            for i,nm in enumerate(names[::-1]):
                if values[i]!=0:
                    pretty.append("%i %s" % (values[i],nm))
            return " ".join(pretty)
        

        【讨论】:

          【解决方案9】:

          我已经在http://sunilarora.org/17329071 上写了一篇详细的博客文章来解决这个问题 我也在这里发布了一个快速的 sn-p。

          from datetime import datetime
          from dateutil.relativedelta import relativedelta
          
          def get_fancy_time(d, display_full_version = False):
              """Returns a user friendly date format
              d: some datetime instace in the past
              display_second_unit: True/False
              """
              #some helpers lambda's
              plural = lambda x: 's' if x > 1 else ''
              singular = lambda x: x[:-1]
              #convert pluran (years) --> to singular (year)
              display_unit = lambda unit, name: '%s %s%s'%(unit, name, plural(unit)) if unit > 0 else ''
          
              #time units we are interested in descending order of significance
              tm_units = ['years', 'months', 'days', 'hours', 'minutes', 'seconds']
          
              rdelta = relativedelta(datetime.utcnow(), d) #capture the date difference
              for idx, tm_unit in enumerate(tm_units):
                  first_unit_val = getattr(rdelta, tm_unit)
                  if first_unit_val > 0:
                      primary_unit = display_unit(first_unit_val, singular(tm_unit))
                      if display_full_version and idx < len(tm_units)-1:
                          next_unit = tm_units[idx + 1]
                          second_unit_val = getattr(rdelta, next_unit)
                          if second_unit_val > 0:
                              secondary_unit = display_unit(second_unit_val, singular(next_unit))
                              return primary_unit + ', '  + secondary_unit
                      return primary_unit
              return None
          

          【讨论】:

            【解决方案10】:
            DAY_INCREMENTS = [
                [365, "year"],
                [30, "month"],
                [7, "week"],
                [1, "day"],
            ]
            
            SECOND_INCREMENTS = [
                [3600, "hour"],
                [60, "minute"],
                [1, "second"],
            ]
            
            
            def time_ago(dt):
                diff = datetime.now() - dt  # use timezone.now() or equivalent if `dt` is timezone aware
                if diff.days < 0:
                    return "in the future?!?"
                for increment, label in DAY_INCREMENTS:
                    if diff.days >= increment:
                        increment_diff = int(diff.days / increment)
                        return str(increment_diff) + " " + label + plural(increment_diff) + " ago"
                for increment, label in SECOND_INCREMENTS:
                    if diff.seconds >= increment:
                        increment_diff = int(diff.seconds / increment)
                        return str(increment_diff) + " " + label + plural(increment_diff) + " ago"
                return "just now"
            
            
            def plural(num):
                if num != 1:
                    return "s"
                return ""
            

            【讨论】:

              【解决方案11】:

              这是@sunil 帖子的要点

              >>> from datetime import datetime
              >>> from dateutil.relativedelta import relativedelta
              >>> then = datetime(2003, 9, 17, 20, 54, 47, 282310)
              >>> relativedelta(then, datetime.now())
              relativedelta(years=-11, months=-3, days=-9, hours=-18, minutes=-17, seconds=-8, microseconds=+912664)
              

              【讨论】:

                【解决方案12】:

                您可以从以下链接下载和安装。它应该对你更有帮助。它一直在提供用户友好的信息。

                经过很好的测试。

                https://github.com/nareshchaudhary37/timestamp_content

                以下步骤安装到您的虚拟环境中。

                git clone https://github.com/nareshchaudhary37/timestamp_content
                cd timestamp-content
                python setup.py
                

                【讨论】:

                  【解决方案13】:

                  这是基于 Jed Smith 的实现的更新答案,该实现正确处理了偏移天真和偏移感知日期时间。您还可以提供默认时区。 Python 3.5+。

                  import datetime
                  
                  def pretty_date(time=None, default_timezone=datetime.timezone.utc):
                      """
                      Get a datetime object or a int() Epoch timestamp and return a
                      pretty string like 'an hour ago', 'Yesterday', '3 months ago',
                      'just now', etc
                      """
                  
                      # Assumes all timezone naive dates are UTC
                      if time.tzinfo is None or time.tzinfo.utcoffset(time) is None:
                          if default_timezone:
                              time = time.replace(tzinfo=default_timezone)
                  
                      now = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc)
                  
                      if type(time) is int:
                          diff = now - datetime.fromtimestamp(time)
                      elif isinstance(time, datetime.datetime):
                          diff = now - time
                      elif not time:
                          diff = now - now
                      second_diff = diff.seconds
                      day_diff = diff.days
                  
                      if day_diff < 0:
                          return ''
                  
                      if day_diff == 0:
                          if second_diff < 10:
                              return "just now"
                          if second_diff < 60:
                              return str(second_diff) + " seconds ago"
                          if second_diff < 120:
                              return "a minute ago"
                          if second_diff < 3600:
                              return str(second_diff / 60) + " minutes ago"
                          if second_diff < 7200:
                              return "an hour ago"
                          if second_diff < 86400:
                              return str(second_diff / 3600) + " hours ago"
                      if day_diff == 1:
                          return "Yesterday"
                      if day_diff < 7:
                          return str(day_diff) + " days ago"
                      if day_diff < 31:
                          return str(day_diff / 7) + " weeks ago"
                      if day_diff < 365:
                          return str(day_diff / 30) + " months ago"
                      return str(day_diff / 365) + " years ago"
                  

                  【讨论】:

                    【解决方案14】:

                    很长时间以来,我一直在将这段代码从一种编程语言拖到另一种编程语言,我不记得我最初是从哪里得到它的。它在 PHP、Java 和 TypeScript 中对我很有帮助,现在是 Python 的时候了。

                    它处理过去和未来的日期,以及边缘情况。

                    def unix_time() -> int:
                        return int(time.time())
                    
                    
                    def pretty_time(t: int, absolute=False) -> str:
                        if not type(t) is int:
                            return "N/A"
                        if t == 0:
                            return "Never"
                    
                        now = unix_time()
                        if t == now:
                            return "Now"
                    
                        periods = ["second", "minute", "hour", "day", "week", "month", "year", "decade"]
                        lengths = [60, 60, 24, 7, 4.35, 12, 10]
                    
                        diff = now - t
                    
                        if absolute:
                            suffix = ""
                        else:
                            if diff >= 0:
                                suffix = "ago"
                            else:
                                diff *= -1
                                suffix = "remaining"
                    
                        i = 0
                        while diff >= lengths[i] and i < len(lengths) - 1:
                            diff /= lengths[i]
                            i += 1
                    
                        diff = round(diff)
                        if diff > 1:
                            periods[i] += "s"
                    
                        return "{0} {1} {2}".format(diff, periods[i], suffix)
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-07-12
                      • 1970-01-01
                      • 2015-08-15
                      • 1970-01-01
                      • 2018-04-27
                      • 2012-04-21
                      • 2017-07-24
                      相关资源
                      最近更新 更多