Seite 1 von 1
Mit Zeitwerten rechnen
Verfasst: Dienstag 5. Dezember 2006, 21:28
von Mawilo
Hallo allerseits,
irgendwie stehe ich auf dem Schlauch. Ich benötige für ein Programm eine Funktion, mit der ich mit Zeitwerten im Format hh:mm rechnen kann.
Mein Versuch liefert mir leider nicht das genaue Ergebnis.
Ich bin für Hinweise dankbar
Hier mein Versuch:
Code: Alles auswählen
wert1 = '-155:00'
wert2 = '-20:20'
def sumZeit(value1, value2, operation):
operations = ['+', '-']
if operation in operations:
v1h, v1m = value1.split(':')
v2h, v2m = value2.split(':')
if int(v1h) < 0:
v1_in_Minuten = int(v1h) * 60 - int(v1m)
else:
v1_in_Minuten = int(v1h) * 60 + int(v1m)
if int(v2h) < 0:
v2_in_Minuten = int(v2h) * 60 - int(v2m)
else:
v2_in_Minuten = int(v2h) * 60 + int(v2m)
print v1_in_Minuten, v2_in_Minuten
if operation == '-':
v2_in_Minuten = v2_in_Minuten * -1
ergebnis = v1_in_Minuten + v2_in_Minuten
print ergebnis
stunden = ergebnis / 60
minuten = ergebnis - (stunden * 60)
print '%02i:%02i'%(stunden, minuten)
sumZeit(wert1, wert2, '+')
Stephan
Verfasst: Dienstag 5. Dezember 2006, 21:35
von jens
Schau dir mal datetime an:
http://docs.python.org/lib/module-datetime.html
Beispiele findest du hier im Forum...
Verfasst: Dienstag 5. Dezember 2006, 22:11
von Mawilo
Danke für die schnelle Antwort.
Ich habe mal folgendes Beispiel probiert:
Code: Alles auswählen
import datetime as dt
wert1 = '-155:00'
wert2 = '-20:20'
def sumZeit(value1, value2, operation):
operations = ['+', '-']
if operation in operations:
v1h, v1m = value1.split(':')
v2h, v2m = value2.split(':')
x1 = dt.timedelta(hours = int(v1h), minutes = int(v1m))
x2 = dt.timedelta(hours = int(v2h), minutes = int(v2m))
x3 = x1 + x2
print x3
sumZeit(wert1, wert2, '+')
Als Ergebnis bekomme ich:
Ich benötige aber das Ergebnis im Format: 175:20
Gibt es dafür noch anders formatierte Ausgaben?
Stephan
Verfasst: Dienstag 5. Dezember 2006, 23:19
von BlackJack
Für dieses einfache Problem kann man sich auch schnell eine Klasse basteln:
Code: Alles auswählen
class Time(object):
def __init__(self, hours=0, minutes=0):
self.minutes = hours * 60 + minutes
def __str__(self):
return '%d:%02d' % divmod(self.minutes, 60)
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):
return cls(*map(int, time.split(':')))
def main():
wert1 = '-155:00'
wert2 = '-20:20'
print Time.from_string(wert1) + Time.from_string(wert2)
Recht ungetestet, aber da kommt '-175:20' als Ergebnis.
Edit: Formatierung der Minuten in der Zeichenkettendarstellung korrigiert.
Verfasst: Dienstag 5. Dezember 2006, 23:44
von JR
Hi Stephan!
Hier ist ein lauffähiges Beispiel, wenn man es ohne spezielle Datentypen lösen will.
Meine Tests waren okay, aber teste es selbst nochmal ausgiebig.
[EDIT: Habe einen Fehler entfernt]
Code: Alles auswählen
#!/Python24/python.exe
# -*- coding: iso-8859-1 -*-
# File: time_calc.py
def calc(time1='', time2='', operation='+'):
result = ''
argsOk = False
if time1 and time2 and operation in ['+', '-']:
pos1 = time1.find(':')
pos2 = time2.find(':')
pos_minus1 = time1.find('-')
pos_minus2 = time2.find('-')
if pos1 == len(time1) - 3 and pos2 == len(time2) - 3:
try:
t1 = time1.replace('-', '').replace(':', '')
t2 = time2.replace('-', '').replace(':', '')
int(t1)
int(t2)
if pos_minus1 > 0 or pos_minus2 > 0:
print 'Einer der beiden Zeitwerte enthält ein Minus an einer falschen Stelle!'
else:
minus1 = 1
if time1[0] == '-':
minus1 = -1
time1 = time1[1:]
pos1 -= 1
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:
hh1 = int(time1[:pos1])
hh2 = int(time2[:pos2])
mm1 = int(time1[pos1 + 1:])
mm2 = int(time2[pos2 + 1:])
# zeiten in minuten
min1 = minus1 * (60 * hh1 + mm1)
min2 = minus2 * (60 * hh2 + mm2)
if operation == '+':
min_result = min1 + min2
else:
min_result = min1 - min2
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)
return result
if __name__ == '__main__':
result = calc('-155:01', '20:37', '-')
if result:
print result
Viel Spaß!
Gruß
Jamil
Verfasst: Mittwoch 6. Dezember 2006, 00:03
von JR
Hi BlackJack,
möchte dir nicht auf den Schlips treten, aber -155:01 - 20:37 = -175:38
Grüße
Jamil
Verfasst: Mittwoch 6. Dezember 2006, 01:04
von BlackJack
JR hat geschrieben:möchte dir nicht auf den Schlips treten, aber -155:01 - 20:37 = -175:38
Da ich keinen Schlips trage, dürfte das schwierig werden. Und ich weiss auch nicht warum ich mich auf den Schlips getreten fühlen sollte, wenn Du mit anderen Werten ein anderes Ergebnis herausbekommst. Das ist normal.
Wo wir gerade beim Schlipstreten sind: Dein Quelltext sieht ziemlich, äh, suboptimal aus. Insbesondere was Lesbarkeit und Verständlichkeit angeht.
Verfasst: Mittwoch 6. Dezember 2006, 07:09
von JR
Morgen BlackJack!
Ich finde dein Codesnippet auch schöner. Aber meins funktioniert.

Ich hatte gestern abend nicht mehr die Lust, viel Wert aufs Codedesign zu legen.
Meist schreibe ich erst einmal einen funktionierenden Code und dann kürze, optimiere und verschönere ich ihn.
Das kommt sicher daher, dass Zeit im Beruf Geld ist und der Kunde vor den Kollegen kommt. Also erst dem Kunden die Lösung bereitstellen, dann dafür sorgen, das spätere Anpassungen ebenso schnell erfolgen können.
Grüße dich
Jamil
Verfasst: Mittwoch 6. Dezember 2006, 13:21
von Mawilo
Hallo,
vielen Dank für die Vorschläge. Ich werde beide heute Abend mal ausprobieren.
Stephan
Verfasst: Mittwoch 6. Dezember 2006, 14:11
von Python 47
JR hat geschrieben:Morgen BlackJack!
Ich finde dein Codesnippet auch schöner. Aber meins funktioniert.
BlackJacks funktioniert auch:
dann bekommt er auch -175:20 raus, du hast aber mit folgendem gerechnet:
Code: Alles auswählen
if __name__ == '__main__':
result = calc('-155:01', '20:37', '-')
Ist ja wohl logisch, dass wenn man mit unterschiedlichen Werten rechnet, unterschiedliche Ergebnisse bekommt.

Verfasst: Mittwoch 6. Dezember 2006, 14:43
von JR
Hi!
Was du da schreibst ist Unfug. Macht aber nichts.
Probier es einfach selbst mit beiden Scripten aus.
Ist nicht immer drin, was drauf steht. Welche Werte ich beim Test benutzt habe, kannst du hier nicht sehen, es sei denn du hast dich auf meinem Rechner eingehackt. Und das bezweifle ich ein wenig
Viele Grüße
Jamil
Verfasst: Mittwoch 6. Dezember 2006, 16:04
von BlackJack
JR hat geschrieben:Was du da schreibst ist Unfug. Macht aber nichts.
Probier es einfach selbst mit beiden Scripten aus.
Er schreibt keinen Unfug. Befolge mal Deinen eigenen Rat.
Ist nicht immer drin, was drauf steht. Welche Werte ich beim Test benutzt habe, kannst du hier nicht sehen, es sei denn du hast dich auf meinem Rechner eingehackt. Und das bezweifle ich ein wenig

Welche Werte Du benutzt hast, kann man in dem von Dir hier veröffentlichten Quelltext nachlesen.
Verfasst: Mittwoch 6. Dezember 2006, 16:12
von sape
Jack, was ich nicht ganz versteh ist warum du bei ``from_string`` ein Dekorator benutzt
lg
Verfasst: Mittwoch 6. Dezember 2006, 16:35
von BlackJack
Weil das eine `classmethod` ist und keine "instancemethod". Das ist eine Methode auf der *Klasse* `Time` und nicht auf einem *Exemplar* vom Typ `Time`.
Verfasst: Mittwoch 6. Dezember 2006, 17:15
von JR
BlackJack hat geschrieben:
Welche Werte Du benutzt hast, kann man in dem von Dir hier veröffentlichten Quelltext nachlesen.
Hey, wir reden aneinander vorbei

Was meint ihr, wie oft ich die main()
über
Code: Alles auswählen
if __name__ == '__main__':
result = calc('-155:01', '20:37', '-')
if result:
print result
ausführen ließ?
Ich habe doch nicht nur einen Test gemacht.
Wenn ich meins ausführe:
Code: Alles auswählen
#!/Python24/python.exe
# -*- coding: iso-8859-1 -*-
# File: time_calc.py
def calc(time1='', time2='', operation='+'):
result = ''
argsOk = False
if time1 and time2 and operation in ['+', '-']:
pos1 = time1.find(':')
pos2 = time2.find(':')
pos_minus1 = time1.find('-')
pos_minus2 = time2.find('-')
if pos1 == len(time1) - 3 and pos2 == len(time2) - 3:
try:
t1 = time1.replace('-', '').replace(':', '')
t2 = time2.replace('-', '').replace(':', '')
int(t1)
int(t2)
if pos_minus1 > 0 or pos_minus2 > 0:
print 'Einer der beiden Zeitwerte enthält ein Minus an einer falschen Stelle!'
else:
minus1 = 1
if time1[0] == '-':
minus1 = -1
time1 = time1[1:]
pos1 -= 1
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:
hh1 = int(time1[:pos1])
hh2 = int(time2[:pos2])
mm1 = int(time1[pos1 + 1:])
mm2 = int(time2[pos2 + 1:])
# zeiten in minuten
min1 = minus1 * (60 * hh1 + mm1)
min2 = minus2 * (60 * hh2 + mm2)
if operation == '+':
min_result = min1 + min2
else:
min_result = min1 - min2
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)
return result
if __name__ == '__main__':
result = calc('-155:01', '-20:37', '+')
if result:
print result
kommt -175:38 raus. Das stimmt doch, oder?
Wenn ich von BlackJack
Code: Alles auswählen
class Time(object):
def __init__(self, hours=0, minutes=0):
self.minutes = hours * 60 + minutes
def __str__(self):
return '%d:%02d' % divmod(self.minutes, 60)
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):
return cls(*map(int, time.split(':')))
def main():
wert1 = '-155:01'
wert2 = '20:37'
print Time.from_string(wert1) - Time.from_string(wert2)
if __name__ == '__main__':
main()
ausführe, kommt -176:24 raus. Das stimmt nicht, oder?
---------------------
Mir geht es hier keineswegs darum, jemanden anzuschwärzen, zu ärgern oder wie auch immer.
BlackJack hatte eh geschrieben:
BlackJack hat geschrieben:
Recht ungetestet, aber ...
Korrigiert mich bitte, wenn ich mich irre!
Ansonsten diskutieren wir da am besten jetzt nicht viel weiter, sonst enthalten unsere Beiträge keine hilfreichen Informationen die sich direkt auf Python beziehen.
Viele Grüße
Jamil
Verfasst: Mittwoch 6. Dezember 2006, 18:41
von BlackJack
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)
Verfasst: Mittwoch 6. Dezember 2006, 19:20
von JR
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
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
etc. anfangen kann. Ist other frei gewählt?
Am meisten Rätsel bereitet mit folgende Methode in deinem Code:
Was tut diese Methode?
Da steckt doch sicherlich mehr dahinter, als nur ein Attribut auszulesen???
Grüße und bis gleich
Jamil
Verfasst: Mittwoch 6. Dezember 2006, 19:49
von JR
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.
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
Verfasst: Mittwoch 6. Dezember 2006, 20:25
von BlackJack
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
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
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:
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.
Verfasst: Mittwoch 6. Dezember 2006, 22:53
von Mawilo
Das ist ja klasse. Jetzt habe ich zwei Lösungen, die funktionieren
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