59

I have a python datetime object (representing five minutes from now) which I would like to convert to UTC. I am planning to output it in RFC 2822 format to put in an HTTP header, but I am not sure if that matters for this question. I found some information on this site about converting time objects, and it looks simpler that way, but this time I really want to use datetime objects, because I am using timedeltas to adjust them:

I tried something like this:

from datetime import datetime, timedelta

now = datetime.now()
fiveMinutesLater = datetime.now() + timedelta(minutes=5)
fiveMinutesLaterUtc = ???

Nothing in the time or datetime module looks like it would help me. It seems like I may be able to do it by passing the datetime object through 3 or 4 functions, but I am wondering if there is a simpler way.

I would prefer not to use third-party modules, but I may if it is the only reasonable choice.

Flimm
  • 136,138
  • 45
  • 251
  • 267
Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148

9 Answers9

63

Run this to obtain a naive datetime in UTC (and to add five minutes to it):

>>> from datetime import datetime, timedelta
>>> datetime.utcnow()
datetime.datetime(2021, 1, 26, 15, 41, 52, 441598)
>>> datetime.utcnow() + timedelta(minutes=5)
datetime.datetime(2021, 1, 26, 15, 46, 52, 441598)

If you would prefer a timezone-aware datetime object, run this in Python 3.2 or higher:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc)
datetime.datetime(2021, 1, 26, 15, 43, 54, 379421, tzinfo=datetime.timezone.utc)
Flimm
  • 136,138
  • 45
  • 251
  • 267
Senyai
  • 1,395
  • 1
  • 17
  • 26
  • 8
    Weird that no-one mentioned that `utcnow()` [returns](https://docs.python.org/3/library/datetime.html#datetime.datetime.utcnow) a ["naive" datetime object -- with no timezone info](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects), -- so it's very likely not what you want. The documentation even has a warning about this. – Nickolay Feb 13 '20 at 16:44
  • 2
    I've edited the answer to give both options of a naive datetime and an aware datetime. – Flimm Jan 26 '21 at 15:48
11

First you need to make sure the datetime is a timezone-aware object by setting its tzinfo member:

http://docs.python.org/library/datetime.html#datetime.tzinfo

You can then use the .astimezone() function to convert it:

http://docs.python.org/library/datetime.html#datetime.datetime.astimezone

Amber
  • 507,862
  • 82
  • 626
  • 550
  • 1
    According to the docs, I need to come up with a subclass of the tzinfo class to come up with an object that I can pass to the "now" function to make it aware of my server's time zone. That seems kind of complicated. Does anyone know a simpler way? If I find a simpler way, I will post it here. – Elias Zamaria Jul 26 '10 at 00:26
  • 7
    @mikez302 - Look into the pytz module. It is effectively a database of datetime.tzinfo timezone definitions for all common timezones. – Joe Kington Jul 27 '10 at 19:07
  • @EliasZamaria: to get the local timezone as `pytz` tzinfo object, you could [use `tzlocal.get_localzone()`](http://stackoverflow.com/q/13218506/4279) – jfs Mar 27 '15 at 09:17
  • This was simplified in Python 3.3 (which supports `.astimezone()` to set the timezone of a naive datetime object to the local (system) timezone, and further simplified in Python 3.6 which allows you to simply use `dt.astimezone(timezone.utc)` -- see [Carlos A. Ibarra's answer](https://stackoverflow.com/a/59336611/1026) for details. – Nickolay Feb 13 '20 at 16:36
6

For those who ended up here looking for a way to convert a datetime object to UTC seconds since UNIX epoch:

import time
import datetime

t = datetime.datetime.now()
utc_seconds = time.mktime(t.timetuple())
ishmael
  • 1,796
  • 3
  • 18
  • 19
  • 4
    That's not accurate, from mktime doc: Convert a time tuple in local time to seconds since the Epoch. – Esteban Feldman Feb 10 '12 at 22:35
  • 2
    this is not the answer to the question the OP asked. :( – sneak Feb 27 '13 at 18:44
  • note: local time maybe ambiguous (e.g., during a "fall back" DST transition) and there is 50% that `mktime()` may return a wrong value. It also fails if the local timezone had/will have a different utc offset in the past/future (many timezones do) *and* C `mktime()` does not use the tz database (e.g., on Windows). The portable solution to convert a naive datetime object representing local time to UTC is to [use `tzlocal.get_localzone()` to get the local timezone as `pytz` tzinfo object](http://stackoverflow.com/q/13218506/4279) – jfs Mar 27 '15 at 08:37
3

Use the following:

from datetime import timezone
utc_datetime = local_datetime.astimezone().astimezone(timezone.utc).replace(tzinfo=None)

Given a naive datetime object assumed to have a local datetime, you can use the following sequence of method calls to convert it to a naive UTC datetime representing the same UTC time (tested with Python 3.6.3).

  1. astimezone() to add the local timezone so it's no longer naive.
  2. astimezone(timezone.utc) to convert it from local to UTC.
  3. replace(tzinfo=None) to remove the timezone so it's naive again, but now UTC

Example:

>>> local_datetime = datetime.now()
>>> local_datetime
datetime.datetime(2019, 12, 14, 10, 30, 37, 91818)
>>> local_datetime.astimezone()
datetime.datetime(2019, 12, 14, 10, 30, 37, 91818, tzinfo=datetime.timezone(datetime.timedelta(-1, 68400), 'Eastern Standard Time'))
>>> local_datetime.astimezone().astimezone(timezone.utc)
datetime.datetime(2019, 12, 14, 15, 30, 37, 91818, tzinfo=datetime.timezone.utc)
>>> local_datetime.astimezone().astimezone(timezone.utc).replace(tzinfo=None)
datetime.datetime(2019, 12, 14, 15, 30, 37, 91818)

Note: The first astimezone() is not really needed because of this note in the Python docs:

Changed in version 3.6: The astimezone() method can now be called on naive instances that are presumed to represent system local time.

Carlos A. Ibarra
  • 6,002
  • 1
  • 28
  • 38
  • Thanks! So simply `local_datetime.astimezone(timezone.utc)` if you're fine with having a timezone-[aware](https://docs.python.org/3/library/datetime.html#aware-and-naive-objects) datetime object and are running on Python 3.6 or later. This answer does not apply to Python < 3.3. – Nickolay Feb 13 '20 at 16:30
2

Here's a stdlib solution (no 3rd-party modules) that works on both Python 2 and 3.

To get the current UTC time in RFC 2822 format:

>>> from email.utils import formatdate
>>> formatdate(usegmt=True)
'Fri, 27 Mar 2015 08:29:20 GMT'

To get the UTC time 5 minutes into the future:

#!/usr/bin/env python
import time
from email.utils import formatdate

print(formatdate(time.time() + 300, usegmt=True)) # 5 minutes into the future
# -> Fri, 27 Mar 2015 08:34:20 GMT
jfs
  • 399,953
  • 195
  • 994
  • 1,670
2

I found a way to take the current time, add a timedelta object to it, convert the result to UTC, and output it in RFC 2822:

time.strftime("%a, %d-%b-%Y %H:%M:%S GMT",
    time.gmtime(time.time() + datetime.timedelta(minutes=5).seconds))

This did not exactly answer my question, but I am putting it here because it may help someone else in my situation.

EDIT: I would like to add that this trick only works if the timedelta is less than one day. If you want something that works with any sort of timedelta value, you can use timedelta.total_seconds() (for Python 2.7 and later), or with 86400*timedelta.days + timedelta.seconds. I haven't actually tried this so I'm not 100% sure if it will work.

Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148
  • note: `%b` may be locale-dependent. [Use email.utils.formatdate instead](http://stackoverflow.com/a/29296267/4279). Unrelated: `86400*timedelta.days + timedelta.seconds` always works if you need to support Python 2.6+ and don't care about microseconds. – jfs Mar 27 '15 at 08:51
1

You can use the formatdate method in the email.Utils module like follows

>>> from email.Utils import formatdate
>>> print formatdate()
Sun, 25 Jul 2010 04:02:52 -0000

The above is date time in RFC 2822 format. By default it returns UTC time but in-case you need local time you can call formatdate(localtime=True).

For more information do check http://docs.python.org/library/email.mime.html#module-email.util

GeekTantra
  • 11,580
  • 6
  • 41
  • 55
  • 1
    it won't work in Python 3; you could [use `email.utils` (lowecase) instead](http://stackoverflow.com/a/29296267/4279) – jfs Mar 27 '15 at 08:42
1

To convert to UTC from a date string:

from time import mktime
from datetime import datetime

mktime(datetime.utctimetuple(datetime.strptime("20110830_1117","%Y%m%d_%H%M")))
ElaineN
  • 35
  • 1
  • 1
    This will not work --- mktime uses the local timezone. See http://stackoverflow.com/questions/2956886/python-calendar-timegm-vs-time-mktime – teu Oct 30 '14 at 19:38
0

solution with fantastic Delorean lib:

>>> import datetime
>>> import delorean
>>> dt = datetime.datetime.now()
>>> dl = delorean.Delorean(dt, timezone='US/Pacific')
>>> dl.shift('UTC')
Delorean(datetime=2015-03-27 03:12:42.674591+00:00, timezone=UTC)

>>> dl.shift('UTC').datetime
datetime.datetime(2015, 3, 27, 3, 12, 42, 674591, tzinfo=<UTC>)

>>> dl.shift('EST').datetime
datetime.datetime(2015, 3, 26, 22, 12, 42, 674591, tzinfo=<StaticTzInfo 'EST'>)

it allows to shift datetime between different timezones easily

DmitrySemenov
  • 9,204
  • 15
  • 76
  • 121
  • 2
    I wouldn't trust it too much, given that [`delorean`'s author does not understand the difference between `.now()` and `.now(tz)`](https://github.com/myusuf3/delorean/pull/46). – jfs Mar 27 '15 at 09:10