I have data like this: "2016-10-17 09:34:02" with the format: "%Y-%m-%d %H:%M:%S" and I use: from datetime import datetime
My variable is like this:
date_object = datetime.strptime(datetemp, format)
So far, so good...
But I need get only the time part from this object (date_object) to make some comparisons...
When I do this:
print(date_object.time)
I get the following error:
built-in method time of datetime.datetime object at 0x00A94AE8
How can i get just the time part from the object date_object? This will allow me to make comparisons within hourly ranges.
You need to add parenthesis () to your print(date_object.time) call:
print(date_object.time())
Example output:
>>> import datetime
>>> now = datetime.datetime.now()
>>> now.time()
datetime.time(22, 14, 6, 996000)
>>> print(now.time())
22:14:06.996000
>>> import datetime as dt
>>> timenow = dt.datetime.now()
>>> timenow
datetime.datetime(2016, 11, 23, 9, 59, 54, 291083)
>>> timenow.date()
datetime.date(2016, 11, 23)
>>> timenow.time()
datetime.time(9, 59, 54, 291083)
the outputs are in datetime type.
>>> print(datetime.time())
00:00:00
or you can convert it into a string and print
>>> time_str = str(timenow.time())
>>> time_str
'09:59:54.291083'
date_object.time().__str__() this will give you the format you want
date_object.time().__str__() is equal to `print(date_object.time())`
but you can store it in a var, not just print it in you screen.
I skimmed over the datetime.py file and it does have a now() method/function and I thought import was used to include specific methods and variables.
datetime.now() is actually a method of the class datetime that you can import from the module datetime.
from datetime import datetime
now = datetime.now()
import datetime
print datetime # <module 'datetime' (built-in)>
print datetime.datetime # <type 'datetime.datetime'>
print datetime.datetime.now # <built-in method now of type object at 0x00000000701B9300>
print datetime.datetime.now() # 2016-01-11 14:07:23.763000
datetime is the module, which is actually nothing more than a python file that includes classes.
datetime.datetime is a class defined in that python file.
datetime.datetime.now is a method defined in that class. So it is not importable without actually importing the class.
and finally datetime.datetime.now() is the method called to return the value.
now() is a method of the datetime class:
from datetime import datetime
print(datetime.now())
datetime.datetime(2016, 1, 11, 15, 8, 22, 634020)
If you want just use now you could do following:
now = datetime.now
print(now())
datetime.datetime(2016, 1, 11, 15, 9, 24, 683569)
I am using feedparser in order to get RSS data.
Here is my code :
>>> import datetime
>>> import time
>>> import feedparser
>>> d=feedparser.parse("http://.../rss.xml")
>>> datetimee_rss = d.entries[0].published_parsed
>>> datetimee_rss
time.struct_time(tm_year=2015, tm_mon=5, tm_mday=8, tm_hour=16, tm_min=57, tm_sec=39, tm_wday=4, tm_yday=128, tm_isdst=0)
>>> datetime.datetime.fromtimestamp(time.mktime(datetimee_rss))
datetime.datetime(2015, 5, 8, 17, 57, 39)
In my timezone (FR), the actual date is May, 8th, 2015 18:57.
In the RSS XML, the value is <pubDate>Fri, 08 May 2015 18:57:39 +0200</pubDate>
When I parse it into datetime, I got 2015, 5, 8, 17, 57, 39.
How to have 2015, 5, 8, 18, 57, 39 without dirty hack, but simply by configuring the correct timezone ?
EDIT:
By doing :
>>> from pytz import timezone
>>> datetime.datetime.fromtimestamp(time.mktime(datetimee_rss),tz=timezone('Euro
pe/Paris'))
datetime.datetime(2015, 5, 8, 17, 57, 39, tzinfo=<DstTzInfo 'Europe/Paris' CEST+2:00:00 DST>)
I got something nicer, however, it doesn't seem to work in the rest of the script, I got plenty of TypeError: can't compare offset-naive and offset-aware datetimes error.
feedparser does provide the original datetime string (just remove the _parsed suffix from the attribute name), so if you know the format of the string, you can parse it into a tz-aware datetime object yourself.
For example, with your code, you can get the tz-aware object as such:
datetime.datetime.strptime(d.entries[0].published, '%a, %d %b %Y %H:%M:%S %z')
for more reference on strptime(), see https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
EDIT: Since Python 2.x doesn't support %z directive, use python-dateutil instead
pip install python-dateutil
then
from dateutil import parser
datetime_rss = parser.parse(d.entries[0].published)
documentation at https://dateutil.readthedocs.org/en/latest/
feedparser returns time in UTC timezone. It is incorrect to apply time.mktime() to it (unless your local timezone is UTC that it isn't). You should use calendar.timegm() instead:
import calendar
from datetime import datetime
utc_tuple = d.entries[0].published_parsed
posix_timestamp = calendar.timegm(utc_tuple)
local_time_as_naive_datetime_object = datetime.frometimestamp(posix_timestamp) # assume non-"right" timezone
RSS feeds may use many different dates formats; I would leave the date parsing to feedparser module.
If you want to get the local time as an aware datetime object:
from tzlocal import get_localzone # $ pip install tzlocal
local_timezone = get_localzone()
local_time = datetime.frometimestamp(posix_timestamp, local_timezone) # assume non-"right" timezone
Try this:
>>> import os
>>> os.environ['TZ'] = 'Europe/Paris'
>>> time.tzset()
>>> time.tzname
('CET', 'CEST')
What I need to do
I have a timezone-unaware datetime object, to which I need to add a time zone in order to be able to compare it with other timezone-aware datetime objects. I do not want to convert my entire application to timezone unaware for this one legacy case.
What I've Tried
First, to demonstrate the problem:
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> import pytz
>>> unaware = datetime.datetime(2011,8,15,8,15,12,0)
>>> unaware
datetime.datetime(2011, 8, 15, 8, 15, 12)
>>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC)
>>> aware
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> aware == unaware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
First, I tried astimezone:
>>> unaware.astimezone(pytz.UTC)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime
>>>
It's not terribly surprising this failed, since it's actually trying to do a conversion. Replace seemed like a better choice (as per How do I get a value of datetime.today() in Python that is "timezone aware"?):
>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>>
But as you can see, replace seems to set the tzinfo, but not make the object aware. I'm getting ready to fall back to doctoring the input string to have a timezone before parsing it (I'm using dateutil for parsing, if that matters), but that seems incredibly kludgy.
Also, I've tried this in both Python 2.6 and Python 2.7, with the same results.
Context
I am writing a parser for some data files. There is an old format I need to support where the date string does not have a timezone indicator. I've already fixed the data source, but I still need to support the legacy data format. A one time conversion of the legacy data is not an option for various business BS reasons. While in general, I do not like the idea of hard-coding a default timezone, in this case it seems like the best option. I know with reasonable confidence that all the legacy data in question is in UTC, so I'm prepared to accept the risk of defaulting to that in this case.
In general, to make a naive datetime timezone-aware, use the localize method:
import datetime
import pytz
unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
aware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC)
now_aware = pytz.utc.localize(unaware)
assert aware == now_aware
For the UTC timezone, it is not really necessary to use localize since there is no daylight savings time calculation to handle:
now_aware = unaware.replace(tzinfo=pytz.UTC)
works. (.replace returns a new datetime; it does not modify unaware.)
All of these examples use an external module, but you can achieve the same result using just the datetime module, as also presented in this SO answer:
from datetime import datetime, timezone
dt = datetime.now()
dt = dt.replace(tzinfo=timezone.utc)
print(dt.isoformat())
# '2017-01-12T22:11:31+00:00'
Fewer dependencies and no pytz issues.
NOTE: If you wish to use this with python3 and python2, you can use this as well for the timezone import (hardcoded for UTC):
try:
from datetime import timezone
utc = timezone.utc
except ImportError:
#Hi there python2 user
class UTC(tzinfo):
def utcoffset(self, dt):
return timedelta(0)
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return timedelta(0)
utc = UTC()
I wrote this Python 2 script in 2011, but never checked if it works on Python 3.
I had moved from dt_aware to dt_unaware:
dt_unaware = dt_aware.replace(tzinfo=None)
and dt_unware to dt_aware:
from pytz import timezone
localtz = timezone('Europe/Lisbon')
dt_aware = localtz.localize(dt_unware)
I use this statement in Django to convert an unaware time to an aware:
from django.utils import timezone
dt_aware = timezone.make_aware(dt_unaware, timezone.get_current_timezone())
Python 3.9 adds the zoneinfo module so now only the standard library is needed!
from zoneinfo import ZoneInfo
from datetime import datetime
unaware = datetime(2020, 10, 31, 12)
Attach a timezone:
>>> unaware.replace(tzinfo=ZoneInfo('Asia/Tokyo'))
datetime.datetime(2020, 10, 31, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))
>>> str(_)
'2020-10-31 12:00:00+09:00'
Attach the system's local timezone:
>>> unaware.replace(tzinfo=ZoneInfo('localtime'))
datetime.datetime(2020, 10, 31, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='localtime'))
>>> str(_)
'2020-10-31 12:00:00+01:00'
Subsequently it is properly converted to other timezones:
>>> unaware.replace(tzinfo=ZoneInfo('localtime')).astimezone(ZoneInfo('Asia/Tokyo'))
datetime.datetime(2020, 10, 31, 20, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='Asia/Tokyo'))
>>> str(_)
'2020-10-31 20:00:00+09:00'
Wikipedia list of available time zones
Windows has no system time zone database, so here an extra package is needed:
pip install tzdata
There is a backport to allow use of zoneinfo in Python 3.6 to 3.8:
pip install backports.zoneinfo
Then:
from backports.zoneinfo import ZoneInfo
I agree with the previous answers, and is fine if you are ok to start in UTC. But I think it is also a common scenario for people to work with a tz aware value that has a datetime that has a non UTC local timezone.
If you were to just go by name, one would probably infer replace() will be applicable and produce the right datetime aware object. This is not the case.
the replace( tzinfo=... ) seems to be random in its behaviour. It is therefore useless. Do not use this!
localize is the correct function to use. Example:
localdatetime_aware = tz.localize(datetime_nonaware)
Or a more complete example:
import pytz
from datetime import datetime
pytz.timezone('Australia/Melbourne').localize(datetime.now())
gives me a timezone aware datetime value of the current local time:
datetime.datetime(2017, 11, 3, 7, 44, 51, 908574, tzinfo=<DstTzInfo 'Australia/Melbourne' AEDT+11:00:00 DST>)
Use dateutil.tz.tzlocal() to get the timezone in your usage of datetime.datetime.now() and datetime.datetime.astimezone():
from datetime import datetime
from dateutil import tz
unlocalisedDatetime = datetime.now()
localisedDatetime1 = datetime.now(tz = tz.tzlocal())
localisedDatetime2 = datetime(2017, 6, 24, 12, 24, 36, tz.tzlocal())
localisedDatetime3 = unlocalisedDatetime.astimezone(tz = tz.tzlocal())
localisedDatetime4 = unlocalisedDatetime.replace(tzinfo = tz.tzlocal())
Note that datetime.astimezone will first convert your datetime object to UTC then into the timezone, which is the same as calling datetime.replace with the original timezone information being None.
This codifies #Sérgio and #unutbu's answers. It will "just work" with either a pytz.timezone object or an IANA Time Zone string.
def make_tz_aware(dt, tz='UTC', is_dst=None):
"""Add timezone information to a datetime object, only if it is naive."""
tz = dt.tzinfo or tz
try:
tz = pytz.timezone(tz)
except AttributeError:
pass
return tz.localize(dt, is_dst=is_dst)
This seems like what datetime.localize() (or .inform() or .awarify()) should do, accept both strings and timezone objects for the tz argument and default to UTC if no time zone is specified.
for those that just want to make a timezone aware datetime
import datetime
datetime.datetime(2019, 12, 7, tzinfo=datetime.timezone.utc)
for those that want a datetime with a non utc timezone starting in python 3.9 stdlib
import datetime
from zoneinfo import ZoneInfo
datetime.datetime(2019, 12, 7, tzinfo=ZoneInfo("America/Los_Angeles"))
Yet another way of having a datetime object NOT naive:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc)
datetime.datetime(2021, 5, 1, 22, 51, 16, 219942, tzinfo=datetime.timezone.utc)
quite new to Python and I encountered the same issue. I find this solution quite simple and for me it works fine (Python 3.6):
unaware=parser.parse("2020-05-01 0:00:00")
aware=unaware.replace(tzinfo=tz.tzlocal()).astimezone(tz.tzlocal())
Here is a simple solution to minimize changes to your code:
from datetime import datetime
import pytz
start_utc = datetime.utcnow()
print ("Time (UTC): %s" % start_utc.strftime("%d-%m-%Y %H:%M:%S"))
Time (UTC): 09-01-2021 03:49:03
tz = pytz.timezone('Africa/Cairo')
start_tz = datetime.now().astimezone(tz)
print ("Time (RSA): %s" % start_tz.strftime("%d-%m-%Y %H:%M:%S"))
Time (RSA): 09-01-2021 05:49:03
In the format of unutbu's answer; I made a utility module that handles things like this, with more intuitive syntax. Can be installed with pip.
import datetime
import saturn
unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
now_aware = saturn.fix_naive(unaware)
now_aware_madrid = saturn.fix_naive(unaware, 'Europe/Madrid')
Changing between timezones
import pytz
from datetime import datetime
other_tz = pytz.timezone('Europe/Madrid')
# From random aware datetime...
aware_datetime = datetime.utcnow().astimezone(other_tz)
>> 2020-05-21 08:28:26.984948+02:00
# 1. Change aware datetime to UTC and remove tzinfo to obtain an unaware datetime
unaware_datetime = aware_datetime.astimezone(pytz.UTC).replace(tzinfo=None)
>> 2020-05-21 06:28:26.984948
# 2. Set tzinfo to UTC directly on an unaware datetime to obtain an utc aware datetime
aware_datetime_utc = unaware_datetime.replace(tzinfo=pytz.UTC)
>> 2020-05-21 06:28:26.984948+00:00
# 3. Convert the aware utc datetime into another timezone
reconverted_aware_datetime = aware_datetime_utc.astimezone(other_tz)
>> 2020-05-21 08:28:26.984948+02:00
# Initial Aware Datetime and Reconverted Aware Datetime are equal
print(aware_datetime1 == aware_datetime2)
>> True
Above all mentioned approaches, when it is a Unix timestamp, there is a very simple solution using pandas.
import pandas as pd
unix_timestamp = 1513393355
pst_tz = pd.Timestamp(unix_timestamp, unit='s', tz='US/Pacific')
utc_tz = pd.Timestamp(unix_timestamp, unit='s', tz='UTC')