Search code examples
pythonpython-3.xpytz

fractions of seconds and pytz: do you have a cleaner solution?


I have times in a log that look like this:

1440498131.372625

What I've done using pytz is

utc = pytz.utc
for anra in raFromMCCS:
    fsecs = float(anra.time)
    isecs = int(fsecs)
    isec2 = int(fsecs * 1000)
    dt = datetime.utcfromtimestamp(isecs).replace(tzinfo=utc)
    #print (dt.year)
    dt2 = utc.localize(datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, int((fsecs - isecs) * 1000000)))
    #      dt3 = datetime.utcfromtimestamp(isec2)
    print(dt, dt2)#, dt3)  

I left in the stupid dt3 attempt to show I'm new to all sorts of things here.

I know that dt2 gives me what I want but it seems like a roundabout way to get there. If you have a nicer solution, please let me know.

Thanks!


Solution

  • You could pass the float to fromtimestamp() directly:

    d = datetime.fromtimestamp(1440498131.372625, utc)
    

    If you know that the input is POSIX time (non-"right" timezone) then you could use the direct formula:

    d = datetime(1970, 1, 1, tzinfo=utc) + timedelta(seconds=1440498131.372625)
    

    It should provide a portable (wider) range for input timestamps. The rounding behavior should be more consistent between Python versions, see datetime.utcfromtimestamp rounds results incorrectly.

    If input is a string; you could parse microseconds using strptime('%f'):

    from datetime import datetime, timedelta
    
    seconds, dot, us = "1440498131.372625".partition('.')
    d = datetime(1970, 1, 1, tzinfo=timezone.utc) + timedelta(seconds=int(seconds))
    if dot:
        d = d.replace(microsecond=datetime.strptime(us, '%f').microsecond)
    

    where timezone.utc is defined here. It also works if microseconds are represented using less than 6 digits e.g., ".372".

    Only the last code example guarantees to preserve microseconds for any input timestamp.