在Python中将日期时间写入和读取二进制格式

8
我想在Python中将一系列日期时间存储在二进制文件中。
编辑:所谓“二进制”是指每种数据类型的最佳数字表示法。这个应用场景是保存由(unix-timestamp,纬度,经度,海拔)组成的GPS轨迹点,因此整个结构是小端字节序的“长整型,浮点数,浮点数,浮点数”,每个值占四个字节。
注意:我使用“unix-timestamp”并不是因为有任何对Unix平台的喜好,而仅仅是作为表示日期时间值的明确方式。
目前,我正在像下面的代码一样处理,但除了一些时区混淆问题(我的时区是-3),我认为将其转换为int再转回去可能不是正确的方法,因为在python/numpy中,datetimedatetime64是原生类型,如果我没有弄错的话。因此,一个datetime64需要八个字节而不是我使用的四个字节(long)unix-timestamp。
import datetime
import calendar
import struct

now = datetime.datetime.now()
print now

stamp = calendar.timegm(now.utctimetuple())
print stamp

binarydatetime = struct.pack('<L', stamp)
recoverstamp = struct.unpack('<L', binarydatetime)[0]
print recoverstamp

recovernow = datetime.datetime.fromtimestamp(recoverstamp)
print recovernow

所以主要问题是:“这是将naive datetime转换为二进制并恢复的pythonic方法吗?”
另一个问题是:“如果代码中所有内容都应该是naive,为什么我有一个时区偏移量?”
谢谢阅读!

在这里定义“二进制”。您希望与哪些其他软件进行互操作?实际上,没有存储日期时间的二进制格式标准,大多数软件选择自己首选的格式,这个格式可能基于UNIX时间戳也可能不是。 - Martijn Pieters
@MartijnPieters 我希望数据类型以一种语言和平台无关的方式写入文件。请看我的编辑! - heltonbiker
1
将SQLite数据库视为便携式二进制格式,使用其本地日期时间类型来存储GPS轨迹点,以UTC(或GPS)时间。 - jfs
你解决了这个问题吗?(从字节中“读取”时间戳)。我也遇到了同样的问题。 - garrythehotdog
@garrythehotdog 请看下面我自己的回答。 - heltonbiker
3个回答

6
我发现了一种方法,使用Unix时间戳并将其存储为整数。这对我有效,因为我不需要毫秒级别的分辨率,但是我认为使用长整型可以通过修改代码实现微秒级别的分辨率。
与我的原始代码相比,更改的地方在于用time.mktime替换了calendar.timegm,并用timetuple替换了utctimetuple,以保持所有内容都是naive。
这样做:
import datetime
import struct
import time

now = datetime.datetime.now()
print now

stamp = time.mktime(now.timetuple())
print stamp

recoverstamp = datetime.datetime.fromtimestamp(stamp)
print recoverstamp

binarydatetime = struct.pack('<L', stamp)
recoverbinstamp = struct.unpack('<L', binarydatetime)[0]
print recoverbinstamp

recovernow = datetime.datetime.fromtimestamp(recoverbinstamp)
print recovernow

返回这个:

返回此内容:

2013-09-02 11:06:28.064000
1378130788.0
2013-09-02 11:06:28
1378130788
2013-09-02 11:06:28

通过这种方式,我可以轻松地将打包的binarydatetime写入文件,并稍后再次读取它。


对我来说,微秒很重要,你使用长整型是什么意思? - le_lemon
@le_lemon,Unix时间戳太大了,无法存储在32位有符号整数中,因此为了以微秒分辨率正确存储它,您需要更大的数字格式,例如uint、long,甚至更好的ulong(无符号64位整数)。请检查所有这些,也许我刚才说的不完全正确,但这些是原则。 - heltonbiker
@heltonbiker 看起来在打包之前需要将 stamp 转换为整数:binarydatetime = struct.pack('<L', int(stamp)) - Andrey

2

目前最简单的解决方案是使用Temporenc: http://temporenc.readthedocs.org/

它可以处理所有编码/解码问题,并允许您将Python datetime对象写入文件:

now = datetime.datetime.now()
temporenc.pack(fp, now)

阅读回复, 只需要这个:
dt = temporenc.unpack(fp)
print(dt)

0
如果您想将对象保存到二进制文件中,可以考虑使用pickle
据我所知,它会写入一个字节流,因此足够二进制化,但结果是Python特定的。
此外,我认为它应该可以处理日期时间。
最后,您可以使用以下代码进行保存:
with open('your_file', 'wb') as file:
    pickle.Pickler(file).dump(your_var)

这是用于恢复的代码

with open('your_file', 'rb') as file:
     recovered=pickle.Unpickler(file).load()

实际上,我想要一种与语言和平台无关的方式来存储datetime数据类型。请参见我的编辑。 - heltonbiker
啊,我曾经认为pickle不行。 你看,我想不出其他方法来做这件事,所以现在这肯定足够好了。"Pythonic"是一个非常抽象的概念(就像PEP 20一样). - Wjars
你可以使用str.encode('encodage')来获得十六进制、utf-8或其他表示字符串的方式,但这有点离题。 (5分钟的编辑会话时间太短了)无法帮助你。 - Wjars
实际上,我并没有存储表示日期和时间的字符串,而是一个“本地”的datetime.datetime对象:http://docs.python.org/2/library/datetime.html#datetime.datetime - heltonbiker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接