Python: Je dois afficher les temps de modification des fichiers au format "il y a 1 jour", "il y a deux heures".
Y a-t-il quelque chose de prêt à le faire? Ce devrait être en anglais.
Le code a été initialement publié sur un article de blog "Python Pretty Date function" ( http://evaisse.com/post/93417709/python-pretty-date-function )
Il est reproduit ici car le compte du blog a été suspendu et la page n'est plus disponible.
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 = 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"
Si vous utilisez Django , la nouveauté de la version 1.4 est le filtre de modèle naturaltime
.
Pour l'utiliser, commencez par ajouter 'Django.contrib.humanize'
à votre paramètre INSTALLED_APPS
dans settings.py et {% load humanize %}
au modèle dans lequel vous utilisez le filtre.
Ensuite, dans votre modèle, si vous avez une variable datetime my_date
, vous pouvez imprimer sa distance par rapport au présent à l’aide de {{ my_date|naturaltime }}
, qui sera rendu sous la forme 4 minutes ago
.
Autres nouveautés dans Django 1.4.
Documentation sur naturaltime
et autres filtres de l'ensemble Django.contrib.humanize
.
En cherchant la même chose avec l'exigence supplémentaire de gérer les dates futures, j'ai trouvé ceci: http://pypi.python.org/pypi/py-pretty/1
Exemple de code (du site):
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'
La réponse associée à Jed Smith est bonne et je l’utilise depuis environ un an, mais je pense qu’elle pourrait être améliorée de plusieurs façons:
Voici ce que je suis venu avec:
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'))
Remarquez comment chaque tuple dans intervals
est facile à interpréter et à vérifier: un 'minute'
est 60
secondes; un 'hour'
est 60
minutes; etc. Le seul fudge est de mettre weeks_per_month
à sa valeur moyenne; compte tenu de la demande, ça devrait aller. (Et notez qu’il est clair en un coup d’œil que les trois dernières constantes se multiplient par 365.242, le nombre de jours par an.)
L'un des inconvénients de ma fonction est qu'elle ne fait rien en dehors du motif "## unités": "Hier", "tout à l'heure", etc. sont tout de suite en sortie. Là encore, l'affiche originale ne demandait pas ces termes sophistiqués, je préfère donc ma fonction pour sa brièveté et la lisibilité de ses constantes numériques. :)
Vous pouvez aussi le faire avec arrow package
De page de github :
>>> import arrow >>> utc = arrow.utcnow() >>> utc = utc.replace(hours=-1) >>> local.humanize() 'an hour ago'
Le paquet ago le fournit. Appelez human
sur un objet datetime
pour obtenir une description lisible par l'homme de la différence.
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
Il y a 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'
Il prend en charge la localisation l10n , l'internationalisation i18n :
>>> _ = humanize.i18n.activate('ru_RU')
>>> print humanize.naturaltime(datetime.now() - timedelta(days=1))
день назад
>>> print humanize.naturaltime(datetime.now() - timedelta(hours=2))
2 часа назад
J'ai écrit un article de blog détaillé pour la solution sur http://sunilarora.org/17329071 Je publie également un extrait rapide ici.
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
Utilisation d'objets datetime avec tzinfo:
def time_elapsed(etime):
# need to add tzinfo to datetime.utcnow
now = datetime.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)
Voici une réponse mise à jour basée sur l'implémentation de Jed Smith, qui transmet correctement les dates/heures naïves et sensibles à l'offset. Vous pouvez également donner un fuseau horaire par défaut. 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"
Vous pouvez télécharger et installer le lien ci-dessous. Cela devrait être plus utile pour vous. Il fournit un message convivial de seconde en année.
C'est bien testé.
https://github.com/nareshchaudhary37/timestamp_content
Les étapes ci-dessous à installer dans votre env virtuel.
git clone https://github.com/nareshchaudhary37/timestamp_content
cd timestamp-content
python setup.py
Ceci est le message de @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)