ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python夏令时问题

2019-11-21 09:09:31  阅读:528  来源: 互联网

标签:python-datetime python-dateutil timezone datetime python


我在夏时制上遇到麻烦.

让我解释一下上下文.

我将UTC中的日期存储在数据库中.每个用户都有一个时区,我也将此信息存储在数据库中.

我根据每个用户的时区计算“ 1个月”的时间段.

例如,用户应看到:

2014-01-06 -> 2014-02-05
2014-02-06 -> 2014-03-05
2014-03-06 -> 2014-04-05
2014-04-06 -> 2014-05-05
2014-05-06 -> 2014-06-05
etc.

夏令时开启或关闭时出现问题(三月和十一月)

代替:

> 2014-03-06-> 2014-04-05,我知道了2014-03-06-> 2014-04-06
> 2014-11-06-> 2014-12-05,我得到2014-11-05-> 2014-12-04

然后对所有下一个偏移量.

我尝试使用UTC日期,而不是将它们转换为用户时区以在get_end_date中添加1个月,但是仍然存在问题.

知道如何处理吗?

谢谢

这是我的代码和get_end_date方法.

import pytz
from dateutil.parser import parse as parse_date
from dateutil.relativedelta import relativedelta

def to_tz(dt, tz):
    tz = pytz.timezone(tz)
    return tz.normalize(dt.astimezone(tz))

def get_end_date(dt, tz):
    dt_central = to_tz(dt, tz)

    # Add 1 month, set hours, minutes, seconds, microseconds to 0 and remove -1 ms
    dt_central = dt_central + relativedelta(months=+1)
    dt_central = dt_central.replace(hour=0, minute=0, second=0, microsecond=0)
    dt_central = dt_central + relativedelta(microseconds=-1)

    return to_tz(dt_central, 'UTC')

def print_periods(start_dt, tz, nb_periods=6):    
    for i in xrange(nb_periods):
        print '\n# Period {}'.format(i+1)

        end_dt = get_end_date(start_dt, tz)
        start_dt_central, end_dt_central = to_tz(start_dt, tz), to_tz(end_dt, tz)

        print '{} -> {}'.format(start_dt_central.date(), end_dt_central.date())
        print '  > start_dt_central: ', start_dt_central
        print '  > end_dt_central: ', end_dt_central
        print '  > start_dt: ', start_dt
        print '  > end_dt: ', end_dt

        start_dt = end_dt + relativedelta(microseconds=1)

输出:

central_tz = 'US/Central'
start_dt = parse_date('2014-01-06 06:00:00+00:00')

In [7]: print_periods(start_dt, central_tz, nb_periods=12)
# Period 1
2014-01-06 -> 2014-02-05
  > start_dt_central:  2014-01-06 00:00:00-06:00
  > end_dt_central:  2014-02-05 23:59:59.999999-06:00
# Period 2
2014-02-06 -> 2014-03-05
  > start_dt_central:  2014-02-06 00:00:00-06:00
  > end_dt_central:  2014-03-05 23:59:59.999999-06:00
# Period 3
2014-03-06 -> 2014-04-06
  > start_dt_central:  2014-03-06 00:00:00-06:00
  > end_dt_central:  2014-04-06 00:59:59.999999-05:00
# Period 4
2014-04-06 -> 2014-05-05
  > start_dt_central:  2014-04-06 01:00:00-05:00
  > end_dt_central:  2014-05-05 23:59:59.999999-05:00
# Period 5
2014-05-06 -> 2014-06-05
  > start_dt_central:  2014-05-06 00:00:00-05:00
  > end_dt_central:  2014-06-05 23:59:59.999999-05:00
# Period 6
2014-06-06 -> 2014-07-05
  > start_dt_central:  2014-06-06 00:00:00-05:00
  > end_dt_central:  2014-07-05 23:59:59.999999-05:00
# Period 7
2014-07-06 -> 2014-08-05
  > start_dt_central:  2014-07-06 00:00:00-05:00
  > end_dt_central:  2014-08-05 23:59:59.999999-05:00
# Period 8
2014-08-06 -> 2014-09-05
  > start_dt_central:  2014-08-06 00:00:00-05:00
  > end_dt_central:  2014-09-05 23:59:59.999999-05:00
# Period 9
2014-09-06 -> 2014-10-05
  > start_dt_central:  2014-09-06 00:00:00-05:00
  > end_dt_central:  2014-10-05 23:59:59.999999-05:00
# Period 10
2014-10-06 -> 2014-11-05
  > start_dt_central:  2014-10-06 00:00:00-05:00
  > end_dt_central:  2014-11-05 22:59:59.999999-06:00
# Period 11
2014-11-05 -> 2014-12-04
  > start_dt_central:  2014-11-05 23:00:00-06:00
  > end_dt_central:  2014-12-04 23:59:59.999999-06:00
# Period 12
2014-12-05 -> 2015-01-04
  > start_dt_central:  2014-12-05 00:00:00-06:00
  > end_dt_central:  2015-01-04 23:59:59.999999-06:00

更新:解决方案

克里斯蒂安的解决方案1

def get_end_date(dt, tz):
    dt_central = to_tz(dt, tz)

    orig_tz = dt_central.tzinfo
    dt_central = dt_central.replace(tzinfo=None)

    # Calculations

    dt_central = orig_tz.localize(dt_central)

    dt_utc = to_tz(dt_central, 'UTC')

    return dt_utc 

我自己的解决方案2

def get_end_date(dt, tz):
    dt_central = to_tz(dt, tz)

    # Calculations

    dt_utc = to_tz(dt_central, 'UTC')

    # When switch to Daylight Saving Time
    if to_tz(dt_utc, tz).hour == 0:
        dt_utc = dt_utc.replace(hour=dt_utc.hour-1)
    # When leave Daylight Saving Time  
    elif to_tz(dt_utc, tz).hour == 22:
        dt_utc = dt_utc.replace(hour=dt_utc.hour+1)

    return dt_utc

解决方法:

在扩展vevents的重复规则时,dateutil的规则存在类似问题.对我有用的是保存时区信息,然后将每个datetime对象转换为朴素的datetime对象,进行计算,然后使用保存的时区本地化每个datetime.

因此,遵循以下原则:

orig_tz = dt.tzinfo
dt = dt.replace(tzinfo=None)

# do calculations here

orig_tz.localize(dt)

标签:python-datetime,python-dateutil,timezone,datetime,python
来源: https://codeday.me/bug/20191121/2050696.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有