Serializing / Unserializing datetime

B

Brendan

Hi All

I can't find the "Python Way" of writing a datetime instance to a
string so that it can be easily parsed back again. time.strptime is
apparantly not supported on some platforms, and time.time <==>
datetime.utcfromtimestamp will cause problems come 2038. Unfortunately
there don't seem to be "fromstring" equivalents for datetime.ctime or
datetime.isoformat.

Ideally the serialized datetime should be human readable, and
potentially parseable from other languages. Any suggestions?

Brendan
 
J

John Machin

Hi All

I can't find the "Python Way" of writing a datetime instance to a
string so that it can be easily parsed back again. time.strptime is
apparantly not supported on some platforms, and time.time <==>
datetime.utcfromtimestamp will cause problems come 2038. Unfortunately
there don't seem to be "fromstring" equivalents for datetime.ctime or
datetime.isoformat.

Ideally the serialized datetime should be human readable, and
potentially parseable from other languages. Any suggestions?

It's not that hard to DIY; the simple code at the end of this posting
(1) handles fractions of a second [which you may or may not want]
without burdening the network or the readers' eyeballs with excess
trailing zeroes (2) doesn't handle TZs [which you may or may not want].

Some further validation on input strings may be a good idea, if you need
to eat other software's strings as well as yours. E.g. check that where
the '-' characters should be that you find nothing stranger than '.' or
'/'; certainly not digits.

HTH,
John

8<---
import datetime

def datetime_from_str(s):
# YYYY-MM-DD HH:MM:SS.TTT
# 01234567890123456789012
year = int(s[0:4])
month = int(s[5:7])
day = int(s[8:10])
hour = int(s[11:13])
minute = int(s[14:16])
microseconds = int(float(s[17:]) * 1000000.0)
second, microsecond = divmod(microseconds, 1000000)
return datetime.datetime(year, month, day, hour, minute, second,
microsecond)

def datetime_as_str(dtm):
part1 = dtm.strftime("%Y-%m-%d %H:%M:%S")
micros = dtm.microsecond
if not micros:
return part1
part2 = (".%06d" % micros).rstrip('0')
return part1 + part2

if __name__ == "__main__":
tests = [
'1999-12-31 23:59:59.999999',
'1999-12-31 23:59:59.99999999',
'1999-12-31 23:59:59.999',
'1999-12-31 23:59:59',
'2000-01-01 00:00:00.000',
'2000-01-01 00:00:00',
'2000-01-01 00:00:00.000001',
'2000-01-01 00:00:00.001',
]
for test in tests:
dtm = datetime_from_str(test)
print "input str: ", repr(test)
print "datetime: ", repr(dtm)
round_trip = datetime_as_str(dtm)
print "output str:", repr(round_trip), ["not same",
""][round_trip == test]
print
8<---
 
G

Gerard Flanagan

Brendan said:
Thanks John. I've discovered that datetime.strptime will be available
in 2.5, (http://docs.python.org/dev/whatsnew/modules.html) but your
example will work in the meantime.

BJ

I don't think it's what you want but I had the following on file - it
uses time.strptime() which I didn't know there was a problem with. Not
tested beyond what you see.

--------------------------------------------------------------------------------
import time
import datetime

DDMMYY = ['%d %m %Y', '%d %m %y', '%d/%m/%Y', '%d/%m/%y', '%d-%m-%Y',
'%d-%m-%y' ]

def yearmonthday(datestring, fmts=DDMMYY):
ymd = None
for f in fmts:
try:
ymd = time.strptime( datestring, f )
break
except ValueError:
continue
if ymd is None:
raise ValueError
return ymd[0], ymd[1], ymd[2]

def is_valid_date(datestring, fmts=DDMMYY):
try:
yearmonthday(datestring, fmts)
return True
except ValueError:
return False

def string_to_date(datestring, fmts=DDMMYY):
return datetime.date( *yearmonthday(datestring, fmts) )

assert string_to_date( '1/2/01', DDMMYY) == datetime.date(2001,2,1)
assert string_to_date( '1 2 01', DDMMYY) == datetime.date(2001,2,1)
assert string_to_date( '01/02/01', DDMMYY) == datetime.date(2001,2,1)
assert string_to_date( '1/02/2001', DDMMYY) == datetime.date(2001,2,1)
assert string_to_date( '29/02/2008', DDMMYY) ==
datetime.date(2008,2,29)
assert string_to_date( '01/2/99', DDMMYY) == datetime.date(1999,2,1)

for d in [ '', '32/1/01', '01/13/01', '29/2/07', '1/2', 'abcdef' ]:
assert not is_valid_date(d, DDMMYY)
 
J

John Machin

Thanks John. I've discovered that datetime.strptime will be available
in 2.5, (http://docs.python.org/dev/whatsnew/modules.html) but your
example will work in the meantime.

Only in the meantime? I would thought there was a good chance it would
continue to work in 2.5 -- especially as I tested it with 2.5a2 :)

Hmmm ... now you've got me thinking, maybe there's an anti-DIY
enforced-use-of-official-functionality gadget in 2.5. Just because I'm
paranoid doesn't mean the PSU isn't out to ~;{[]=]|\ <no connection>
 
J

John Machin

I don't think it's what you want but I had the following on file - it
uses time.strptime() which I didn't know there was a problem with.

In 2.3, time.strptime became a pure-Python routine, thus losing its
dependency on the existence and correctness of the strptime in the C
library.

However, the whole time module has a problem: the range of years it
handles -- 1970 to 2038 (maybe). This is documented on the first page of
The Fine Manual. Not very useful for customer's date of birth, and (as
Brendan indicated), likely to cause Y2.038K problems.

Cheers,
John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top