web-dev-qa-db-de.com

Benutzerfreundliches Zeitformat in Python?

Python: Ich muss Dateimodifikationen mal im Format "Vor 1 Tag", "Vor zwei Stunden" anzeigen.

Gibt es etwas, das dazu bereit ist? Es sollte auf Englisch sein.

54
flybywire

Der Code wurde ursprünglich in einem Blogbeitrag "Python Pretty Date function" veröffentlicht ( http://evaisse.com/post/93417709/python-pretty-date-function )

Sie wird hier reproduziert, da der Blog-Account gesperrt wurde und die Seite nicht mehr verfügbar ist.

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"
105
Jed Smith

Wenn Sie Django verwenden, ist in Version 1.4 der Vorlagenfilter naturaltime neu.

Um dies zu verwenden, fügen Sie zunächst 'Django.contrib.humanize' zu Ihrer INSTALLED_APPS-Einstellung in settings.py und {% load humanize %} zur Vorlage hinzu, in der Sie den Filter verwenden.

Wenn Sie in Ihrer Vorlage eine Datums-/Zeitvariable my_date haben, können Sie die Entfernung von der Gegenwart mithilfe von {{ my_date|naturaltime }} drucken. Dies wird in etwa wie 4 minutes ago dargestellt.

Andere neue Dinge in Django 1.4.

Dokumentation für naturaltime und andere Filter im Django.contrib.humanize-Set.

29
plowman

Bei der Suche nach der gleichen Anforderung mit der zusätzlichen Anforderung, dass zukünftige Daten verarbeitet werden müssen, fand ich Folgendes: http://pypi.python.org/pypi/py-pretty/1

Beispielcode (von 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'
14
Karim

Die Antwort, mit der Jed Smith zu tun hatte, ist gut, und ich habe sie ungefähr ein Jahr lang benutzt, aber ich denke, es könnte in mancher Hinsicht verbessert werden:

  • Es ist schön, jede Zeiteinheit in Bezug auf die vorangehende Einheit definieren zu können, anstatt "magische" Konstanten wie 3600, 86400 usw. im gesamten Code zu haben.
  • Nach langem Einsatz finde ich, dass ich nicht so eifrig zur nächsten Einheit gehen möchte. Beispiel: Sowohl 7 Tage als auch 13 Tage werden als "1 Woche" angezeigt. Ich würde stattdessen "7 Tage" oder "13 Tage" sehen.

Folgendes habe ich mir ausgedacht:

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'))

Beachten Sie, dass jedes Tuple in intervals leicht zu interpretieren und zu überprüfen ist: Ein 'minute' ist 60 Sekunden; ein 'hour' ist 60 Minuten; usw. Der einzige Fudge setzt weeks_per_month auf seinen Durchschnittswert; Angesichts der Anwendung sollte das in Ordnung sein. (Und beachten Sie, dass auf einen Blick klar ist, dass sich die letzten drei Konstanten mit 365.242, der Anzahl von Tagen pro Jahr, multiplizieren.)

Ein Nachteil meiner Funktion ist, dass sie nichts außerhalb des "## units" -Musters tut: "Yesterday", "just now", usw. sind gerade out. Andererseits hat das Originalposter nicht nach diesen ausgefallenen Begriffen gefragt, deshalb bevorzuge ich meine Funktion wegen ihrer Prägnanz und der Lesbarkeit ihrer numerischen Konstanten. :)

5
Chip Hogg

Sie können das auch mit arrow package machen

Von github page :

>>> import arrow
>>> utc = arrow.utcnow()
>>> utc = utc.replace(hours=-1)
>>> local.humanize()
'an hour ago'
5
vishes_shell

Das Paket ago bietet dies. Rufen Sie human für ein datetime-Objekt auf, um eine vom Menschen lesbare Beschreibung des Unterschieds zu erhalten. 

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
4

Es gibt humanize Paket :

>>> 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'

Es unterstützt die Lokalisierung l10n , Internationalisierung i18n :

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

Ich habe einen ausführlichen Blogbeitrag für die Lösung auf http://sunilarora.org/17329071 .__ geschrieben. Ich poste hier auch einen kurzen Ausschnitt.

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
1
sunil

Verwenden von datetime-Objekten mit 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)
1

Hier ist eine aktualisierte Antwort, die auf der Implementierung von Jed Smith basiert und sowohl Offset-naive als auch Offset-bewusste Datenzeiten korrekt übermittelt. Sie können auch eine Standardzeitzone angeben. 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"
0
Mikko Ohtamaa

Sie können den folgenden Link herunterladen und installieren. Es sollte für Sie hilfreicher sein. Es bietet seit dem zweiten Jahr eine benutzerfreundliche Nachricht.

Es ist gut getestet.

https://github.com/nareshchaudhary37/timestamp_content

Nachfolgende Schritte zur Installation in Ihrer virtuellen Umgebung.

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

Dies ist der Hauptpunkt von @sunils Post

>>> 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)
0
Steven Almeroth