Re: [Datetime-SIG] Datetime - my issues
[Skip Montanaro
.... ... For historical and interface reasons, the system I work with uses a mixture of epoch seconds, naive datetime objects, and tz-aware datetime objects,
Then for God's sake, be sure nobody in the office carries loaded guns - the temptation would be overpowering ;-)
,... Despite having to convert naive (and implicitly Chicago-based) datetime objects into tz-aware objects, I still find myself looking back at existing code to perform the conversions, as (for whatever reason) the method names aren't terribly suggestive to me, and I sometimes get the names wrong.
Is there anyone who _doesn't_ share that experience? There's also a mixture of relatively new and relatively ancient names in use.
... Getting the string you want (or very close to it, why would you want HHMM offset and timezone name?)
Because it is, in general, a many-to-many relationship (multiple names for a single offset, multiple offsets for a single name). For someone who only uses a relatively tiny subset of the possible canned timezones, though, collisions are unlikely, and I bet they'd rather just see the names. Except for those who'd rather just see the offsets. So that's why - ask for a new environment variable to control it? ;-)
is similarly straightforward, using a tz-aware datetime object:
now = Clock.local_datetime() now datetime.datetime(2015, 7, 29, 13, 15, 23, 650153, tzinfo=
) now.isoformat() '2015-07-29T13:15:23.650153-05:00' I do find the slightly slavish adherence to the old Unix time(3) function implication that "times don't have fractions of a second" a bit clumsy:
That's interesting to me, but mainly because I'm surprised your financial services applications care about fractional seconds! Do you, perhaps, track real-time transactions in heavily traded markets?
...
now datetime.datetime(2015, 7, 29, 13, 15, 23, 650153, tzinfo=
) now.timetuple() time.struct_time(tm_year=2015, tm_mon=7, tm_mday=29, tm_hour=13, tm_min=15, tm_sec=23, tm_wday=2, tm_yday=210, tm_isdst=1) What happened to my microseconds???
You're using methods designed for interoperability with the C language's ubiquitous "struct tm": http://pubs.opengroup.org/onlinepubs/007908775/xsh/time.h.html The meanings, and even the names of the fields, are identical between Python and C. A struct tm doesn't know microseconds from doughnuts. That's why microseconds are missing here. It's perhaps unfortunate that, when some functionality in C's standard library was already available in some Python module, datetime generally declined to implement a work-a-like of its own, more natural for use with datetime's view of things.
That forces me to write little helper functions like this:
def to_timestamp(dt): """Convert a datetime object into seconds since the Unix epoch.""" return time.mktime(dt.timetuple()) + dt.microsecond/1e6
Python 3.3 (which you don't use) added a timestamp() method to datetime objects.
Going forward, I think it would be cleaner if datetime.timetuple() returned a tuple with microseconds, and the relevant old-style functions in the time module were smart enough to know when to ignore them.
Death to legacy code. Come the revolution, even the letter C will be removed from the alphabet ;-)
I also occasionally want timedelta objects in seconds, so have this:
def as_seconds(delta): """Convert a timedelta object into seconds (float).""" return delta.days*24*60*60 + delta.seconds + delta.microseconds/1e6
Python 3.2 (which you don't use) added a total_seconds() method to timedetla objects, returning the same thing as your function.
Despite the overflow possibilities (I doubt I will still be working when that happens), I think it would be nice to have a few convenience functions like this, in the to-be-named-later datetime utils module.
As above, the timestamp and timedelta seconds functionalities were already added, via new methods.
I'm less thrilled with some heuristic function which allows you to take a datetime object and add or subtract some number of months, as I can't see a good way to get that right.
Nevertheless, there can be a _defined_ way, and even choice among multiple defined ways. While there is apparently no limit to the perversity of bureaucrats making up "business rules", the set of idiocies they can inflict on the world is almost certainly no worse than countably infinite, so Python long ints suffice to model them ;-)
Finally, at some point I read somewhere that using dtobject.astimezone(newzone) was preferable to using zone.normalize(dtobject). My code is now littered with both spellings, but I have no recollection of why one would be preferred over the other (except that pytz is clearly not part of the standard library).
Can't help there. I generally write my own tzinfo subclasses, because I only work for myself now, and like amusing timezone names ;-) From the massive discussion so far, it sounds like pytz does as much work to try to "fix" Python's datetime arithmetic as to supply a mountain of standardized zoneinfo objects. Since Python's datetime arithmetic is fine by me already, I don't need the extra complications of changing what already works (in my eyes).
Corollary: It seems to me like the astimezone call ought to work:
now = datetime.datetime.now() autoloading datetime import pytz chi = pytz.timezone("America/Chicago") now.astimezone(chi) ValueError astimezone() cannot be applied to a naive datetime [<stdin>|<module>|1] chi.localize(now) datetime.datetime(2015, 7, 29, 13, 39, 23, 139107, tzinfo=
) but maybe that's just a case of explicit-is-better-than-implicit...
Really a case of in-the-face-of-ambiguity-refuse-the-temptation-to-guess. now() returns a naive datetime, so astimezone() has no idea what you _think_ its timezone "really is". But note that you can pass a tzinfo argument to now() to _tell_ now() which timezone you want. Then .now(tz) acts like return tz.fromutc(datetime.utcnow().replace(tzinfo=tz)). That is, it returns an aware datetime for the timezone you passed in, recording current time in that timezone. So try just now = datetime.datetime.now(chi) instead? Or if you know darned well your system clock is using the `chi` timezone, even now = datetime.datetime.now().replace(tzinfo=chi) However, without being intimately familiar with all the details of pytz's "try to fix the arithmetic" gimmicks (just reading its docs doesn't reveal much about that), I can't guess whether pytz operations will be happy with datetimes created in those ways. Python's own operations will be delighted with them :-)
participants (1)
-
Tim Peters