How can I convert a dateutil.relativedelta object to a datetime.timedelta object?
e.g.,
# pip install python-dateutil
from dateutil.relativedelta import relativedelta
from datetime import timedelta
rel_delta = relativedelta(months=-2)
# How can I convert rel_delta to a timedelta object so that I can call total_seconds() ?
time_delta = ???(rel_delta)
time_delta.total_seconds() # call the timedelta.total_seconds() method
You can't, for one huge reason: They don't store the same information. datetime.timedelta only stores days, seconds, and milliseconds, whereas dateutil.relativedelta stores every single time component fed to it.
That dateutil.relativedelta does so is important for storing things such as a difference of 1 month, but since the length of a month can vary this means that there is no way at all to express the same thing in datetime.timedelta.
In case someone is looking to convert a relativedelta to a timedelta from a specific date, simply add and subtract the known time:
utcnow = datetime.utcnow()
rel_delta = relativedelta(months=-2)
time_delta = utcnow + rel_delta - utcnow # e.g, datetime.timedelta(days=-62)
As a commenter points out, the resulting timedelta value will differ based on what month it is.
Depending on why you want to call total_seconds, it may be possible to refactor your code to avoid the conversion altogether. For example, consider a check on whether or not a user is over 18 years old:
datetime.date.today() - user['dateOfBirth'] < datetime.timedelta(days=365*18)
This check is not a good idea, because the timedelta object does not account for things like leap years. It's tempting to rewrite as:
datetime.date.today() - user['dateOfBirth'] < dateutil.relativedelta.relativedelta(years=18)
which would require comparing a timedelta (LHS) to a relativedelta (RHS), or converting one to the other. However, you can refactor the check to avoid this conversion altogether:
user['dateOfBirth'] + dateutil.relativedelta.relativedelta(years=18) > datetime.date.today()
Related
I have a timestamp such 1474398821633L that I think is in utc. I want to compare it to datetime.datetime.now() to verify if it is expired.
I am using python 2.7
from datetime import datetime
timestamp = 1474398821633L
now = datetime.now()
if datetime.utcfromtimestamp(timestamp) < now:
print "timestamp expired"
However I got this error when trying to create a datetime object from the timestamp: ValueError: timestamp out of range for platform localtime()/gmtime() function
What can I do?
It looks like your timestamp is in milliseconds. Python uses timestamps in seconds:
>>> datetime.datetime.utcfromtimestamp(1474398821.633)
datetime.datetime(2016, 9, 20, 19, 13, 41, 633000)
In other words, you might need to divide your timestamp by 1000. in order to get it in the proper range.
Also, you'll probably want to compare datetime.utcnow() instead of datetime.now() to make sure that you're handling timezones correctly :-).
As #mgilson pointed out your input is likely "milliseconds", not "seconds since epoch".
Use time.time() instead of datetime.now():
import time
if time.time() > (timestamp_in_millis * 1e-3):
print("expired")
If you need datetime then use datetime.utcnow() instead of datetime.now(). Do not compare .now() that returns local time as a naive datetime object with utcfromtimestamp() that returns UTC time also as a naive datetime object (it is like comparing celsius and fahrenheit directly: you should convert to the same unit first).
from datetime import datetime
now = datetime.utcnow()
then = datetime.utcfromtimestamp(timestamp_in_millis * 1e-3)
if now > then:
print("expired")
See more details in Find if 24 hrs have passed between datetimes - Python.
I have a time series that I have pulled from a netCDF file and I'm trying to convert them to a datetime format. The format of the time series is in 'days since 1990-01-01 00:00:00 +10' (+10 being GMT: +10)
time = nc_data.variables['time'][:]
time_idx = 0 # first timestamp
print time[time_idx]
9465.0
My desired output is a datetime object like so (also GMT +10):
"2015-12-01 00:00:00"
I have tried converting this using the time module without much success although I believe I may be using wrong (I'm still a novice in python and programming).
import time
time_datetime = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(time[time_idx]*24*60*60))
Any advice appreciated,
Cheers!
The datetime module's timedelta is probably what you're looking for.
For example:
from datetime import date, timedelta
days = 9465 # This may work for floats in general, but using integers
# is more precise (e.g. days = int(9465.0))
start = date(1990,1,1) # This is the "days since" part
delta = timedelta(days) # Create a time delta object from the number of days
offset = start + delta # Add the specified number of days to 1990
print(offset) # >>> 2015-12-01
print(type(offset)) # >>> <class 'datetime.date'>
You can then use and/or manipulate the offset object, or convert it to a string representation however you see fit.
You can use the same format as for this date object as you do for your time_datetime:
print(offset.strftime('%Y-%m-%d %H:%M:%S'))
Output:
2015-12-01 00:00:00
Instead of using a date object, you could use a datetime object instead if, for example, you were later going to add hours/minutes/seconds/timezone offsets to it.
The code would stay the same as above with the exception of two lines:
# Here, you're importing datetime instead of date
from datetime import datetime, timedelta
# Here, you're creating a datetime object instead of a date object
start = datetime(1990,1,1) # This is the "days since" part
Note: Although you don't state it, but the other answer suggests you might be looking for timezone aware datetimes. If that's the case, dateutil is the way to go in Python 2 as the other answer suggests. In Python 3, you'd want to use the datetime module's tzinfo.
netCDF num2date is the correct function to use here:
import netCDF4
ncfile = netCDF4.Dataset('./foo.nc', 'r')
time = ncfile.variables['time'] # do not cast to numpy array yet
time_convert = netCDF4.num2date(time[:], time.units, time.calendar)
This will convert number of days since 1900-01-01 (i.e. the units of time) to python datetime objects. If time does not have a calendar attribute, you'll need to specify the calendar, or use the default of standard.
We can do this in a couple steps. First, we are going to use the dateutil library to handle our work. It will make some of this easier.
The first step is to get a datetime object from your string (1990-01-01 00:00:00 +10). We'll do that with the following code:
from datetime import datetime
from dateutil.relativedelta import relativedelta
import dateutil.parser
days_since = '1990-01-01 00:00:00 +10'
days_since_dt = dateutil.parser.parse(days_since)
Now, our days_since_dt will look like this:
datetime.datetime(1990, 1, 1, 0, 0, tzinfo=tzoffset(None, 36000))
We'll use that in our next step, of determining the new date. We'll use relativedelta in dateutils to handle this math.
new_date = days_since_dt + relativedelta(days=9465.0)
This will result in your value in new_date having a value of:
datetime.datetime(2015, 12, 1, 0, 0, tzinfo=tzoffset(None, 36000))
This method ensures that the answer you receive continues to be in GMT+10.
I want to compare only time part in datetime. I have different dates with only time field to compare. Since dates are different and only time part i want to consider So i think creating two datetime object will not help.
my string as
start="22:00:00"
End="03:00:00"
Tocompare="23:30:00"
Above are strings when i convert them with datetime as
dt=datetime.strptime(start,"%H:%M:%S")
it gives
1900-01-01 22:00:00
which is default date in python.
So i need to avoid all this and want only time part. I simply need to check does my Tocompare falls between start and End
Just call the .time() method of the datetime objects to get their hours, minutes, seconds and microseconds.
dt = datetime.strptime(start,"%H:%M:%S").time()
Compare their times using datetime.time().
import datetime
start = datetime.datetime.strptime(start, '%H:%M:%S')
start = datetime.time(start.hour, start.minute,start.second)
tocompare = datetime.datetime.strptime(tocompare, '%H:%M:%S')
tocompare = datetime.time(tocompare.hour, tocompare.minute, tocompare.second)
start > tocompare # False
When dealing with times and dates in python, you will stumble across the time.struct_time object:
st = time.strptime("23.10.2012", "%d.%m.%Y")
print st
time.struct_time(tm_year=2012, tm_mon=10, tm_mday=23, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=1, tm_yday=297, tm_isdst=-1)
Now as this struct does not support item assignment (i.e. you cannot do something like st[1]+=1) how else is it possible to increase, say, the number of the month.
Solutions suggest to convert this time_struct into seconds and add the corresponding number of seconds, but this does not look nice. You also need to know how many days are in a month, or if the year is a leap year or not. I want an easy way to obtain a time_struct to be e.g.
time.struct_time(tm_year=2012, tm_mon=11, tm_mday=23, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=1, tm_yday=297, tm_isdst=-1)
with just the month increased by one. Creating a time_struct from scratch would be fineābut how? What ways are there?
Use the datetime module instead, which has a far richer set of objects to handle date(time) arithmetic:
import datetime
adate = datetime.datetime.strptime("23.10.2012", "%d.%m.%Y").date()
adate + datetime.timedelta(days=30)
You can use the excellent python-dateutil add-on module to get an ever richer set of options for dealing with deltas:
from dateutil.relativedelta import relativedelta
adate + relativedelta(months=1)
relativedelta knows about leap years, month lengths, etc. and will do the right thing when adding a month to, say, January 30th (you end up with February 28th or 29th, it won't cross month boundaries).
So... the schema for the tuple underlying time_struct is given in the documentation here:
http://docs.python.org/2/library/time.html#time.struct_time
And even though it's read-only as a time_struct, you can use casting to list() to get at that tuple directly (remembering to wrap-around your month after you increment it, and keep the end range in 1-12 rather than 0-11). Then the time.struct_time() function will convert a valid 9-tuple back into a time_struct:
st = time.strptime("23.10.2012", "%d.%m.%Y")
st_writable = list(st)
st_writable[1] = (st_writable[1] + 1)%12 + 1
st = time.struct_time(tuple(st_writable))
You can first convert it to datetime, then add a timedelta offset to it:
from time import mktime
from datetime import datetime
dt = datetime.fromtimestamp(mktime(struct))
timedelta = datetime.timedelta(seconds=10)
dt = dt + timedelta
References:
How do you convert a Python time.struct_time object into a datetime object?
http://docs.python.org/library/datetime.html
If you want to avoid datetime all together and stick with time, you can convert to unix timestamp and then subtract the number of seconds you need. To get a time object for 24 hours ago:
time.gmtime(time.mktime(time.gmtime()) - 86400)
However, as OP pointed out this is not good for working with months and should be reserved for seconds, hours, and days.
I have a couple classes extending builtin datetime.*
Is there any good reason to not overload + (MyTime.__radd___) so MyDate + MyTime returns a MyDateTime?
This is already implemented as a class method, datetime.datetime.combine:
import datetime
d = datetime.date(2010, 12, 5)
t = datetime.time(10, 22, 15)
dt = datetime.datetime.combine(d, t)
print dt
prints
2010-12-05 10:22:15
This would generally be frowned upon because you're really combining rather than adding; this is why the actual datetime library has a combine method rather than using addition in this way.
I'm not aware of any other cases in Python where <instance of TypeA> + <instance of TypeB> produces <instance of TypeC>. Thus, the Principle of least astonishment suggests that you should simply provide a combine method rather than overload addition.
Yes, there is at least one good reason not to: the resulting instance is completely different from the two input instances. Is this important? I don't think so -- consider that date - date yields timedelta.
The way I see it:
Does adding two dates together make sense? No.
Does adding two times together make sense? No.
Does adding a date and a time together make sense? Yup!
Does adding a date and a timedelta togethor make sense? Maybe.
Does adding a time and a timedelta together make sense? Maybe.
and for subtraction
Does subtracting two dates make sense? Yes.
Does subtracting two times make sense? Yes.
Does subtracting a time from a date make sense? Nope.
Does subtracting a timedelta from a date make sense? Maybe.
Does subtracting a timedelta from a time make sense? Maybe.
Developing along the lines of what makes sense:
date + time => datetime
date + timedelta => date | datetime or exception or silently drop time portion
time + date => datetime
time + timedelta => time | wrap-around or exception
date - date => timedelta
date - timedelta => date | datetime or exception or silently drop time portion
time - time => timedelta
time - timedelta => time | wrap-around or exception
datetime + timedelta => datetime
datetime - timedelta => datetime
So, if it were me and I were designing a Date, Time, DateTime, TimeDelta framework, I would allow:
date + time
date - date
time - time
datetime + timedelta
datetime - timedelta
and for these:
date +/- timedelta
time +/- timedelta
I would default to returning the same type if the timedelta had none of the other type, and raising an exception if the timedelta did have some of the other type, but there would be a setting that would control that. The other possible behavior would be to drop the unneeded portion -- so a date combined with a timedelta that had hours would drop the hours and return a date.
Due to the existence of the date, time, and datetime cross-type addition and subtraction operators, I would think that this is fine, so long as it is well defined.
Currently (2.7.2):
date = date + timedelta
date = date - timedelta
timedelta = date - date
datetime = datetime + timedelta
datetime = datetime - timedelta
timedelta = datetime - datetime
I believe the following is also reasonable for an extension:
timedelta = time - time
datetime = date + time
I was going to suggest the following as well, but time has very specific min and max values for hour, minute, second, and microsecond, thus requiring a silent wraparound of values or returning of a different type:
time = time + timedelta
time = time - timedelta
Similarly, date cannot handle a timedelta of less than a day being added to it. Often I have been told to simply use Duck Typing with Python, because that's the intent. If that is true, then I would propose the following completed interface:
[date|datetime] = date + timedelta
[date|datetime] = date - timedelta
timedelta = date - date
[time|timedelta] = time + timedelta
[time|timedelta] = time - timedelta
timedelta = time - time
datetime = datetime + timedelta
datetime = datetime - timedelta
datetime = date + time
datetime = date - time
timedelta = datetime - datetime
timedelta = datetime - date
timedelta = timedelta + timedelta
timedelta = timedelta - timedelta
In which, given the case that date has precision loss (for timedelta's with partial days), it is promoted to datetime. Similarly, given the case that time has precision loss (for timedelta's that yield a result of more than one day, or negative time), it is promoted to timedelta. However, I'm not fully comfortable with [time|timedelta]. It makes sense given the rest of the interface from parallelism and precision views, but I do think it might be more elegant to just wraparound the time to the proper hour, thus changing all the [time|timedelta]'s to simply time, but unfortunately that leaves us with lost precision.
In my opinion, the most valuable uses of operator overloading are situations where many input values can be combined. You'd never want to deal with:
concat(concat(concat("Hello", ", "), concat("World", "!")), '\n');
or
distance = sqrt(add(add(x*x, y*y), z*z));
So we overload math symbols to create a more intuitive syntax. Another way to deal with this problem is variadic functions, like + in Scheme.
With your date + time = datetime, it doesn't make sense to add datetime + datetime, datetime + time, or datetime + date, so you could never encounter a situation like those above.
In my opinion, once again, the right thing is to use a constructor method. In a language with strong typing like C++, you'd have DateTime(const Date &d, const Time &t). With Python's dynamic typing, I guess they gave the function a name, datetime.combine(date, time), to make the code clearer when the types of the input variables are not visible in the code.
I guess most important things are functionality and efficiency. Of course using a simple + operator will be easier to use, but i am not sure about functionality.
If we compare it to datetime.combine, What combine do is:
dt = date(2011,01,01)
tm = time(20,00)
dtm = datetime.combine(dt, tm)
For dtm
If dt is a date object and tm is a time object, than date info is taken from dt, time info and tzinfo is taken from tm object
if dt is a datetime object, than its time and tzinfo attributes will be ignored.
From that point of view, working with datetime objects do not seem to be simple objects, but more compex structures with diffrent attributes, like timezone info.
Probably thats why datetime objects have some additional functions that is used for formatting object type and data structure of the object.
Python have a motto (something like that):
In python, nothing is unchangable, if you know what you are doing. If not, it is better to leave library functions as they are...
So, in my opinion, it is better you use combine that overloading + operator