【问题标题】:Making matplotlib's date2num and num2date perfect inverses使 matplotlib 的 date2num 和 num2date 完美逆
【发布时间】:2012-10-26 22:16:10
【问题描述】:

我正在尝试编写一对函数,plottmunixtm,它们在正常的 unix 时间(自 1970-01-01 以来的秒数)和 Matplotlib 的日期表示(自最后一天以来的天数)之间来回转换-1BC 之类的,一个浮点数)。

如果 plottmunixtm 是正确的倒数,则此代码将打印相同的日期/时间两次:

import time, datetime
import matplotlib.dates as dt

# Convert a unix time u to plot time p, and vice versa
def plottm(u): return dt.date2num(datetime.datetime.fromtimestamp(u))
def unixtm(p): return time.mktime(dt.num2date(p).timetuple())

u = 1270000000
print datetime.datetime.fromtimestamp(u), "-->", \
      datetime.datetime.fromtimestamp(unixtm(plottm(u)))

唉,它已经关闭了一个小时(这只发生在某些时间戳上,否则我会插入一个偏移量并完成它)。

可能相关:Problems with Localtime

更新:不特定于 Matplotlib 的相关问题:Convert a unixtime to a datetime object and back again (pair of time conversion functions that are inverses)

【问题讨论】:

    标签: python date datetime matplotlib


    【解决方案1】:

    基于@dreeves 的回答,一种适用于时区感知日期时间的解决方案:

    import matplotlib.dates as dt
    
    from calendar import timegm
    from datetime import datetime
    
    from pytz import utc
    
    
    # Convert a unix time u to plot time p, and vice versa
    def plottm(u):
        return dt.date2num(datetime.fromtimestamp(u, utc))
    
    def unixtm(p):
        return timegm(dt.num2date(p, utc).utctimetuple())
    
    
    u = 1270000000
    print datetime.fromtimestamp(u, utc), "-->", \
          datetime.fromtimestamp(unixtm(plottm(u)), utc)
    

    输出(针对多个时区测试):

    2010-03-31 01:46:40+00:00 --> 2010-03-31 01:46:40+00:00
    

    【讨论】:

    • 当我运行这个时,我的输出是2010-03-31 01:46:40+00:00 --> 2010-03-31 06:46:40+00:00 (1270000000 --> 1270018000)
    • 问题是我的时区目前是UTC,我应该用不同的本地时间进行测试......现在测试。
    • 你能试试更正的例子吗?它使用几个本地时区对其进行了测试,因此现在应该是正确的。
    • 非常感谢,佩德罗!与此同时,我问了这个问题的更一般的版本,这导致了我认为比弄乱 tzlocal 更好的方法。我刚刚发布了一个现在对我有用的答案。
    【解决方案2】:

    感谢F.J.similar question的回复,我相信以下可能是最好的处理方式:

    import datetime, calendar
    import matplotlib.dates as dt
    
    def plottm(u): return dt.date2num(datetime.datetime.utcfromtimestamp(u))
    def unixtm(p): return calendar.timegm(dt.num2date(p).timetuple())
    

    【讨论】:

    • 绝对更好的解决方案:+1 来自我! :) 我确信 time.mktime 有一个 UTC 等价物,但对于我的一生,我不记得在哪里(它在 time.gmtime 文档的上方几行中盯着我看)!应该始终在 UTC 内部工作,并且到/从本地时间应该只发生在用户界面上。
    • num2date 取决于可以配置为任何时区的 tz,timegm 期望 utc 时间,因此 num2date 应该始终以 utc 形式返回时间。我不知道date2num 期望什么时区(如果它不总是UTC;代码可能会失败)。
    【解决方案3】:

    matplotlib.dates.epoch2num()/num2epoch functions 正是这样做的:

    from datetime import datetime, timedelta
    import matplotlib.dates as mpl_dt
    
    matplotlib_epoch = datetime(1, 1, 1)  # utc
    posix_epoch = datetime(1970, 1, 1)  # utc
    DAY = 86400  # seconds
    
    
    def plottm(u):
        """posix timestamp -> plot time"""
        td = (datetime.utcfromtimestamp(u) - matplotlib_epoch)
        return td.days + 1 + (1000000 * td.seconds + td.microseconds) / 1e6 / DAY
    
    
    def unixtm(p):
        """plot time -> posix timestamp"""
        td = timedelta(days=p-1)
        return (matplotlib_epoch + td - posix_epoch).total_seconds()
    
    
    def main():
        f = datetime.utcfromtimestamp
        u = 1270000000.1234567890
        print(f(u))
        print(mpl_dt.epoch2num(u))
        print(plottm(u))
        print(f(mpl_dt.num2epoch(mpl_dt.epoch2num(u))))
        print(f(mpl_dt.num2epoch(plottm(u))))
        print(f(unixtm(mpl_dt.epoch2num(u))))
        print(f(unixtm(plottm(u))))
    
        assert abs(mpl_dt.epoch2num(u) - plottm(u)) < 1e-5
    
        p = 86401.234567890 / DAY
        print(f(mpl_dt.num2epoch(p)))
        print(f(unixtm(p)))
        assert abs(mpl_dt.num2epoch(p) - unixtm(p)) < 1e-5
    
    main()
    

    输出

    2010-03-31 01:46:40.123457
    733862.074076
    733862.074076
    2010-03-31 01:46:40.123453
    2010-03-31 01:46:40.123453
    2010-03-31 01:46:40.123453
    2010-03-31 01:46:40.123453
    0001-01-01 00:00:01.234566
    0001-01-01 00:00:01.234566
    

    【讨论】:

    • 谢谢 J.F.!您是否认为有任何理由比我发布的解决方案更喜欢这个解决方案(基于 F.J. 的回答,令人困惑)?
    • @dreeves:是的。您的代码可能不正确。我已经离开appropriate comment on your answer。除非您有特定理由不使用它们,否则应使用 epoch2num/num2epoch。您也可以测试datetime.mindatetime.max 周围的时间,以查看精度是否丢失或是否有效。
    猜你喜欢
    • 1970-01-01
    • 2018-01-14
    • 2019-04-08
    • 2019-05-04
    • 2010-12-05
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多