Tommy
Tommy

Reputation: 785

Converting list of strings to datetime

I am attempting to convert a list of strings to datetime.

Here is an example of the data I'm dealing with:
x = ['59:55:00', '59:55:00', '59:58:00', '1:00:02', '1:00:05', '1:01:26']

For example, the list is supposed to reflect 59 minutes, 58 seconds to 1 hour, 0 minutes and 5 seconds.

I understand this is a wacky format, but I'm playing with the hand I've been dealt. I'm not sure how to handle the data once I get into values that are greater than 59 minutes.

I tried using:

from datetime import datetime
for i in x:
    datetime_object = datetime.strptime(i, '%M:%S:%f')
    print(datetime_object)

My results are:

1900-01-01 00:59:55
1900-01-01 00:59:55
1900-01-01 00:59:58
1900-01-01 00:01:00.020000
1900-01-01 00:01:00.050000
1900-01-01 00:01:01.260000

I would like to keep my output to minutes and seconds. For example 1:01:26 would be 00:61:26

So my desired output would look something like:

1900-01-01 00:59:55
1900-01-01 00:59:55
1900-01-01 00:59:58
1900-01-01 00:60:02
1900-01-01 00:60:02
1900-01-01 00:61:26

Any help or guidance is greatly appreciated!

Upvotes: 3

Views: 3008

Answers (5)

jpp
jpp

Reputation: 164623

Your list contains durations rather than times. datetime.timedelta is designed for this purpose, but isn't necessary given you want a very specific string format for output.

The problem with your input data is the inconsistency of formatting. If you are willing to hard-code a limiting value for the first part, you can apply a toggle via ternary statements:

from datetime import timedelta

x = ['59:55:00', '59:55:00', '59:58:00', '1:00:02', '1:00:05', '1:01:26']

def converter(value, limit=59):
    var1, var2, var3 = map(int, value.split(':'))
    switch = var1 < limit
    mins = var1 * 60 + var2 if switch else var1
    secs = var3 if switch else var2
    return f'00:{mins:02}:{secs:02}'

res = list(map(converter, x))

print(res)
# ['00:59:55', '00:59:55', '00:59:58', '00:60:02', '00:60:05', '00:61:26']

Upvotes: 1

Ajax1234
Ajax1234

Reputation: 71451

datetime.datetime objects must take parameters that are within a certain range i.e minutes must be between 0 and 59. However, you can create a class to handle this desired behavior. The class can convert the input into the desired timestamp format, store the original string, and provide a to_date property to retrieve the actual timestamp as a datetime.datetime object:

import datetime

class Minutes:
  d = datetime.datetime.now()
  def __init__(self, _str, _year = None):
    self._val = _str
    d = datetime.datetime.now()
    self.year = _year if _year is not None else '-'.join(str(getattr(d, i)) for i in ['year', 'month', 'day'])
  @property
  def to_date(self):
    return datetime.datetime(*map(int, self.year.split('-')), *map(int, str(self).split(':')))
  def __str__(self):
    _h, _m, _s = map(int, self._val.split(':'))
    h, m, s = 0 if _h else _h, _m+(_h*60) if _h else _m, _s
    return f'{self.year} '+':'.join(str(i).zfill(2) for i in [h, m, s])
  def __repr__(self):
    return str(self)

x = ['59:55:00', '59:55:00', '59:58:00', '1:00:02', '1:00:05', '1:01:26']
new_x = [Minutes(i, '1900-01-01') for i in x]    

Output:

[1900-01-01 00:3595:00, 
 1900-01-01 00:3595:00, 
 1900-01-01 00:3598:00, 
 1900-01-01 00:60:02, 
 1900-01-01 00:60:05, 
 1900-01-01 00:61:26]

Upvotes: 2

Chris Hunt
Chris Hunt

Reputation: 4030

Given the guarantee that the data will not go back to the previous format, we can normalize it. To keep things clean this is probably better wrapped in a generator so it doesn't clutter your main application logic. For example:

def normalized(times):
    hms = False
    last_minute = 0
    for t in x:
        h, m, s = [int(i) for i in t.split(':')]
        if not hms:
            if h < last_minute:
                hms = True
            else:
                h, m, s = 0, h, m
                last_minute = m
        yield f'{h:02}:{m:02}:{s:02}'


x = ['59:55:00', '59:55:00', '59:58:00', '1:00:02', '1:00:05', '1:01:26']


for v in normalized(x):
    print(v)

results in

00:59:55
00:59:55
00:59:58
01:00:02
01:00:05
01:01:26

Now in the loop you can do whatever you want.

Upvotes: 0

Michael Butscher
Michael Butscher

Reputation: 10959

Maybe strptime isn't the right tool here (some error checking omitted for brevity):

def convert(s):
    parts = [int(i) for i in s.split(":")]

    if parts[0] < 3:  # 3 is arbitrary value, may need adaption
        # Assuming format hour:min:sec
        h, m, s = parts
        millis = 0
    else:
        # Assuming format min:sec:millisec
        m, s, millis = parts
        h = 0

    return "1900-01-01 00:{:02}:{:02}".format(h * 60 + m, s)


x = ['59:55:00', '59:55:00', '59:58:00', '1:00:02', '1:00:05', '1:01:26']

print(*(convert(i) for i in x), sep="\n")

Output:

1900-01-01 00:59:55
1900-01-01 00:59:55
1900-01-01 00:59:58
1900-01-01 00:60:02
1900-01-01 00:60:05
1900-01-01 00:61:26

Upvotes: 1

Alex Python
Alex Python

Reputation: 327

>>> time = datetime.datetime.now()
>>> halfformatted = time.strftime('00:{minutes}:%S.%f')
>>> minutes_total = time.hour * 60 + time.minute
>>> halfformatted.format(minutes=minutes_total)
'00:358:33.339341'

Upvotes: 0

Related Questions