1

I have exported some data from another programm, where I added up time for a station waiting. So after some time, I have the format '32:00:00:33.7317' for the waiting time.

This is my function to convert every date into the format I want:

def Datum_formatieren(Datensatz):
    if len(str(Datensatz)) == 24:
        return datetime.datetime.strptime(Datensatz, "%d.%m.%Y %H:%M:%S.%f").strftime("%d%H%M")
    elif len(str(Datensatz)) == 3:
        return 0
        #return datetime.datetime.strptime(Datensatz, "%S.%f").strftime("%d%H%M")
    elif len(str(Datensatz)) == 5:
        return str(Datensatz)
    elif len(str(Datensatz)) == 7:
        return str(Datensatz)
    elif len(str(Datensatz)) == 6:
        return datetime.datetime.strptime(str(Datensatz), "%S.%f").strftime("%d%H%M")
    elif len(str(Datensatz)) == 9 or len(str(Datensatz))==10:
        return datetime.datetime.strptime(str(Datensatz), "%M:%S.%f").strftime("%d%H%M")
    elif len(str(Datensatz)) == 12 or len(str(Datensatz)) ==13:
        return datetime.datetime.strptime(str(Datensatz), "%H:%M:%S.%f").strftime("%d%H%M")
    elif len(str(Datensatz)) == 15 or len(str(Datensatz)) == 16:
        return datetime.datetime.strptime(str(Datensatz), "%d:%H:%M:%S.%f").strftime("%d%H%M")

I get the following error since python does not recognize days above 30 or 31:

ValueError: time data '32:00:00:33.7317' does not match format '%d:%H:%M:%S.%f'

How do I convert all entries with days above 31 into a format, which python can recognize?

  • Why are you using `str()` on `Datensatz`? It's almost always an error to use `str()` and then parse the result. Can you try skipping the `str()` and formatting the value directly from `Datensatz`? – Jiří Baum Mar 18 '22 at 08:31
  • Because I need to know the length of the date i want to convert into the needed format. The formats are always different depending on the length of the entry – Tarik Benrabah Mar 18 '22 at 09:09
  • You should be able to get that directly from `Datensatz`; what type is it? – Jiří Baum Mar 18 '22 at 09:20

3 Answers3

1

You cannot use datetime.datetime.strptime() to construct datetimes that are invalid - why see other answer.

You can however leverage datetime.timespan:

import datetime 

def Datum_formatieren(Datensatz):        
    # other cases omitted for brevity

    # Input:  "days:hours:minutes:seconds.ms"
    if len(Datensatz) in (15,16):
        k = list(map(float,Datensatz.split(":")))
        secs = k[0]*60*60*24 + k[1]*60*60 + k[2]*60 + k[3]  
        td = datetime.timedelta(seconds=secs)
        days = td.total_seconds() / 24 / 60 // 60
        hours = (td.total_seconds() - days * 24*60*60) / 60 // 60
        minuts = (td.total_seconds() - days *24*60*60 - hours * 60*60) // 60
        print(td)
        return f"{td.days}{int(hours):02d}{int(minuts):02d}"

print(Datum_formatieren("32:32:74:33.731"))

Output for "32:32:74:33.731":

33 days, 9:14:33.731000   # timespan
330914                    # manually parsed
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
0

You are misusing datetime wich only map to correct dates with times - not "any amount time passed".

Use a timedelta instead:

Adapted from datetime.timedelta:

from datetime import datetime, timedelta
delta = timedelta( days=50, seconds=27, microseconds=10, 
                   milliseconds=29000, minutes=5, hours=8, weeks=2 )

print(datetime.now() + delta)

You can add any timedelta to a normal datetime and get the resulting value.


If you want to stick wich your approach you may want to shorten it:

 if len(str(Datensatz)) == 9 or len(str(Datensatz))==10:
 if len(Datensatz) in (9,10):

Related: How to construct a timedelta object from a simple string (look at its answers and take inspiration with attribution from it)

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • Looking at the code in thequestion, it's quite possible `Datensatz` is already `timedelta` – Jiří Baum Mar 18 '22 at 08:34
  • @JiříBaum Datensatz is a string that is parsed via `datetime.datetime.strptime()` wich leads to a DateTime. That is then formatted back into a string. You cannot have a "DateTime" with a dayvalue of 32 - that is the problem here. – Patrick Artner Mar 18 '22 at 09:47
  • The code works so far, the only problem I have is that i get an error, if the %d is above 31 as python does not recognize days above 31 – Tarik Benrabah Mar 18 '22 at 09:51
  • @Tarik - DateTime - Objects describe a DATE. `datetime.datetime.strptime()` returns a DateTime. Give me one calenderial Date that has a dayvalue of 32. This will also crash for *all invalid dates*: Februar has only 28 or 29 days depending on the year - try to create a string of length 24 `Datensatz = "30.02.2022 10:10:10.4444" ` and feed it into your function. – Patrick Artner Mar 18 '22 at 09:56
  • Yes, I get what you are saying, but I need these values in the format that they are counting the days, so could i somehow convert each entry, which has days > 31 into month:1 and days:0 So "32:00:00:33.7317" becomes "01:00:00:00:33.7317" – Tarik Benrabah Mar 18 '22 at 10:03
  • @PatrickArtner - it looks like `Datensatz` is _not_ a string; the code always uses it as `str(Datensatz)` so it looks like it's originally a different type. That type probably has direct access to the number of days, hours, minutes, seconds etc. – Jiří Baum Mar 18 '22 at 10:30
  • @JiříBaum ... _ '32:00:00:33.7317' _ is a string - thats directly from the question. And you can do `str(str(str(str("of this string"))))` all day long .... and still feed it a string. The code uses `datetime.datetime.strptime(Datensatz, "%d.%m.%Y %H:%M:%S.%f")` without str as well - the str is only needlessly used for len() measurement. – Patrick Artner Mar 18 '22 at 10:40
  • Sure; I have a hunch `Datensatz` is not a string, though – Jiří Baum Mar 18 '22 at 10:42
0
  • You're taking the Datensatz variable, converting it to string using str(), then parsing it back into an internal representation; there is almost always a better way to do it.

    Can you check what type the Datensatz variable has, perhaps print(type(Datensatz)) or based on the rest of your code?

    Most likely the Datensatz variable already has fields for the number of days, hours, minutes and seconds. It's usually much better to base your logic on those directly, rather than converting to string and back.

  • As others have pointed out, you're trying to use a datetime.datetime to represent a time interval; this is incorrect. Instead, you need to either:

    • Use the datetime.timedelta type, which is designed for time intervals. It can handle periods over 30 days correctly:

      >>> print(datetime.timedelta(days=32, seconds=12345))
      32 days, 3:25:45
      >>> 
      
    • Since your function is named Datum_formatieren, perhaps you intend to take Datensatz and convert it to string, for output to the user or to another system.

      In that case, you should take the fields directly in Datensatz and convert them appropriately, perhaps using f-strings or % formatting. Depending on the situation, you may need to do some arithmetic. The details will depend on the type of Datensatz and the format you need on the output.

Jiří Baum
  • 6,697
  • 2
  • 17
  • 17