Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I extend Python's datetime.datetime with my own methods?

I'm trying to extend Python's datetime.datetime class with a couple of extra methods. So, for example I'm doing:

import datetime

class DateTime(datetime.datetime):
    def millisecond(self):
        return self.microsecond/1000

but then if I do

>>> d = DateTime(2010, 07, 11, microsecond=3000)
>>> print d.millisecond()
3
>>> delta = datetime.timedelta(hours=4)
>>> newd = d + delta
>>> print newd.millisecond()
AttributeError: 'datetime.datetime' object has no attribute 'millisecond'

This is obviously because doing d + delta calls the datetime.datetime.__add__() method which returns a datetime.datetime object.

Is there any way I can make this datetime.datetime object convert to a DateTime object? Or would I have to reimplement all the operators in my DateTime subclass to return the correct type?

like image 985
Milliams Avatar asked Jul 23 '10 13:07

Milliams


People also ask

How do you add 1 second to time in Python?

Use the timedelta() class from the datetime module to add seconds to datetime, e.g. result = dt + timedelta(seconds=24) .


2 Answers

A bit late, but the following works:

import ctypes as c

_get_dict = c.pythonapi._PyObject_GetDictPtr
_get_dict.restype = c.POINTER(c.py_object)
_get_dict.argtypes = [c.py_object]

import datetime

def millisecond(td):
    return (td.microsecond / 1000)
d = _get_dict(datetime.datetime)[0]
d['millisecond'] = millisecond

now = datetime.datetime.now()
print now.millisecond(), now.microsecond

Basically, you use ctypes to get an editable copy of the classes dictionary, and then just put your method in. I use this only to backport functions to older python versions, which I think is fairly clean. For example:

from datetime import timedelta
try:
    timedelta.total_seconds # new in 2.7
except AttributeError:
    def total_seconds(td):
        return float(td.days * 24 * 3600 + td.seconds + td.microseconds / 1e6)
    d = _get_dict(timedelta)[0]
    d['total_seconds'] = total_seconds
    # works now in 2.4
like image 130
jdm Avatar answered Sep 28 '22 10:09

jdm


unutbu was so close to what you originally asked for:

class DateTime(datetime.datetime):
    @property
    def millisecond(self):
        return self.microsecond/1000.0

datetime.datetime = DateTime

I use this pattern to implement APIs that will only show up in 3.3 while working in 3.1 or 3.2. The rest of the class keeps right on working as it ever did, with no performance loss.

Edited to add: This only works with 2.6+ for builtins, because it only works on new-style classes. Builtins were old-style until 2.6.

like image 33
SilverbackNet Avatar answered Sep 28 '22 09:09

SilverbackNet