Marius Marius - 22 days ago 9
Python Question

Keeping a strange time format, and adding values to it in python

So i have been trying to add a time format to my REST calls in python, but there seems to always be some type of issue, first of all here is the time format requirement, and it has to be exact, or it wont work unfortunately.

Use the following ISO-8601 compliant date/time format in request parameters.

yyyy-MM-dd'T'HH:mm:ss.SSSXXX

For example, May 26 2014 at 21:49:46 PM could have a format like one of the following:

l In PDT: 2014-05-26T21:49:46.000-07:00

l In UTC: 2014-05-26T21:49:46.000Z

Code Description


  • yyyy Four digit year

  • MM Two-digit month (01=January, etc.)

  • dd Two-digit day of month (01 through 31)

  • T Separator for date/time

  • HH Two digits of hour (00 through 23) (am/pm NOT allowed)

  • mm Two digits of minute (00 through 59)

  • ss Two digits of second (00 through 59)

  • SSS Three digit milliseconds of the second

  • XXX ISO 8601 time zone (Z or +hh:mm or -hh:mm)



So, what i have tried before is:

def format_time(self, isnow):
currentdt = datetime.datetime.utcnow()
if not isnow:
currentdt += datetime.timedelta(0,3)
(dt, micro) = currentdt.strftime('%Y-%m-%dT%H:%M:%S.%f').split('.')
dt = "%s.%03dZ" % (dt, int(micro) / 1000)
return dt


Now, this might return it in the kinda right format, but there is still the problem with timezones.

The end result i am trying to accomplish, is when i execute this, it finds the current time, (Amsterdam timezone/GMT/UTC+1), and creates it in this format.
And the else statement, to get the same time, but append X seconds.

Would anyone be so kind to help me out here?

Answer

Ok, so you got the microseconds formatted as milliseconds, well done there.

Now your challenge is to handle the timezone offset; it can't only be Z.

And to make things more difficult, strftime's %z format gives + (or -) HHMM, instead of HH:MM.

So you'll need to deal with that. Here's one way to do it:

Python 3:

def format_time(self, isnow):
    currentdt = datetime.datetime.now(datetime.timezone.utc)
    if not isnow:
        currentdt += datetime.timedelta(0,3)
    (dt, micro) = currentdt.strftime('%Y-%m-%dT%H:%M:%S.%f').split('.')
    tz_offset = currentdt.astimezone().strftime('%z')
    tz_offset = "Z" if tz_offset == "" else tz_offset[:3] + ":" + tz_offset[3:]

    dt = "%s.%03d%s" % (dt, int(micro) / 1000, tz_offset)
    return dt

Python 2:

import pytz
from dateutil.tz import *

def format_time(self, isnow):
    currentdt = datetime.datetime.now(pytz.utc)
    if not isnow:
        currentdt += datetime.timedelta(0,3)
    (dt, micro) = currentdt.strftime('%Y-%m-%dT%H:%M:%S.%f').split('.')
    tz_offset = currentdt.astimezone(tzlocal()).strftime('%z')
    tz_offset = "Z" if tz_offset == "" else tz_offset[:3] + ":" + tz_offset[3:]

    dt = "%s.%03d%s" % (dt, int(micro) / 1000, tz_offset)
    return dt

Response to comment: I needed to make a few changes. It's remarkably non-trivial to find the current timezone. The easiest way I could find was from http://stackoverflow.com/a/25887393/1404311 and I've integrated those concepts into the code that is now above.

Basically, instead of utcnow(), you should use now(datetime.timezone.utc). The former gives a naive datetime, while the latter gives a datetime set to UTC, but aware that it is. Then use astimezone() to make it aware of your local timezone, then use strftime('%z') to get the time offzone from there. THEN go through the string manipulation.