13

I'm new to Python and I cannot for the life of me find my specific answer online. I need to format a timestamp to this exact format to include 'T', 'Z' and no sub or miliseconds like this yyyy-mm-ddThh:mm:ssZ i.e. 2019-03-06T11:22:00Z. There's lots of stuff on parsing this format but nothing about formatting this way. The only way I have nearly got it to work involves sub-seconds which I do not need. I've tried using arrow and reading their documentation but unable to get anything to work. Any help would be appreciated.

ra67052
  • 449
  • 2
  • 4
  • 15
  • Please, provide an Input with an expected output along with what you've tried. – DirtyBit Mar 06 '19 at 11:29
  • https://stackoverflow.com/questions/46318714/how-do-i-generate-a-python-timestamp-to-a-particular-format I think this will solve your problem – Aman Jaiswal Mar 06 '19 at 11:29
  • Possible duplicate of [python getting date from string](https://stackoverflow.com/questions/54782989/python-getting-date-from-string) – DirtyBit Mar 06 '19 at 11:30
  • Does this answer your question? [How do I turn a python datetime into a string, with readable format date?](https://stackoverflow.com/questions/2158347/how-do-i-turn-a-python-datetime-into-a-string-with-readable-format-date) – questionto42 Mar 15 '22 at 20:00

4 Answers4

28

Try datetime library

import datetime

output_date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
print(output_date)

For more information, refer to the Python Documentation.

Toastrackenigma
  • 7,604
  • 4
  • 45
  • 55
skaul05
  • 2,154
  • 3
  • 16
  • 26
  • Thanks I've tried that but that gives me milisecond or sub-seconds and I need the sub seconds removed but having messed about with the code you gave me I got it to work :) date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ") print(date) – ra67052 Mar 06 '19 at 11:32
16

Be careful. Just be cause a date can be formatted to look like UTC, doesn't mean it's accurate.

In ISO 8601, 'Z' is meant to designate "zulu time" or UTC ('+00:00'). While local times are typically designated by their offset from UTC. Even worse, these offsets can change throughout a year due to Daylight Saving Time (DST).

So unless you live in England in the winter or Iceland in the summer, chances are, you aren't lucky enough to be working with UTC locally, and your timestamps will be completely wrong.

Python3.8

from datetime import datetime, timezone

# a naive datetime representing local time
naive_dt = datetime.now()

# incorrect, local (MST) time made to look like UTC (very, very bad)
>>> naive_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
'2020-08-27T20:57:54Z'   # actual UTC == '2020-08-28T02:57:54Z'

# so we'll need an aware datetime (taking your timezone into consideration)
# NOTE: I imagine this works with DST, but I haven't verified

aware_dt = naive_dt.astimezone()

# correct, ISO-8601 (but not UTC)
>>> aware_dt.isoformat(timespec='seconds')
'2020-08-27T20:57:54-06:00'

# lets get the time in UTC
utc_dt = aware_dt.astimezone(timezone.utc)

# correct, ISO-8601 and UTC (but not in UTC format)
>>> utc_dt.isoformat(timespec='seconds')
'2020-08-28T02:57:54+00:00'

# correct, UTC format (this is what you asked for)
>>> date_str = utc_dt.isoformat(timespec='seconds')
>>> date_str.replace('+00:00', 'Z')
'2020-08-28T02:57:54Z'

# Perfect UTC format
>>> date_str = utc_dt.isoformat(timespec='milliseconds')
>>> date_str.replace('+00:00', 'Z')
'2020-08-28T02:57:54.640Z'

I just wanted to illustrate some things above, there are much simpler ways:

from datetime import datetime, timezone


def utcformat(dt, timespec='milliseconds'):
    """convert datetime to string in UTC format (YYYY-mm-ddTHH:MM:SS.mmmZ)"""
    iso_str = dt.astimezone(timezone.utc).isoformat('T', timespec)
    return iso_str.replace('+00:00', 'Z')


def fromutcformat(utc_str, tz=None):
    iso_str = utc_str.replace('Z', '+00:00')
    return datetime.fromisoformat(iso_str).astimezone(tz)


now = datetime.now(tz=timezone.utc)

# default with milliseconds ('2020-08-28T02:57:54.640Z')
print(utcformat(now))

# without milliseconds ('2020-08-28T02:57:54Z')
print(utcformat(now, timespec='seconds'))


>>> utc_str1 = '2020-08-28T04:35:35.455Z'
>>> dt = fromutcformat(utc_string)
>>> utc_str2 = utcformat(dt)
>>> utc_str1 == utc_str2
True

# it even converts naive local datetimes correctly (as of Python 3.8)
>>> now = datetime.now()
>>> utc_string = utcformat(now)

>>> converted = fromutcformat(utc_string)
>>> now.astimezone() - converted
timedelta(microseconds=997)

Sam
  • 181
  • 1
  • 4
  • Thank you, had not thought about that, thankfully the app runs on UTC to get over the daylight saving issue, the use of the 'Z' was specified in the interface message in the JSON hence why we had to use that. However, this post is very insightful and will keep that in my back pocket. – ra67052 Oct 16 '20 at 17:25
  • @Sam: I have similar requirement, could you please advise how we can take account of daylight saving on and off. – Gaurav Parek Aug 30 '21 at 12:08
2

Thanks to skaul05 I managed to get the code I needed, it's

date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
print(date)
Vladimir Vagaytsev
  • 2,871
  • 9
  • 33
  • 36
ra67052
  • 449
  • 2
  • 4
  • 15
0

With f strings, you can shorten it down to:

from datetime import datetime

f'{datetime.now():%Y-%m-%dT%H:%M:%SZ}'

Credits go to How do I turn a python datetime into a string, with readable format date?.

questionto42
  • 7,175
  • 4
  • 57
  • 90