Sekunden in jeweils Stunden / Tagen /Wochen/Monate umwandeln

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Diealready
User
Beiträge: 7
Registriert: Samstag 28. Dezember 2013, 12:19

Ich habe auf meinem Gameserver ein Plugin was die Spielzeiten alias "Playtime" jedes Spieler in Sekunden speichert.
Also wenn Spieler "123456" exact 5 Minuten auf meinem Server gespielt hat wird in der Datenbank 300.00 Sekunden angezeigt (60 sekunden * 5=300 sekunden)

Nun hab ich ein Script erstellt was die Sekunden in jeweils Sekunden oder Stunden oder Tage oder Wochen oder Monate ausgibt.

Code: Alles auswählen

def formatTimeAgo(seconds):
    if seconds < 60:
        return "%i seconds" % seconds
    elif seconds < 3600:
        return "%i minutes" % (seconds/float(60))
    elif seconds < (3600*24):
        return "%.1f hours" % (seconds/float(3600))
    elif seconds < (3600*24*7):
        return "%.1f Days" % (seconds/float(3600*24))
    elif seconds < (3600*24*7*30):
        return "%.1f Weeks" % (seconds/float(3600*24*7))
    else:
        return "%.1f Months" % (seconds/float(3600*24*30))
Dieses Script funktioniert einwand frei denn es zeigt für Spieler 123456 exakt 5 Minutes also "5 minutes" an.
Doch ich möchte gerne das es mir ab Wochen also "Weeks" nicht einfach nur als Beispiel (21523 Sekunden) Es würde mir 3.4 Wochen anzeigen also im Spiel 3.4 Weeks. Doch ich möchte das es mir gerne anzeigt 3 Wochen 2 Tage also "3 Weeks 2 Days" anzeigt oder für 1 Monat 2 Wochen "1 month 2 Weeks".

Viel Dank im vorraus.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Schau dir mal den Modulo-Operator an, damit geht es recht schnell. Du berechnest also erst die Anzahl der Wochen und aus dem Rest dann die Tage. Wenn dann noch etwas die Stunden, dann die Minuten und abschließend die Sekunden.
Das Leben ist wie ein Tennisball.
BlackJack

So ein Stück weit können die Sachen aus dem `datetime`-Modul auch helfen diese Umrechnung zu machen.
Diealready
User
Beiträge: 7
Registriert: Samstag 28. Dezember 2013, 12:19

EyDu hat geschrieben:Hallo und willkommen im Forum!

Schau dir mal den Modulo-Operator an, damit geht es recht schnell. Du berechnest also erst die Anzahl der Wochen und aus dem Rest dann die Tage. Wenn dann noch etwas die Stunden, dann die Minuten und abschließend die Sekunden.
Hallo Eydu,

Danke für die freundliche Begrüßung.

Ich werde mir dies mal anschauen. Danke
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

Ist sicher keine Schönheit, was die Funktion selbst oder die Ausgabe betrifft, aber im Prinzip würde ich es so machen.
Wie dann Deine Rückgabezeichenkette aussehen soll, das musst Du natürlich selbst festlegen.

Code: Alles auswählen

def to_special_string(sekunden):
    #falls tatsaechlich mal ein float ankommt
    sekunden = int(sekunden)

    #Ermitteln der Einzelwerte
    minuten = sekunden/60
    sekunden -= minuten*60
    
    stunden = minuten/60
    minuten -= stunden*60
    
    tage = stunden/24
    stunden -= tage*24
    
    wochen = tage/7
    tage -=wochen*7
    
    monate = wochen/4
    wochen -= monate*4

    #Monate sind natuerlich tricky, ich habe mich für 4 Wochen entschieden, ansonsten kann es seltsam werden
    #angenommen, Du gehst von 30 Tagen aus:
    #29 Tage = 4 Wochen, 1 Tag
    #30 Tage = 1 Monat, 0 Wochen, 0 Tage
    #die Herangehensweise wäre analog, Du muesstest erst die Anzahl der Monate aus den Tagen ermitteln, danach die Wochen aus den Tagen, also:
    #monate = tage/30
    #tage -= monate*30
    #wochen = tage/7
    #tage -= wochen*7
    
    #Zusammenbasteln eines Rueckgabewertes
    return_value = ''
    if monate>0:
        if monate>1:
            return_value += "%d Monate " % monate
        else:
            return_value += "einen Monat "
    
    if wochen>0:
        if wochen>1:
            return_value += "%d Wochen " % wochen
        else:
            return_value += "eine Woche "

    if tage>0:
        if tage>1:
            return_value += "%d Tage " % tage
        else:
            return_value += "einen Tag "
    
    print monate,wochen,tage,stunden,minuten,sekunden #nur zur Kontrolle
    return_value += "%02d:%02d:%02d" % (stunden, minuten, sekunden)

    return return_value
Gibt es an der Herangehensweise etwas auszusetzen?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@NoPy: Es gibt den Modulo-Operator »%« der den Rest einer Division ermittelt (»mod« in Delphi), in Python sogar »divmod« das Division und Rest gleichzeitig berechnet. In Python wird gerne mit Listen gearbeitet, z.B. um einen String aus mehreren Teilen zusammenzusetzen benutzt man eine Liste und »'..'.join«. Dazu wäre es praktisch, alles irgendwo in Listen zu speichern, um so Redundanzen im Code zu vermeiden:

Code: Alles auswählen

UNITS = ('Monate', 'Wochen', 'Tage', 'Stunden' ,'Minuten', 'Sekunden')
SPANS = (60, 60, 24, 7, 4)

def to_special_string(seconds):
    parts = [seconds]
    for span in SPANS:
        parts[:1] = divmod(parts[0], span)
    return ' '.join(
        '%d %s'%(value, unit) if value!=1 else '1 %s'%unit[:-1]
        for value, unit in zip(parts, UNITS) if value)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier mal mit Trennung von Berechnung und Ausgabe:

Code: Alles auswählen

from collections import namedtuple

class Duration(namedtuple('Duration', 'weeks, days, hours, minutes, seconds')):
    def __str__(self):
        return ', '.join(self._get_formatted_units())

    def _get_formatted_units(self):
        for unit_name, value in self._asdict().items():
            if value > 0:
                if value == 1:
                    unit_name = unit_name.rstrip('s')
                yield '{} {}'.format(value, unit_name)


def get_duration(seconds):
    minutes, seconds = divmod(seconds, 60)
    hours, minutes = divmod(minutes, 60)
    days, hours = divmod(hours, 24)
    weeks, days = divmod(days, 7)
    return Duration(weeks, days, hours, minutes, seconds)
Beispiele aus der Python-Shell:

Code: Alles auswählen

>>> print get_duration(3)
3 seconds
>>> print get_duration(59)
59 seconds
>>> print get_duration(1)
1 second
>>> print get_duration(61)
1 minute, 1 second
>>> print get_duration(62)
1 minute, 2 seconds
>>> print get_duration(121)
2 minutes, 1 second
>>> print get_duration(3600)
1 hour
>>> print get_duration(3601)
1 hour, 1 second
>>> print get_duration(3602)
1 hour, 2 seconds
>>> print get_duration(3120)
52 minutes
>>> print get_duration(42354365)
70 weeks, 5 hours, 6 minutes, 5 seconds
Die Fehlerausgabe bei negativen Werten und die Sonderbehandlung von einer 0-sekündigen Spieldauer (hierfür würde mein Code überhaupt keine formattierte Ausgabe liefern) habe ich mal weggelassen...
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier nochmal eine deutlich flexiblere Variante, basierend auf den Ideen von Sirius3:

Code: Alles auswählen

from collections import namedtuple, OrderedDict

UNITS = OrderedDict([
    ('Monate', 1), ('Wochen', 4), ('Tage', 7),
    ('Stunden', 24), ('Minuten', 60), ('Sekunden', 60)
])

class Duration(namedtuple('Duration', UNITS.keys())):
    def __str__(self):
        return ', '.join(self._get_formatted_units())

    def _get_formatted_units(self):
        data = self._asdict()
        if not any(data.values()):
            yield '0 {}'.format(data.keys()[-1])
            return
        for unit_name, value in data.items():
            if value:
                if value == 1:
                    unit_name = unit_name[:-1]
                yield '{} {}'.format(value, unit_name)

def get_duration(seconds):
    parts = [seconds]
    for span in reversed(UNITS.values()[1:]):
        parts[:1] = divmod(parts[0], span)
    return Duration(*parts)
Ich habe jetzt auch die Behandlung einer 0-sekündigen Spieldauer eingebaut.
Diealready
User
Beiträge: 7
Registriert: Samstag 28. Dezember 2013, 12:19

Ich entschuldige mich für meine verspätete Antwort (hat schon seine Gründe ;>)

Ich danke euch erstmal für die Antworten , sehen auch ziemlich vielversprechend aus , doch wäre dies auch möglich ohne irgendwelche module zu importieren? sondern einfach meinen vorgegebenen Code zu ändern? (<< Dies ist eine Frage :D)

Schönen Abend euch und einen guten Arbeitsstart ;)
BlackJack

@Diealready: Die Antwort ist ganz offensichtlich ja. Aber warum sollte man keine Module benutzen? Noch dazu wenn sie schon in der Standardbibliothek vorhanden sind?
Diealready
User
Beiträge: 7
Registriert: Samstag 28. Dezember 2013, 12:19

Ich mags eigentlich sehr ungern module zu importieren , da ich die Scripts für meinen Gameserver benutze , und daher die libs von dem jeweiligen modul einfügen muss.
BlackJack

@Diealready: Das sind Module aus der Standardbibliothek. Die sind dabei, die muss man nicht hinzufügen.
Diealready
User
Beiträge: 7
Registriert: Samstag 28. Dezember 2013, 12:19

Danke für die schnelle Antwort :)

Doch leider bekomm ich trotzdem die nachricht
"no module named 'namedtuple'()"

Gruß
BlackJack

@Diealready: Das wird wahrscheinlich weder die tatsächliche Meldung sein, noch wird das von einer hier gezeigten Quelltextzeile stammen. Was versuchst Du denn da tatsächlich und wie sieht die Meldung tatsächlich aus?
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

Bei mir geht es ohne Probleme. Sieht lustig aus :)
Benutzeravatar
HarteWare
User
Beiträge: 69
Registriert: Samstag 23. Februar 2013, 21:16
Wohnort: localhost

Sorry, aber ich muss mal kurz nochmals anmerken, das ist... sagen wir nicht sehr gut, wenn du irgendwie bewusst keine module nutzen willst.

Du willst schließlich nicht Zeit damit verschwenden, das Rad täglich neu zu erfinden. Dazu sind die Lösungen der Standardbibliothek einfach besser - da steckt richtig Zeit und Arbeit drin.

Das ist auch übrigens, meiner Meinung nach, einer der Stärken von Python. Es gibt eigentlich für die meisten Sachen irgendein Modul...
Da wäre es doch schade drum, diese auch nicht zu nutzen, wenn angemessen.

LG
Diealready
User
Beiträge: 7
Registriert: Samstag 28. Dezember 2013, 12:19

Leider siehts danach aus das Eventscripts Python die Standartmodule von Python nicht dabei hat.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Diealready hat geschrieben:Leider siehts danach aus das Eventscripts Python die Standartmodule von Python nicht dabei hat.
Sollte es sich um ein Python 2.5 handeln, wäre ``namedtuple`` tatsächlich nicht dabei. Man kann sich aber ja sicher die Python-Version anzeigen lassen, oder?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Diealready
User
Beiträge: 7
Registriert: Samstag 28. Dezember 2013, 12:19

Auf der Seite steht.

Full Python 2.5 language support for addons:
Antworten