I could finally install the astronomical calculations Ephem package in my Windows7 64 bit machine and Python 3.3.1 thanks to the precompiled version distributed by http://www.lfd.uci.edu/%7Egohlke/pythonlibs/.
In learning to use it I have stumbled on the following oddity, for which I can find no explanation:
Python 3.3.1 (v3.3.1:d9893d13c628, Apr 6 2013, 20:30:21) [MSC v.1600 64 bit (AMD64)] on win32 Type "copyright", "credits" or "license()" for more information.
>>> import ephem
>>> ephem.localtime( ephem.Date( '1970' ) )
datetime.datetime(1970, 1, 1, 1, 0, 0, 3)
>>> ephem.localtime( ephem.Date( '1969' ) )
Traceback (most recent call last):
File "", line 1, in ephem.localtime( ephem.Date( '1969' ) )
File "C:\Python33\lib\site-packages\ephem__init__.py", line 479, in localtime timetuple = time.localtime(calendar.timegm(date.tuple()))
OSError: [Errno 22] Invalid argument
>>>
All arguments smaller than 1970 trigger this same error. As ephem.Date() does not seem to be the culprit,
>>> ephem.Date('1969')
25202.5
>>>
I can only conclude that the odd behaviour belongs to ephem.localtime(). Is my use of it mistaken or does the code have some bug?
I'm not directly familiar with the Ephem package, but the behavior you're seeing strongly suggests that what you're seeing is an epoch problem; the Unix epoch being 1970-01-01 00:00:00 UTC, attempts to convert dates prior to that into a Unix time value (an unsigned 32- or 64-bit int) will have undefined results.
Judging by the documentation for Ephem's date method, this shouldn't be happening; that appears to use a different internal time representation whose epoch is 1899-12-31 12:00:00, though I'm not quite sure in what time zone. The Ephem localtime method, however, returns a Python datetime object; Python's own documentation for the datetime module describes datetime as supporting years ranging from 1 to 9999, so the behavior you're seeing would seem to suggest that, somewhere between Ephem's internal date representation and Python's datetime, there's an attempt to convert to a Unix timestamp. Looking at the traceback in your question, we have the following highly suggestive line:
File "C:\Python33\lib\site-packages\ephem__init__.py", line 479, in localtime \
timetuple = time.localtime(calendar.timegm(date.tuple()))
And in checking the Python documentation for the calendar module, we find:
calendar.timegm(tuple)
An unrelated but handy function that takes a time tuple such as returned by the gmtime() function in the time module, and returns the corresponding Unix timestamp value, assuming an epoch of 1970, and the POSIX encoding. In fact, time.gmtime() and timegm() are each others’ inverse.
So there's the problem: Ephem localtime() is trying to pass its argument through the Unix timestamp format, which isn't working because dates earlier than the Unix epoch would have to be represented by negative timestamp values, and the Unix timestamp is an unsigned integer.
Now, as for how to go about fixing this, there I'm afraid I may not be of as much help, because I've never used either Ephem or Python. In general, I'd advise modifying Ephem localtime() so that it doesn't try to represent its argument as a Unix timestamp; perhaps there's some more widely ranging time representation you could use, or perhaps you could rework localtime() to operate in terms of the time conversion functions provided by the datetime module.
It also occurs to me that you may wish to report this to the Ephem developers as a bug; if their package is intended to work with dates ranging back to 1899 and possibly before, then presumably they would be interested to know at least one of the functions in their package can't handle anything earlier than 1970. (Of course, their documentation may describe this limitation of localtime(); I didn't find anything about it when I looked, but my review was hardly exhaustive.)
It works on my machine (Ubuntu, Python 3.3.0, ephem 3.7.5.1):
>>> import ephem
>>> ephem.Date('1969')
25202.5
>>> d = ephem.Date('1969')
>>> d.datetime() # utc
datetime.datetime(1969, 1, 1, 0, 0)
>>> ephem.localtime(d) # local timezone
datetime.datetime(1969, 1, 1, 6, 0, 0, 2)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With