【问题标题】:Odd behaviour of Ephem's Python package *localtime()* functionEphem 的 Python 包 *localtime()* 函数的奇怪行为
【发布时间】:2013-04-29 13:28:42
【问题描述】:

感谢http://www.lfd.uci.edu/%7Egohlke/pythonlibs/分发的预编译版本,我终于可以在我的Windows7 64位机器和Python 3.3.1中安装天文计算Ephem包了。

在学习使用它的过程中,我偶然发现了以下奇怪现象,对此我找不到任何解释:

Win32 上的 Python 3.3.1(v3.3.1:d9893d13c628,2013 年 4 月 6 日,20:30:21)[MSC v.1600 64 位 (AMD64)] 输入“copyright”、“credits”或“license()”了解更多信息。

>>> 导入 ehem

>>> ephem.localtime( ephem.Date( '1970' ) )

datetime.datetime(1970, 1, 1, 1, 0, 0, 3)

>>> ephem.localtime( ephem.Date( '1969' ) )

Traceback(最近一次调用最后一次):

文件“”,第 1 行,在 ephem.localtime(ephem.Date('1969'))

文件“C:\Python33\lib\site-packages\ephem__init__.py”,第 479 行,本地时间 timetuple = time.localtime(calendar.timegm(date.tuple()))

OSError: [Errno 22] 无效参数

>>>

所有小于 1970 的参数都会触发同样的错误。由于 ehem.Date() 似乎不是罪魁祸首,

>>> ephem.Date('1969')

25202.5

>>>

我只能得出结论,奇怪的行为属于 ehem.localtime()。是我用错了还是代码有bug?

【问题讨论】:

  • 尝试:import time; time.localtime(-31536000.0)(在 Ubuntu 上运行良好)。

标签: windows-7 python-3.x


【解决方案1】:

我并不直接熟悉 Ephem 包,但您看到的行为强烈表明您看到的是一个时代问题; Unix 纪元是 1970-01-01 00:00:00 UTC,尝试将在此之前的日期转换为 Unix 时间值(无符号 32 位或 64 位 int)将产生未定义的结果。

根据the documentation for Ephem's date method 判断,这不应该发生;这似乎使用了不同的内部时间表示,其纪元是 1899-12-31 12:00:00,尽管我不太确定在哪个时区。 Ephem localtime 方法,然而,returns a Python datetime objectPython's own documentation for the datetime moduledatetime 描述为支持从 1 到 9999 的年份,因此您看到的行为似乎表明,在 Ephem 的内部日期表示和 Python 的 datetime 之间的某个位置,尝试转换为 Unix 时间戳.查看您问题中的回溯,我们有以下高度暗示性的行:

File "C:\Python33\lib\site-packages\ephem__init__.py", line 479, in localtime \
timetuple = time.localtime(calendar.timegm(date.tuple()))

在检查the Python documentation for the calendar module 时,我们发现:

calendar.timegm(元组)

一个不相关但方便的函数,它接受一个时间元组,例如由 time 模块中的 gmtime() 函数返回,并返回相应的 Unix 时间戳值,假设 1970 年,以及POSIX 编码。实际上,time.gmtime() 和 timegm() 是互逆的。

所以问题来了:Ephem localtime() 试图通过 Unix 时间戳格式传递它的参数,这不起作用,因为早于 Unix 纪元的日期必须用负时间戳值表示,而 Unix 时间戳是一个无符号整数。

现在,至于如何解决这个问题,恐怕我可能无法提供太多帮助,因为我从未使用过 Ephem 或 Python。一般来说,我建议修改 Ephem localtime() 以便它不会尝试将其参数表示为 Unix 时间戳;也许您可以使用一些更广泛的时间表示,或者您可以重新设计localtime() 以根据 datetime 模块提供的时间转换功能进行操作。

我还想到您可能希望将此作为错误报告给 Ephem 开发人员;如果他们的包打算使用追溯到 1899 年甚至更早的日期,那么大概他们有兴趣知道他们包中的至少一个函数不能处理早于 1970 年的任何事情。(当然,他们的文档可能描述localtime()的这个限制;我看的时候没有发现任何关于它的东西,但我的评论几乎没有详尽。)

【讨论】:

  • 非常感谢 Aaron 的详尽解释。我将继续尝试理解和解决问题,你肯定已经查明了问题的原因。弗朗西斯科。
  • Unix 时间戳不是无符号整数。记录了相应的 Python 方法以接受/返回浮点数(尽管精度可能不超过一秒,具体取决于操作系统),至少在 Ubuntu 上它们接受负值。
  • ...为什么,所以不是。男孩,我的脸红了吗?
【解决方案2】:

它适用于我的机器(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)

【讨论】:

  • 这让它更奇怪了!弗朗西斯科。
  • 显然 time.localtime() 不能接受否定参数 on windows : time.localtime(-1) -> ValueError: (22, 'Invalid argument') 在 2.7.13 windows 7 上。最近被它咬了,正在寻找解决方法。我想这就是 OP 在 Windows 上出现问题的原因(可能在内部调用 time.localtime)
  • @Mr_and_Mrs_D 是的。 time 模块中的函数被记录为相应平台函数和 localtime() on Windows doesn't accept negative values 的瘦包装器
  • 谢谢!那应该是OP的问题。在我的情况下有什么简单的解决方法吗?还是值得提问?
  • @Mr_and_Mrs_D 这取决于你的情况,上下文。
猜你喜欢
  • 1970-01-01
  • 2014-12-20
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
  • 1970-01-01
  • 1970-01-01
  • 2017-09-14
  • 1970-01-01
相关资源
最近更新 更多