How to check if a datetime object is localized with pytz? - python

I want to store a datetime object with a localized UTC timezone. The method that stores the datetime object can be given a non-localized datetime (naive) object or an object that already has been localized. How do I determine if localization is needed?
Code with missing if condition:
class MyClass:
def set_date(self, d):
# what do i check here?
# if(d.tzinfo):
self.date = d.astimezone(pytz.utc)
# else:
self.date = pytz.utc.localize(d)

How do I determine if localization is needed?
From datetime docs:
a datetime object d is aware iff:
d.tzinfo is not None and d.tzinfo.utcoffset(d) is not None
d is naive iff:
d.tzinfo is None or d.tzinfo.utcoffset(d) is None
Though if d is a datetime object representing time in UTC timezone then you could use in both cases:
self.date = d.replace(tzinfo=pytz.utc)
It works regardless d is timezone-aware or naive.
Note: don't use datetime.replace() method with a timezone with a non-fixed utc offset (it is ok to use it with UTC timezone but otherwise you should use tz.localize() method).

if you want to check if a datetime object 'd' is localized, check the d.tzinfo, if it is None, no localization.

Here is a function wrapping up the top answer.
def tz_aware(dt):
return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None

Here's a more complete function to convert or coerce a timestamp obj to utc. If it reaches the exception this means the timestamp is not localized. Since it's good practice to always work in UTC within the code, this function is very useful at the entry level from persistence.
def convert_or_coerce_timestamp_to_utc(timeobj):
out = timeobj
try:
out = timeobj.astimezone(pytz.utc) # aware object can be in any timezone
except (ValueError,TypeError) as exc: # naive
out = timeobj.replace(tzinfo=pytz.utc)
return out
The small addition from the 'try catch' in the answer by J.F. Sebastian is the additional catch condition, without which not all naive cases will be caught by the function.

Related

How to print only if specific time starts with x in Python

Hi I'm a newbie learning python and I want to print something only if current time starts with x (for example, if current time starts with = 4, print "hi", time = 4:18), this is the code I made, it says attribute error:
import datetime
local = datetime.datetime.now().time().replace(microsecond=0)
if local.startswith('16'):
print("Hi! It's ", local)
The .replace() method returns a date object. date objects don't have a .startswith() method. That method is only for str.
Try converting your date to a string first:
if str(local).startswith('16'):
print("Hi! It's ", local)
The documentation lists all of the methods available on a date object.
You need to first convert it to a string, as datetime objects have no startswith() method. Use strftime, example:
import datetime
t = datetime.datetime(2012, 2, 23, 0, 0)
t2 = t.strftime('%m/%d/%Y')
will yield:
'02/23/2012'. Once it's converted, you can use t2.startswith().
https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
You can get the hour of the time and check if it is 16:
if local.hour == 16:
print("Hi! It's ",local)
If you need to use startswith() then you can convert it to a string like this:
if str(local).startswith('16'):
print("Hi! It's ", local)
That's not a good way. Check the time as int is the better solution here.
replace() has 2 needed str arguments. You use a named attribute which doesn't exist.

Comparing two date objects in Python: TypeError: '<' not supported between instances of 'datetime.date' and 'method'

This shouldn't be too difficult but I can't seem to get it to work.
I want to compare two datetime.date types in Python but I keep getting a Type Error:
from datetime import date
class Vacancy(object):
def __init__(self, date): #date is a datetime string of format 2017-13-03T00.00.000Z
self.date = datetime.strptime(date[:-1], '%Y-%m-%dT%H:%M:%S.%f').date()
def getDate(self):
return self.date
all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
for o in all_objects:
earliestDate = date(2020, 1, 1)
if o.getDate() < earliestDate:
earliestDate = o.getDate()
print(earliestDate)
TypeError: '<' not supported between instances of 'datetime.date' and 'method'
Which doesn't make sense to me because:
print(type(earliestDate)) and print(type(o.getDate())) both give
<class 'datetime.date'>
What could I be doing wrong?
EDIT: added class sample code for the objects in all_objects
EDIT2: As many of you pointed out it is indeed a missing '()'. In my actual code I was assigning the method instad of the value by doing earliestDate = o.getDate. Next time I'll try to be more truthful to my code. Thank you all for the insight you provided as I indeed come from Java and I don't fully comprehend Python yet.
The TypeError should give you all information you need to solve this problem. Here's how to interpret it:
TypeError: '<' not supported between instances of 'datetime.date' and 'method'
The '<' not supported means that you got the error when using the < operator, as you already know.
The comparison doesn't work because one of the things you are comparing is not a datetime.date instance. You already got this, too.
The method type is what you get if you would use o.getDate instead of o.getDate(). In Python you can pass around methods as values if you like, just like lambdas or functions. This is not what you want in this case however, so make sure you use () everywhere you want to call a method, even if it doesn't take any arguments.
The order of the types in the error message is also interesting. That datetime.date comes before method mean that the date was on the left side and the problematic value was on the right side. In your case, the earliestDate is holding a method instead of a datetime.date.
Now that we know that earliestDate is the problem, where is it updated? earliestDate = date(2020, 1, 1) is clearly a date, but how about earliestDate = o.getDate()? It's using parentheses, so o.getDate() must be returning a method.
Given your code, the Vacancy will always have self.date set to a date, or an exception will be thrown (something like ValueError: time data 'xxx' does not match format '%Y-%m-%dT%H:%M:%S.%f'). I'm guessing your code looks different and the initialization for Vacancy is wrong somehow. This is the benefit of providing a MCVE :)
You overwritten the definition of date, try this (maintaining the datetime namespace with an alias: dt). A good practice would be to not name local or member variables with the same name of functions and objects of the libraries you import (you imported date from datetime and then use date as the argument of the init).
import datetime as dt
class Vacancy(object):
def __init__(self, date):
self.date = date
def getDate(self):
return self.date
all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
for o in all_objects:
earliestDate = dt.date(2020, 1, 1)
if o.getDate() < earliestDate:
earliestDate = o.getDate()
print(earliestDate)
An extra observation is that in python there is no need of defining getters and setters, since the variables are public. It is better if you just:
import datetime as dt
class Vacancy(object):
def __init__(self, date):
self.date = date
all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
for o in all_objects:
earliestDate = dt.date(2020, 1, 1)
if o.date < earliestDate:
earliestDate = o.date
And if you want to be sure the date member variable is not modified, you can do something like this:
class Vacancy(object):
def __init__(self, date):
self.date = date
def getMinDate(self, other_date):
if self.date < other_date:
return dt.date(self.date)
else:
return other_date
all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
earliestDate = dt.date(2020, 1, 1)
for o in all_objects:
earliestDate = o.getMinDate(earliestDate)
This error is also thrown when trying to apply the condition to NULL values in the column.
To solve this:
Add a condition to only perform the condition when the values are NOT null.
Remove the null values
from datetime import date
class Vacancy(object):
def __init__(self, date): #date is a datetime string of format 2017-13-03T00.00.000Z
self.date = datetime.strptime(date[:-1], '%Y-%m-%dT%H:%M:%S.%f').date()
def getDate(self):
return self.date
all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
for o in all_objects:
earliestDate = date(2020, 1, 1)
# NOT Null condition
if (o != None) and (earliestDate != None):
if o.getDate() < earliestDate:
earliestDate = o.getDate()
print(earliestDate)

How to let datetime.strptime parse zero-padded decimal number only [duplicate]

I've been using the datetime module to do some checking of dates to see if they are in mm/dd/yyyy or mm/dd/yy formats. The problem is that the %d and %m directives aren't sensitive enough to detect when the month or day is a single digit, which is a requirement of mine.
datetime.strptime('01/01/2001', '%m/%d/%Y')
works like I want it to, but
datetime.strptime('1/1/2001', '%m/%d/%Y')
also produces a valid datetime, when I really want it to throw a ValueError unless the month and day are 0-padded. Does anyone know how to set a required precision for datetime formats? Is this possible or should I just go with regex instead?
The datetime function you're using isn't intended to validate input, only to convert strings to datetime objects. Both of your examples are legitimate string inputs as far as datetime is concerned.
If you want to enforce user input to be a specific format, I would go with a regex - see this example from my REPL:
>>> import re
>>> pattern = re.compile(r"^[0-9]{2}/[0-9]{2}/[0-9]{4}$")
>>> def valid_datestring(datestring):
... if pattern.match(datestring):
... return True
... return False
...
>>> valid_datestring('1/1/2001')
False
>>> valid_datestring('01/01/2001')
True
If you want to define a function that returns a formatted date or returns a valueError, you can do something like this:
def format_datestring(datestring):
if not valid_datestring(datestring):
raise ValueError('Date input must be in the form dd/mm/yyyy!')
return datetime.strptime(datestring, '%m/%d/%Y')
You can verify that a string conforms exactly to a formatting string by re-formatting the datetime and comparing to the original string:
datetime_ = datetime.strptime(datetime_string, DATETIME_FORMAT)
if datetime_.strftime(DATETIME_FORMAT) != datetime_string:
[fail]

Adding += support to datetime.time

Python's datetime.time class is missing the functionality of += with datetime.timedelta. I'm attempting to remedy this by creating a derived class Time. I then use the datetime += and get the datetime.time().
However, I can't figure out how to then transfer the parent class values. I've tried to implement a copy method, as shown below but I get the error:
AttributeError: attribute 'hour' of 'datetime.time' objects is not writable
My current implementation:
from datetime import datetime, timedelta, time
class Time(time):
def copy(self,other):
self.hour = other.hour
self.minute = other.minute
self.second = other.second
self.microsecond = other.microsecond
def __add__(self,other):
if isinstance(other,timedelta):
dt = toDatetime(self)
dt += other
t = Time()
t.copy(dt.time())
return t
How can I copy the parent class's values? Also, is there a better way for me to get += support for the equivalent of datetime.time and I am just going about this all wrong?
To create a copy, pass in the time components to the constructor:
t = Time(dt.hour, dt.minute, dt.second, dt.microsecond)
datetime.time() objects are otherwise immutable; you could use their time.replace() method to create a new instance with specific components replaced, but since you are constructing a new subclass instance anyway, just passing in the components is easier.

Retrieve UNIX TIMESTAMP in django api call

I have the following query:
users = Analytics.objects.values('date', 'users').order_by('date')
[(datetime.date(2012, 8, 20), 156L), (datetime.date(2012, 8, 21), 153L),...]
How would I get the unix timestamp of the datetime here? The equivalent of doing:
select concat(UNIX_TIMESTAMP(date), '000') as date, users from analytics_analytics
1345446000000 156
1345532400000 153
1345618800000 153
Note that I do not want to do formatting in python as there are a lot of the above calls that need to be done.
The best way to do this, if really want the DB to do the conversion (and this can be applicable for other things, in general when you want to return information that's not readily available in a column from the DB), you can use the QuerySet.extra() function https://docs.djangoproject.com/en/dev/ref/models/querysets/#extra like this:
Analytics.objects.extra(select={'timestamp': "CONCAT(UNIX_TIMESTAMP(date), '000')"}).order_by('date').values('timestamp', 'users')
Downside of this is that it's no longer DB agnostic, so when you change RDBMS, you have to change the code. Upside is you can use values with it, unlike a property on the model.
Python datetime.date objects don't have a time component, so the timestamp you want needs a little qualification. If midnight suffices, you can use the .timetuple() method together with the time.mktime() function to create a timestamp:
>>> import datetime, time
>>> adate = datetime.date(2012, 8, 20)
>>> print time.mktime(adate.timetuple())
1345413600.0
If you need a specific time in the day, use the datetime.datetime.combine() class method to construct a datetime, then use the same trick to make it a timestamp:
>>> adatetime = datetime.datetime.combine(adate, datetime.time(12, 0))
>>> print time.mktime(adatetime.timetuple())
1345456800.0
Use either as a property on your Django model:
class Analytics(models.Model):
#property
def timestamp(self):
return time.mktime(self.date.timetuple())
I am not familiar with UNIX_TIMESTAMP, but with regard to Django: why not create a calculated field as proprty at your Django Model
class Analytics(...):
...
#property
def unix_timestamp(self):
return time.mktime(self.date.timetuple())

Categories

Resources