Mit Zeitwerten rechnen

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.
BlackJack

Beitragvon BlackJack » Mittwoch 6. Dezember 2006, 18:41

JR hat geschrieben:
BlackJack hat geschrieben:Welche Werte Du benutzt hast, kann man in dem von Dir hier veröffentlichten Quelltext nachlesen.


Hey, wir reden aneinander vorbei :-)


Okay, dann sag das nächste mal bitte etwas deutlicher, dass Du die Werte (auch) mit *meinem* Skript ausprobiert hast. Ich bin nämlich so überheblich, dass ich erst einmal davon ausgehe unfehlbar zu sein. ;-)

Überarbeitete Fassung:

Code: Alles auswählen

class Time(object):
    def __init__(self, hours=0, minutes=0):
        self.minutes = hours * 60 + minutes
   
    def __str__(self):
        hours, minutes = divmod(abs(self.minutes), 60)
        if self. minutes < 0:
            hours = -hours
        return '%d:%02d' % (hours, minutes)
   
    def __int__(self):
        return self.minutes
   
    def __add__(self, other):
        return Time(minutes=int(self) + int(other))
   
    def __sub__(self, other):
        return Time(minutes=int(self) - int(other))
   
    @classmethod
    def from_string(cls, time):
        hours, minutes = map(int, time.split(':'))
        if hours < 0:
            minutes = -minutes
        return cls(hours, minutes)
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Mittwoch 6. Dezember 2006, 19:20

Hi BlackJack,

dein Code sieht wirklich kompakt aus, gefällt mir.

Ich weiß von mir zumindest, dass es immer blöd ist, auf Fehler hingewiesen zu werden, aber:

Man darf deine Klassenfunktionen nicht so (Codeausschnitt)

Code: Alles auswählen

def main():
    wert1 = '-0:01'
    wert2 = '0:37'
   
    print Time.from_string(wert1) + Time.from_string(wert2)


oder so (Codeausschnitt)

Code: Alles auswählen

def main():
    wert1 = '-00:01'
    wert2 = '00:37'
   
    print Time.from_string(wert1) + Time.from_string(wert2)


rufen.

Dann kommt nämlich 0:38 als Ergebnis zurück. Ich hätte 00:36 oder 0:36 erwartet :!:

Mein Code ist recht lang und man erkennt sicher, dass ich noch ein "Anfänger" bin. Was es die Lesbarkeit anbelangt, hängt das bestimmt auch davon ab, wie geübt man schon ist. Ob Stephan versteht, was du geschrieben hast, weiß ich nicht.
Ich verstehe deinen Code noch nicht, obwohl ich schon viele Tausend Zeilen für mein Flugplatzverwaltungsprogramm gecoded habe.
Bewusst zielte mein Ergebnis darauf ab, es im Bezug auf die Art des Aufrufs genau daran anzulehnen, wie Stephan es in seiner Frage aufgezeigt hat:

Code: Alles auswählen

wert1 = '-155:00'
wert2 = '-20:20'

def sumZeit(value1, value2, operation):
    operations = ['+', '-']
    if operation in operations:


Was bedeutet eigentlich das

Code: Alles auswählen

@classmethod


Ehrlich gesagt merke ich gerade, dass ich noch viel zu lernen habe. Ich verstehe beinahe nichts in deinem Code.

Dein Beispiel regt mich jedenfalls dazu an, mal richtig nachzuschlagen, was man mit

Code: Alles auswählen

def __str__(self):
def __add__(self, other):


etc. anfangen kann. Ist other frei gewählt?

Am meisten Rätsel bereitet mit folgende Methode in deinem Code:

Code: Alles auswählen

    def __int__(self):
        return self.minutes

Was tut diese Methode?
Da steckt doch sicherlich mehr dahinter, als nur ein Attribut auszulesen???

Grüße und bis gleich :wink:
Jamil
JR
User
Beiträge: 286
Registriert: Montag 20. Februar 2006, 16:43
Wohnort: Berlin

Beitragvon JR » Mittwoch 6. Dezember 2006, 19:49

Tja, jetzt habe ich noch einen Fehler in meiner Lösung entdeckt. Ich poste den Code jetzt neu. Habe Kommentare eingefügt und die Zeilen 71-73 hinzugefügt.

Code: Alles auswählen

calc('-0:59', '0:37', '+')

ergab 00:22 und nicht -00:22

Code: Alles auswählen

#!/Python24/python.exe
# -*- coding: iso-8859-1 -*-
# File: time_calc.py
def calc(time1='', time2='', operation='+'):
    result = ''
    argsOk = False
    # wenn zeitwerte und ein valider operator übergeben wurden
    if time1 and time2 and operation in ['+', '-']:
        pos1 = time1.find(':')
        pos2 = time2.find(':')
        pos_minus1 = time1.find('-')
        pos_minus2 = time2.find('-')

        # wenn die dopllepunkte an korrekter stelle stehen
        if pos1 == len(time1) - 3 and pos2 == len(time2) - 3:
           try:
               # folgende vier zeilen prüfen, ob korrekt formatierte zeitwerte übergeben wurden
               t1 = time1.replace('-', '').replace(':', '')
               t2 = time2.replace('-', '').replace(':', '')
               int(t1)
               int(t2)
               # selbsterlärend
               if pos_minus1 > 0 or pos_minus2 > 0:
                   print 'Einer der beiden Zeitwerte enthält ein Minus an einer falschen Stelle!'
               else:
                   # für später merken, ob zeit 1 negativ ist
                   minus1 = 1
                   if time1[0] == '-':
                       minus1 = -1
                       time1 = time1[1:]
                       pos1 -= 1
                   # für später merken, ob zeit 2 negativ ist
                   minus2 = 1
                   if time2[0] == '-':
                       minus2 = -1
                       time2 = time2[1:]
                       pos2 -= 1                   
                   argsOk = True
           except:
               print 'Mindestens ein Zeitwert enthält ein ungültiges Zeichen!\nErlaubt sind "-", ":" und Zahlen.'
    if argsOk:
        # zeitwerte in absolutwerte für stunden und minuten auflösen
        hh1 = int(time1[:pos1])
        hh2 = int(time2[:pos2])
        mm1 = int(time1[pos1 + 1:])
        mm2 = int(time2[pos2 + 1:])
       
        # zeiten auf einheit in minuten bringen
        min1 = minus1 * (60 * hh1 + mm1)
        min2 = minus2 * (60 * hh2 + mm2)
       
        # rechnung durchführen
        if operation == '+':
            min_result = min1 + min2
        else:
            min_result = min1 - min2

        # wenn das resultat negativ ist, dann merken, um korrekt mit den funktionen
        # zur ganzzahligen division und modulo zu arbeoten
        # anschließend muss dies bei der rückgabe eines strings berücksichtigt werden
        minus = 1
        if min_result < 0:
            minus = -1
           
        hh_result = abs(min_result) / 60
        min_result = abs(min_result) % 60
       
        result = '%.2d:%.2d'%(minus * hh_result, min_result)
       
        # "sonderfall": resultat ist kleiner als 00:00 und größer -01:00
        if hh_result == 0 and minus == -1:
            result = '-' + result 
        return result

if __name__ == '__main__':
    result = calc('-0:59', '0:37', '+')
    if result:
        print result


Bis denn
Jamil
BlackJack

Beitragvon BlackJack » Mittwoch 6. Dezember 2006, 20:25

JR hat geschrieben:Man darf deine Klassenfunktionen nicht so (Codeausschnitt)

Code: Alles auswählen

def main():
    wert1 = '-0:01'
    wert2 = '0:37'
   
    print Time.from_string(wert1) + Time.from_string(wert2)


rufen.

Dann kommt nämlich 0:38 als Ergebnis zurück. Ich hätte 00:36 oder 0:36 erwartet :!:


Grmpf, warum kann es denn auch keinen Unterschied zwischen -0 und +0 geben. :-)

Nochmal nachgebessert (und immer noch nicht ordentlich getestet):

Code: Alles auswählen

class Time(object):
    def __init__(self, hours=0, minutes=0):
        self.minutes = hours * 60 + minutes
   
    def __str__(self):
        hours, minutes = divmod(abs(self.minutes), 60)
        if self.minutes < 0:
            sign = '-'
        else:
            sign = ''
        return '%s%d:%02d' % (sign, hours, minutes)
   
    def __int__(self):
        return self.minutes
   
    def __add__(self, other):
        return Time(minutes=int(self) + int(other))
   
    def __sub__(self, other):
        return Time(minutes=int(self) - int(other))
   
    @classmethod
    def from_string(cls, time):
        hours, minutes = map(int, time.split(':'))
        if time.startswith('-'):
            minutes = -minutes
        return cls(hours, minutes)


Mein Code ist recht lang und man erkennt sicher, dass ich noch ein "Anfänger" bin. Was es die Lesbarkeit anbelangt, hängt das bestimmt auch davon ab, wie geübt man schon ist. Ob Stephan versteht, was du geschrieben hast, weiß ich nicht.
Ich verstehe deinen Code noch nicht, obwohl ich schon viele Tausend Zeilen für mein Flugplatzverwaltungsprogramm gecoded habe.


In Python? Mit OOP? Ich dachte jedenfalls meine Klasse wäre ziemlich einfach gehalten. Eine Handvoll kurzer Methoden die jede für sich nicht allzu kompliziert ist und die Semantik ist bei den "Spezialmethoden" mit den Unterstrichen ja recht genau definiert.

Bewusst zielte mein Ergebnis darauf ab, es im Bezug auf die Art des Aufrufs genau daran anzulehnen, wie Stephan es in seiner Frage aufgezeigt hat:

Code: Alles auswählen

wert1 = '-155:00'
wert2 = '-20:20'

def sumZeit(value1, value2, operation):
    operations = ['+', '-']
    if operation in operations:


Die Vorgehensweise ist irgendwie so, hm, prozedural. Objekte sind ein wenig flexibler. Die Objekte, vorausgesetzt ich hab's endlich Korrekt implementiert ;-), kann man in eine Liste stecken und mit `sum()` aufaddieren. Wenn man noch eine Vergleichsmethode implementiert, kann man Zeiten vergleichen, eine Liste mit Zeiten sortieren oder mit `min()`/`max()` das Minimum/Maximum finden, und so weiter.

Was bedeutet eigentlich das

Code: Alles auswählen

@classmethod


Das bedeutet das die folgende Methode eine `classmethod` ist. Wenn man die aufruft, dann wird als erstes Argument die Klasse übergeben, zu der die Methode gehört.

Dein Beispiel regt mich jedenfalls dazu an, mal richtig nachzuschlagen, was man mit

Code: Alles auswählen

def __str__(self):
def __add__(self, other):


etc. anfangen kann. Ist other frei gewählt?


Ja. Genau wie `self`. Aber speziell bei `self` macht man sich nicht viele Freunde wenn man etwas anderes wählt, und `other` ist bei den Methoden für binäre Operatoren recht gebräuchlich.

Am meisten Rätsel bereitet mit folgende Methode in deinem Code:

Code: Alles auswählen

    def __int__(self):
        return self.minutes

Was tut diese Methode?
Da steckt doch sicherlich mehr dahinter, als nur ein Attribut auszulesen???


Nicht wirklich. Ich habe es bloss implementiert um bei der Addition/Subtraktion von `Time`-Objekten `int()` anwenden zu können. Das heisst man kann zu einem `Time`-Objekt auch beliebige Objekte addieren, die sich in eine ganze Zahl wandeln lassen, inklusive `int`-Objekte natürlich.
Benutzeravatar
Mawilo
User
Beiträge: 446
Registriert: Sonntag 22. Februar 2004, 10:58
Wohnort: Sachsen
Kontaktdaten:

Beitragvon Mawilo » Mittwoch 6. Dezember 2006, 22:53

Das ist ja klasse. Jetzt habe ich zwei Lösungen, die funktionieren :D

Ehrlich gesagt, muss ich mir die Lösung von BlackJack noch einmal auf der Zunge zergehen lassen. Aber so lernt man wenigstens was dabei.

Vielen Dank

Stephan

Wer ist online?

Mitglieder in diesem Forum: Google [Bot]