【问题标题】:Design - How to handle timestamps (storage) and when performing computations ; Python设计 - 如何处理时间戳(存储)以及何时执行计算; Python
【发布时间】:2013-01-13 19:30:15
【问题描述】:

我正在尝试确定(因为我的应用程序正在处理来自不同来源和不同时区、格式等的大量数据)如何最好地存储和使用我的数据。

例如,我应该将所有内容都存储为 UTC 吗?这意味着当我获取数据时,我需要确定它当前所在的时区,如果它不是 UTC,则进行必要的转换以使其如此。 (注意,我在 EST)。

然后,在对数据执行计算时,我是否应该提取(比如说它是 UTC)并进入我的时区 (EST),所以当我查看它时是否有意义?我应该将其保留为 UTC 并进行所有计算吗?

这些数据中有很多是时间序列的,并且会被绘制成图表,并且图表会在 EST 中。

这是一个 Python 项目,所以假设我有一个数据结构:

"id1": {
    "interval": 60,                            <-- seconds, subDict['interval']
    "last": "2013-01-29 02:11:11.151996+00:00" <-- UTC, subDict['last']
},

我需要对此进行操作,通过确定当前时间 (now()) 是否 > 最后一个 + 间隔(已经过去 60 秒)?所以在代码中:

lastTime = dateutil.parser.parse(subDict['last'])    
utcNow = datetime.datetime.utcnow().replace(tzinfo=tz.tzutc())

if lastTime + datetime.timedelta(seconds=subDict['interval']) < utcNow:
    print "Time elapsed, do something!"

这有意义吗?我在任何地方都在使用 UTC,无论是存储的还是计算的......

另外,如果有人有关于如何在软件中使用时间戳的优秀文章的链接,我很乐意阅读。可能类似于在应用程序中使用时间戳的 Joel On 软件?

【问题讨论】:

  • 抱歉 - 我错过了那里的编辑 - 但是,TZ 因“不正确”而臭名昭著
  • 没问题 - 嗯,是的,这是另一个问题......真是个 PITA。其他管理大量时间数据的项目是如何做到这一点的?
  • 很多项目都没有:)
  • 哈,好吧,我为这个应用程序的第一个 POC 也不是真的……结果调试问题真的很痛苦。而且代码看起来像废话。对于重写,我想正面解决这个问题并尽我所能解决它。
  • AFAIK 你正在尽你所能使用适当的库......

标签: python design-patterns datetime architecture system-design


【解决方案1】:

正如我所见,您似乎没有任何实现问题,我宁愿关注设计方面,而不是代码和时间戳格式。我有参与设计导航系统网络支持的经验,该导航系统在本地网络中实现为分布式系统。该系统的本质是存在大量数据(通常是冲突的),来自不同的来源,因此解决可能的冲突和保持数据完整性相当棘手。只是基于那次经验的一些想法。

时间戳数据,即使在包含许多计算机的分布式系统中,如果您不需要比系统时间函数提供的分辨率更高的分辨率和比操作系统组件提供的更高的时间同步精度,通常也不是问题。

在最简单的情况下,使用 UTC 是相当合理的,并且对于大多数任务来说已经足够了。但是,从设计之初就了解在系统中使用时间戳的目的很重要。时间值(无论是 Unix 时间还是格式化的 UTC 字符串)有时可能是相等的。如果您必须根据时间戳解决数据冲突(我的意思是,总是在从不同来源收到的多个值中选择一个较新(或较旧)的值),您需要了解是否存在错误解决的冲突(这通常意味着冲突可能以不止一种方式解决,因为时间戳是相等的)对于您的系统设计来说是一个致命的问题,或者不是。可能的选择是:

  1. 如果 99.99% 的冲突在所有节点上都以相同的方式解决,则您不必关心剩余的 0.01%,它们不会破坏数据完整性。在这种情况下,您可以安全地继续使用 UTC 之类的东西。

  2. 如果您必须严格解决所有冲突,则必须设计自己的时间戳系统。时间戳可能包括时间(可能不是系统时间,而是一些更高分辨率的计时器)、序列号(即使时间分辨率不足以生成唯一的时间戳)和节点标识符(允许系统的不同节点生成完全唯一的时间戳)。

  3. 最后,您需要的可能不是基于时间的时间戳。你真的需要能够计算一对时间戳之间的时间差吗?仅仅允许排序时间戳,而不是将它们连接到实时时刻还不够吗?如果您不需要时间计算,仅比较、基于顺序计数器而非实时的时间戳是一个不错的选择(有关详细信息,请参阅Lamport time)。

如果您需要严格的冲突解决,或者如果您需要非常高的时间分辨率,您可能必须编写自己的时间戳服务。

许多想法和线索可以从 A. Tanenbaum 的一本书“Distributed systems: Principles and paradigms”中借来。当我遇到这样的问题时,它对我帮助很大,并且其中有一个单独的章节专门讨论时间戳的生成。

【讨论】:

  • 好点。 #3 对我来说很突出,因为我有时间序列数据最终会被绘制出来(资本市场数据),我必须将现实生活/时间事件与它联系起来。在我进一步评论之前,我仍在消化你的整个帖子。
【解决方案2】:

我个人使用的是 Unix-time 标准,由于其简单的表示形式,存储起来非常方便,它只是一个数字序列。由于它在内部代表 UTC 时间,因此您必须确保在存储之前正确生成它(从其他时间戳转换)并根据您想要的任何时区对其进行格式化。

一旦您在后端数据中有一个通用的时间戳格式(tz 感知),绘制数据就非常容易,只需设置目标 TZ。

举个例子:

import time
import datetime
import pytz
# print pre encoded date in your local time from unix epoch
example = {"id1": {
                   "interval": 60,
                   "last": 1359521160.62
                   }
           }
#this will use your system timezone formatted
print time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(example['id1']['last']))
#this will use ISO country code to localize the timestamp
countrytz = pytz.country_timezones['BR'][0]
it = pytz.timezone(countrytz)
print  it.localize(datetime.datetime.utcfromtimestamp(example['id1']['last']))

【讨论】:

    【解决方案3】:

    在我看来,您似乎已经在“以正确的方式”做事。用户可能希望在他们的本地时区(输入和输出)中进行交互,但是以 UTC 格式存储标准化日期是正常的,这样它们就不会产生歧义并简化计算。因此,尽快标准化为 UTC,并尽可能晚地进行本地化。

    可以在此处找到有关 Python 和时区处理的少量信息:

    我目前的偏好是将日期作为 unix 时间戳 tv_sec 值存储在后端存储中,并在处理过程中转换为 Python datetime.datetime 对象。处理通常使用 UTC 时区中的 datetime 对象完成,然后在输出前转换为本地用户的时区。我发现拥有诸如datetime.datetime 之类的丰富对象有助于调试。

    时区处理起来很麻烦,您可能需要根据具体情况确定是否值得努力正确支持时区。

    例如,假设您正在计算每天使用的带宽计数。可能出现的一些问题是:

    1. 夏令时边界会发生什么?您是否应该假设一天总是 24 小时以便于计算,或者您是否需要始终检查每天在夏令时边界上可能有更少或更多小时的计算?
    2. 在呈现本地化时间时,是否重复时间是否重要?例如。如果您在本地时间显示每小时报告而没有附加时区,是否会让用户感到困惑,因为缺少一小时的数据,或者在夏令时更改前后重复一小时的数据。

    【讨论】:

    • 好点。我的帖子已经产生了很多详细的回复,我还在消化它们。
    • 我决定这样做并存储 UTC 时间戳。在阅读了 Django 文档后,我认为这是一个好主意,我觉得这样做很舒服。感谢您的意见。
    • 不用担心,很高兴您提出这个问题,因为我也对其他人的回答感兴趣。
    【解决方案4】:

    我认为最好的方法是将所有时间戳数据存储为 UTC。当您读入时,立即转换为UTC;在显示之前,将 UTC 转换为您当地的时区。

    您甚至可能希望您的代码两次打印所有时间戳,一次在本地时间,第二次在 UTC 时间...这取决于您需要一次在屏幕上显示多少数据。

    我是 RFC 3339 时间戳格式的忠实粉丝。它对人类和机器来说都是明确的。最好的一点是几乎没有什么是可选的,所以看起来总是一样的:

    2013-01-29T19:46:00.00-08:00
    

    我更喜欢将时间戳转换为单个浮点值以进行存储和计算,然后再转换回日期时间格式以进行显示。我不会在浮点数中存钱,但时间戳值在浮点值的精度范围内!

    使用时间浮点数让很多代码变得非常简单:

    if time_now() >= last_time + interval:
        print("interval has elapsed")
    

    看起来你已经在这样做了,所以我不能建议任何显着的改进。

    我编写了一些库函数来将时间戳解析为 Python 时间浮点值,并将时间浮点值转换回时间戳字符串。也许这里的东西对你有用:

    http://home.blarg.net/~steveha/pyfeed.html

    我建议你看看feed.date.rfc3339。 BSD 许可证,因此您可以根据需要使用代码。

    编辑:问题:这对时区有什么帮助?

    Answer: 如果你存储的每个时间戳都以 UTC 时间存储为 Python 时间浮点值(自纪元以来的秒数,小数部分可选),你可以直接比较它们;从另一个中减去一个以找出它们之间的间隔;等等。如果您使用 RFC 3339 时间戳,那么每个时间戳字符串在时间戳字符串中都有时区,并且可以通过您的代码正确地将其转换为 UTC 时间。如果您在显示之前将浮点值转换为时间戳字符串值,则时区将与当地时间正确。

    另外,正如我所说,看起来他已经在做这件事了,所以我不认为我可以提供任何惊人的建议。

    【讨论】:

    • 没有向 OP 解释这对时区有何帮助?
    • 谢谢 - 这确实有道理,但我决定使用 UTC 时间戳而不是 RFC3339 - 部分原因是我已经对 UTC 实现 VS RFC3339 感到舒服。我非常感谢您的反馈,并将在未来的项目中牢记此解决方案。
    • 我不确定您所说的“UTC 时间戳”是什么意思。默认情况下,RFC3339 时间戳为 UTC(如果时区为“Z”或“-00:00”)。无论如何,祝你的项目好运。
    • 对不起 - 我的意思是格式 2013-01-29T19:46:00.00-08:00 VS 2013-01-29 02:11:11.151996+00:00。如果第一个是 RFC3339 UTC 时间戳,那么第二个叫什么?
    • 我不确定它是否有一个通用名称,但它就像一个带有空格的 RFC3339 时间戳,而不是中间的 T。我刚刚检查了 RFC 3339 规范文档,看起来 T 可以选择替换为空格。所以也许它只是 RFC3339 的一个可接受的变体。
    猜你喜欢
    • 1970-01-01
    • 2011-07-02
    • 2015-02-26
    • 2019-02-09
    • 2013-04-30
    • 1970-01-01
    • 2019-12-19
    • 2019-12-17
    • 1970-01-01
    相关资源
    最近更新 更多