Is there an implementation of strfdelta()
and deltafstr()
functions for Python similar to the way that strftime()
works on a datetime
object?
There are similar questions on this...
... but no consistent way of being able to convert back and forth between the two formats.
I want to be able to convert from timedelta
to string
, and then back to timedelta
.
The intended use is for a Hadoop mapper/reducer process (the intermediate delta time output from the mapper script, for input into the reducer script).
After searching for such functions, and not being able to find one that converts back and forth, I wrote the following two functions and include them in a script. This is compatible with Python v2.6.6, which doesn't support some newer features such as timedelta.total_seconds()
:
#!/usr/bin/python
import re
import sys
import datetime
# String from Date/Time Delta:
# Takes a datetime.timedelta object, and converts the internal values
# to a dd:HH:mm:ss:ffffff string, prefixed with "-" if the delta is
# negative
def strfdelta(tdelta):
# Handle Negative time deltas
negativeSymbol = ""
if tdelta < datetime.timedelta(0):
negativeSymbol = "-"
# Convert days to seconds, as individual components could
# possibly both be negative
tdSeconds = (tdelta.seconds) + (tdelta.days * 86400)
# Capture +/- state of seconds for later user with milliseonds calculation
secsNegMultiplier = 1
if tdSeconds < 0:
secsNegMultiplier = -1
# Extract minutes from seconds
tdMinutes, tdSeconds = divmod(abs(tdSeconds), 60)
# Extract hours from minutes
tdHours, tdMinutes = divmod(tdMinutes, 60)
# Extract days from hours
tdDays, tdHours = divmod(tdHours, 24)
# Convert seconds to microseconds, as individual components
# could possibly both be negative
tdMicroseconds = (tdelta.microseconds) + (tdSeconds * 1000000 * secsNegMultiplier)
# Get seconds and microsecond components
tdSeconds, tdMicroseconds = divmod( abs(tdMicroseconds), 1000000)
return "{negSymbol}{days}:{hours:02d}:{minutes:02d}:{seconds:02d}:{microseconds:06d}".format(
negSymbol=negativeSymbol,
days=tdDays,
hours=tdHours,
minutes=tdMinutes,
seconds=tdSeconds,
microseconds=tdMicroseconds)
# Date/Time delta from string
# Example: -1:23:32:59:020030 (negative sign optional)
def deltafstr(stringDelta):
# Regular expression to capture status change events, with groups for date/time,
# instrument ID and state
regex = re.compile("^(-?)(\d{1,6}):([01]?\d|2[0-3]):([0-5][0-9]):([0-5][0-9]):(\d{6})$",re.UNICODE)
matchObj = regex.search(stringDelta)
# If this line doesn't match, return None
if(matchObj is None):
return None;
# Debug - Capture date-time from regular expression
# for g in range(0, 7):
# print "Grp {grp}: ".format(grp=g) + str(matchObj.group(g))
# Get Seconds multiplier (-ve sign at start)
secsNegMultiplier = 1
if matchObj.group(1):
secsNegMultiplier = -1
# Get time components
tdDays = int(matchObj.group(2)) * secsNegMultiplier
tdHours = int(matchObj.group(3)) * secsNegMultiplier
tdMinutes = int(matchObj.group(4)) * secsNegMultiplier
tdSeconds = int(matchObj.group(5)) * secsNegMultiplier
tdMicroseconds = int(matchObj.group(6)) * secsNegMultiplier
# Prepare return timedelta
retTimedelta = datetime.timedelta(
days=tdDays,
hours=tdHours,
minutes=tdMinutes,
seconds=tdSeconds,
microseconds=tdMicroseconds)
return retTimedelta;
Here is some code that tests going back and forward between the two formats. The constructor arguments for the timedelta
object may be changed to test different scenarios:
# Testing (change the constructor for timedelta to test other cases)
firstDelta = datetime.timedelta(seconds=-1,microseconds=999999, days=-1)
print "--------"
print firstDelta
firstDeltaStr = strfdelta(firstDelta)
print "--------"
print firstDeltaStr;
secondDelta = deltafstr(firstDeltaStr)
print "--------"
print secondDelta
secondDeltaStr = strfdelta(secondDelta)
print "--------"
print secondDelta
print "--------"