【发布时间】:2009-10-11 18:28:45
【问题描述】:
Python:我需要以“1 天前”、“2 小时前”的格式显示文件修改时间。
有什么可以做的吗?应该是英文的。
【问题讨论】:
标签: python datetime date time formatting
Python:我需要以“1 天前”、“2 小时前”的格式显示文件修改时间。
有什么可以做的吗?应该是英文的。
【问题讨论】:
标签: python datetime date time formatting
代码最初发表在一篇博文“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"
【讨论】:
如果您碰巧使用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.
【讨论】:
在寻找具有处理未来日期的附加要求的相同内容时,我发现了这一点: 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'
【讨论】:
您也可以使用 arrow 包来做到这一点
来自github page:
>>> import arrow >>> utc = arrow.utcnow() >>> utc = utc.shift(hours=-1) >>> utc.humanize() 'an hour ago'
【讨论】:
>>> 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 转换为幼稚的(在当地时区)。
Jed Smith 链接的答案很好,我用了一年左右,但我认为它可以在几个方面进行改进:
这是我想出的:
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"
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
【讨论】:
将日期时间对象与 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)
【讨论】:
我已经在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
【讨论】:
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 ""
【讨论】:
这是@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)
【讨论】:
您可以从以下链接下载和安装。它应该对你更有帮助。它一直在提供用户友好的信息。
经过很好的测试。
https://github.com/nareshchaudhary37/timestamp_content
以下步骤安装到您的虚拟环境中。
git clone https://github.com/nareshchaudhary37/timestamp_content
cd timestamp-content
python setup.py
【讨论】:
这是基于 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"
【讨论】:
很长时间以来,我一直在将这段代码从一种编程语言拖到另一种编程语言,我不记得我最初是从哪里得到它的。它在 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)
【讨论】: