106

I need to produce a time string that matches the iso format yyyy-mm-ddThh:mm:ss.ssssss-ZO:NE. The now() and utcnow() class methods almost do what I want.

>>> import datetime
>>> #time adjusted for current timezone
>>> datetime.datetime.now().isoformat()
'2010-08-03T03:00:00.000000'
>>> #unadjusted UTC time
>>> datetime.datetime.utcnow().isoformat()
'2010-08-03T10:00:00.000000'
>>>
>>> #How can I do this?
>>> datetime.datetime.magic()
'2010-08-03T10:00:00.000000-07:00'
1
  • "For a datetime instance d, str(d) is equivalent to d.isoformat(' '), but I want to get d.isoformat() equivalence when using "{}".format(d), but I guess that's not going to happen. Commented Oct 16, 2023 at 1:46

7 Answers 7

162

To get the current time in UTC in Python 3.2+:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2015-01-27T05:57:31.399861+00:00'

To get local time in Python 3.3+:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).astimezone().isoformat()
'2015-01-27T06:59:17.125448+01:00'

Explanation: datetime.now(timezone.utc) produces a timezone aware datetime object in UTC time. astimezone() then changes the timezone of the datetime object, to the system's locale timezone if called with no arguments. Timezone aware datetime objects then produce the correct ISO format automatically.

Sign up to request clarification or add additional context in comments.

4 Comments

As of Python 3.6, the astimezone() method can now be called on naive instances that are presumed to represent system local time.
@A-B-B even on Python 3.6, one should use aware datetime objects that work even if the current local time is ambiguous (e.g., during a DST transition).
For anyone looking at this because it is Apache Airflow's format (as I was just stuck doing for an hour as I'm not a python guy), this is the right answer to make a current date in the same format matching airflows. Made some notes on usage / why its safe here - coding-stream-of-consciousness.com/2020/04/01/….
@JohnHumphreys-w00te the format is RFC 3339 -- a profile of the ISO 8601 standard
42

You need to make your datetime objects timezone aware. from the datetime docs:

There are two kinds of date and time objects: “naive” and “aware”. This distinction refers to whether the object has any notion of time zone, daylight saving time, or other kind of algorithmic or political time adjustment. Whether a naive datetime object represents Coordinated Universal Time (UTC), local time, or time in some other timezone is purely up to the program, just like it’s up to the program whether a particular number represents metres, miles, or mass. Naive datetime objects are easy to understand and to work with, at the cost of ignoring some aspects of reality.

When you have an aware datetime object, you can use isoformat() and get the output you need.

To make your datetime objects aware, you'll need to subclass tzinfo, like the second example in here, or simpler - use a package that does it for you, like pytz or python-dateutil

Using pytz, this would look like:

import datetime, pytz
datetime.datetime.now(timezone.utc).isoformat()

You can also control the output format, if you use strftime with the '%z' format directive like

datetime.datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%f%z')

7 Comments

Not entirely correct: the %z format directive prints the time zone offset without a colon, the ISO format however separates hours and minutes in the TZ specifier with a colon. However, calling the isoformat() method on a timezone-aware datetime will work!
A timezone aware datetime will format correctly with .isoformat().
To expand on the comment from @DavidK.Hess , the strftime in your second example is overly complicated. The following works and (imo) is cleaner: datetime.now().replace(tzinfo=pytz.timezone("US/Eastern")).isoformat()
Thanks @jedwards and David - I added that to the answer.
@jedwards: do not use datetime.replace() with a pytz timezone that might have multiple UTC offsets (at different times).
|
17

With arrow:

>>> import arrow
>>> arrow.now().isoformat()
'2015-04-17T06:36:49.463207-05:00'
>>> arrow.utcnow().isoformat()
'2015-04-17T11:37:17.042330+00:00'

Comments

7

You can do it in Python 2.7+ with python-dateutil (which is insalled on Mac by default):

>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> datetime.now(tzlocal()).isoformat()
'2016-10-22T12:45:45.353489-03:00'

Or you if you want to convert from an existed stored string:

>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> from dateutil.parser import parse
>>> parse("2016-10-21T16:33:27.696173").replace(tzinfo=tzlocal()).isoformat()
'2016-10-21T16:33:27.696173-03:00' <-- Atlantic Daylight Time (ADT) 
>>> parse("2016-01-21T16:33:27.696173").replace(tzinfo=tzlocal()).isoformat()
'2016-01-21T16:33:27.696173-04:00' <-- Atlantic Standard Time (AST)

Comments

3

Nine years later. If you know your time zone. I like the T between date and time. And if you don't want microseconds.

Python <= 3.8

pip3 install pytz  # needed!

python3
>>> import datetime
>>> import pytz
>>> datetime.datetime.now(pytz.timezone('Europe/Berlin')).isoformat('T', 'seconds')
'2020-11-09T18:23:28+01:00'

Tested on Ubuntu 18.04 and Python 3.6.9.


Python >= 3.9

pip3 install tzdata  # only on Windows needed!

py -3
>>> import datetime
>>> import zoneinfo
>>> datetime.datetime.now(zoneinfo.ZoneInfo('Europe/Berlin')).isoformat('T', 'seconds')
'2020-11-09T18:39:36+01:00'

Tested on Windows 10 and Python 3.9.0.

1 Comment

The "T" is the default, but of course explicit is better than implicit in which case datetime.datetime.now(pytz.timezone('Europe/Berlin')).isoformat(sep='T', timespec='seconds')
0

Related:

If you date time string from json like Tue Feb 04 18:34:08 +0000 2025 assumed to be in UTC, how do you convert to iso format with timezone?

Note that the default conversion doesn't include time zone:

datetime.strptime(date_str, "%a %b %d %H:%M:%S +0000 %Y").isoformat()
# '2025-02-04T18:34:08'

The replace doesn't work as others have pointed out. The trick is:

datetime.strptime(date_str, "%a %b %d %H:%M:%S +0000 %Y").astimezone(timezone.utc).isoformat()
# '2025-02-05T02:34:08+00:00'

Comments

-16

Something like the following example. Note I'm in Eastern Australia (UTC + 10 hours at the moment).

>>> import datetime
>>> dtnow = datetime.datetime.now();dtutcnow = datetime.datetime.utcnow()
>>> dtnow
datetime.datetime(2010, 8, 4, 9, 33, 9, 890000)
>>> dtutcnow
datetime.datetime(2010, 8, 3, 23, 33, 9, 890000)
>>> delta = dtnow - dtutcnow
>>> delta
datetime.timedelta(0, 36000)
>>> hh,mm = divmod((delta.days * 24*60*60 + delta.seconds + 30) // 60, 60)
>>> hh,mm
(10, 0)
>>> "%s%+02d:%02d" % (dtnow.isoformat(), hh, mm)
'2010-08-04T09:33:09.890000+10:00'
>>>

4 Comments

Small fix for formatting: "%s%+03d:%02d" % (dtnow.isoformat(), hh, mm)
Using subtraction to determine the difference between your own timezone and any other is fraught with dangers. Much better are the solutions where you provide the timezone.
I agree: don't use this solution. Don't reinvent the wheel.
This should not be the accepted answer, see the other answers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.