As you apparently suspect already, having a class full of static methods isn't really Pythonic. The only reason to ever do that is for namespacing, but this should all go into a module anyway, so wrapping all the functions in a class is just unnecessary. Flat is better than nested.
You use the abbreviation
dt a lot in the function names. Don't. The only time you should use abbreviations like that is if they are more recognisable than spelling out what they stand for (the canonical example is "do use
HTTP"). A lot of them probably don't need to mention datetime at all in the name, given they're in a module called dateutil and their only argument is a datetime object.
Similarly, you use the abbreviation "microtimestamp", which is a little opaque. It looks like you mean "Like a Posix timestamp but measured in microseconds", so a more explicit thing to call it is
With those considerations in mind, and with a view to emphasising what the functions do, I would rename them thus:
Do the microsecond ones really need to be functions at all? They seem like they'd be used only rarely (probably at the end points, reading and writing to a database), and since they're one trivial calculation, a small comment at the call site would be sufficient.
Some of these really seem like they belong as instance methods on the
datetime object. In fact, a lot of them are in newer stdlib, and the entire point of your code is to also support versions of Python from before that was the case. So, it might be a good idea to simply offer a compatible interface. There's a few ways to do that.
First, the stdlib
datetime module is implemented in Python, so you could include a newer version of it wholesale and have your
dtutil module do this:
if sys.version_info < (2,7,0):
# Use the newer datetime module even
# on older versions of Python.
import datetime34 as datetime
Second, you could inherit from the stdlib one and add the missing functionality. If you want to add
_totalseconds directly to timedelta this way as well, you would also have to override
__rsub__ to turn any
timedelta object they are about to return into your extended
I was going to suggest monkey patching as another option (this being one limited context where it does seem worth it), but it turns out you can't (
I only recommend adding the strict compatibility things this way. The idea is to set it up so that if you stop supporting 2.6 down the track, you can delete this code without having to adjust anything else, except maybe some imports.
parse_datetime in particular ought to stay separate, especially because it fairly specifically enforces/assumes your local policy ("serialised dates will be in one of these two formats").
In this function:
dt = datetime.datetime.strptime(text, "%Y-%m-%d %H:%M:%S.%f")
dt = datetime.datetime.strptime(text, "%Y-%m-%d %H:%M:%S")
except:, it can mask bugs, and even cause some - eg, you might catch and ignore
except ValueError: instead. Consider adding a docstring to explicitly say that it tries two formats, as well as that it gives you a timezone-aware datetime.
if dt.tzinfo is None:
dt = get_localzone().localize(dt)
(dt - dt.utcoffset()).replace(tzinfo=None) -
datetime.datetime(1970, 1, 1))
The function before this guarantees that it will give an aware datetime, so I think it would be reasonable for this one to assume that is what it is given. Then if you're using the newer version of the module (or faking a compatible interface), then this is just:
localtz, but never use them. Drop those, they're just noise.