我第一次来:)
我有以下Pandas DataFrame
date time
0 2018-03-24 23
1 2018-03-24 24
2 2018-03-25 1
3 2018-03-25 2
4 2018-03-25 3
5 2018-03-25 4
6 2018-03-25 5
7 2018-03-25 6
8 2018-03-25 7
9 2018-03-25 8
10 2018-03-25 9
11 2018-03-25 10
12 2018-03-25 11
13 2018-03-25 12
14 2018-03-25 13
15 2018-03-25 14
16 2018-03-25 15
17 2018-03-25 16
18 2018-03-25 17
19 2018-03-25 18
20 2018-03-25 19
21 2018-03-25 20
22 2018-03-25 21
23 2018-03-25 22
24 2018-03-25 23
25 2018-03-26 1
26 2018-03-26 2
27 2018-03-26 3
28 2018-03-26 4
29 2018-03-26 5
30 2018-03-26 6
31 2018-10-27 23
32 2018-10-27 24
33 2018-10-28 1
34 2018-10-28 2
35 2018-10-28 3
36 2018-10-28 4
37 2018-10-28 5
38 2018-10-28 6
39 2018-10-28 7
40 2018-10-28 8
41 2018-10-28 9
42 2018-10-28 10
43 2018-10-28 11
44 2018-10-28 12
45 2018-10-28 13
46 2018-10-28 14
47 2018-10-28 15
48 2018-10-28 16
49 2018-10-28 17
50 2018-10-28 18
51 2018-10-28 19
52 2018-10-28 20
53 2018-10-28 21
54 2018-10-28 22
55 2018-10-28 23
56 2018-10-28 24
57 2018-10-28 25
58 2018-10-29 1
59 2018-10-29 2
第time
列应表示一天中的小时减去一,例如
date time
2 2018-03-25 1
等于2018-03-25 00:00
欧洲/伦敦时间。
生成此时间序列数据的设备设置为根据'Europe/London'
时区工作,这就是为什么2018年3月25日在23小时(记录[2:25]
)结束,而2018年10月28日结束的原因25小时(记录[33:58]
)(DST开关)。
这是我已经尝试过的东西:
from pytz import timezone
tz = timezone("Europe/London")
dst_switch = [dt for dt in tz._utc_transition_times if dt.year == 2018]
dst_switch_date_range = pd.date_range(dst_switch[0],dst_switch[1], freq='h', tz='utc')
df['datetime'] = pd.to_datetime(df.date) + pd.to_timedelta(df.time - 1, unit='h')
df['dt_utc'] = df['datetime'].dt.tz_localize('UTC')
df['dst_switch'] = df['datetime'].map(lambda dt: 1 if dt in dst_switch_date_range else -1)
df['dt_p'] = df['datetime'] + pd.to_timedelta(df['dst_switch'], unit='h')
df['dt_utc_p'] = df['dt_p'].dt.tz_localize('Europe/London', ambiguous='NaT', nonexistent='NaT').dt.tz_convert('UTC')
df[['date', 'time', 'dt', 'dt_utc', 'map','dt_p', 'dt_utc_p']]
结果为:
date time dt dt_utc dst_switch dt_p dt_utc_p
0 2018-03-24 23 2018-03-24 23:00:00 2018-03-24 22:00:00+00:00 -1 2018-03-24 21:00:00 2018-03-24 21:00:00+00:00
1 2018-03-24 24 2018-03-25 00:00:00 2018-03-24 23:00:00+00:00 -1 2018-03-24 22:00:00 2018-03-24 22:00:00+00:00
2 2018-03-25 1 2018-03-25 01:00:00 2018-03-25 00:00:00+00:00 -1 2018-03-24 23:00:00 2018-03-24 23:00:00+00:00
3 2018-03-25 2 2018-03-25 02:00:00 2018-03-25 01:00:00+00:00 1 2018-03-25 02:00:00 2018-03-25 01:00:00+00:00
4 2018-03-25 3 2018-03-25 03:00:00 2018-03-25 02:00:00+00:00 1 2018-03-25 03:00:00 2018-03-25 02:00:00+00:00
5 2018-03-25 4 2018-03-25 04:00:00 2018-03-25 03:00:00+00:00 1 2018-03-25 04:00:00 2018-03-25 03:00:00+00:00
6 2018-03-25 5 2018-03-25 05:00:00 2018-03-25 04:00:00+00:00 1 2018-03-25 05:00:00 2018-03-25 04:00:00+00:00
7 2018-03-25 6 2018-03-25 06:00:00 2018-03-25 05:00:00+00:00 1 2018-03-25 06:00:00 2018-03-25 05:00:00+00:00
8 2018-03-25 7 2018-03-25 07:00:00 2018-03-25 06:00:00+00:00 1 2018-03-25 07:00:00 2018-03-25 06:00:00+00:00
9 2018-03-25 8 2018-03-25 08:00:00 2018-03-25 07:00:00+00:00 1 2018-03-25 08:00:00 2018-03-25 07:00:00+00:00
10 2018-03-25 9 2018-03-25 09:00:00 2018-03-25 08:00:00+00:00 1 2018-03-25 09:00:00 2018-03-25 08:00:00+00:00
11 2018-03-25 10 2018-03-25 10:00:00 2018-03-25 09:00:00+00:00 1 2018-03-25 10:00:00 2018-03-25 09:00:00+00:00
12 2018-03-25 11 2018-03-25 11:00:00 2018-03-25 10:00:00+00:00 1 2018-03-25 11:00:00 2018-03-25 10:00:00+00:00
13 2018-03-25 12 2018-03-25 12:00:00 2018-03-25 11:00:00+00:00 1 2018-03-25 12:00:00 2018-03-25 11:00:00+00:00
14 2018-03-25 13 2018-03-25 13:00:00 2018-03-25 12:00:00+00:00 1 2018-03-25 13:00:00 2018-03-25 12:00:00+00:00
15 2018-03-25 14 2018-03-25 14:00:00 2018-03-25 13:00:00+00:00 1 2018-03-25 14:00:00 2018-03-25 13:00:00+00:00
16 2018-03-25 15 2018-03-25 15:00:00 2018-03-25 14:00:00+00:00 1 2018-03-25 15:00:00 2018-03-25 14:00:00+00:00
17 2018-03-25 16 2018-03-25 16:00:00 2018-03-25 15:00:00+00:00 1 2018-03-25 16:00:00 2018-03-25 15:00:00+00:00
18 2018-03-25 17 2018-03-25 17:00:00 2018-03-25 16:00:00+00:00 1 2018-03-25 17:00:00 2018-03-25 16:00:00+00:00
19 2018-03-25 18 2018-03-25 18:00:00 2018-03-25 17:00:00+00:00 1 2018-03-25 18:00:00 2018-03-25 17:00:00+00:00
20 2018-03-25 19 2018-03-25 19:00:00 2018-03-25 18:00:00+00:00 1 2018-03-25 19:00:00 2018-03-25 18:00:00+00:00
21 2018-03-25 20 2018-03-25 20:00:00 2018-03-25 19:00:00+00:00 1 2018-03-25 20:00:00 2018-03-25 19:00:00+00:00
22 2018-03-25 21 2018-03-25 21:00:00 2018-03-25 20:00:00+00:00 1 2018-03-25 21:00:00 2018-03-25 20:00:00+00:00
23 2018-03-25 22 2018-03-25 22:00:00 2018-03-25 21:00:00+00:00 1 2018-03-25 22:00:00 2018-03-25 21:00:00+00:00
24 2018-03-25 23 2018-03-25 23:00:00 2018-03-25 22:00:00+00:00 1 2018-03-25 23:00:00 2018-03-25 22:00:00+00:00
25 2018-03-26 1 2018-03-26 01:00:00 2018-03-26 00:00:00+00:00 1 2018-03-26 01:00:00 2018-03-26 00:00:00+00:00
26 2018-03-26 2 2018-03-26 02:00:00 2018-03-26 01:00:00+00:00 1 2018-03-26 02:00:00 2018-03-26 01:00:00+00:00
27 2018-03-26 3 2018-03-26 03:00:00 2018-03-26 02:00:00+00:00 1 2018-03-26 03:00:00 2018-03-26 02:00:00+00:00
28 2018-03-26 4 2018-03-26 04:00:00 2018-03-26 03:00:00+00:00 1 2018-03-26 04:00:00 2018-03-26 03:00:00+00:00
29 2018-03-26 5 2018-03-26 05:00:00 2018-03-26 04:00:00+00:00 1 2018-03-26 05:00:00 2018-03-26 04:00:00+00:00
30 2018-03-26 6 2018-03-26 06:00:00 2018-03-26 05:00:00+00:00 1 2018-03-26 06:00:00 2018-03-26 05:00:00+00:00
31 2018-10-27 23 2018-10-27 23:00:00 2018-10-27 22:00:00+00:00 1 2018-10-27 23:00:00 2018-10-27 22:00:00+00:00
32 2018-10-27 24 2018-10-28 00:00:00 2018-10-27 23:00:00+00:00 1 2018-10-28 00:00:00 2018-10-27 23:00:00+00:00
33 2018-10-28 1 2018-10-28 01:00:00 2018-10-28 00:00:00+00:00 1 2018-10-28 01:00:00 NaT
34 2018-10-28 2 2018-10-28 02:00:00 2018-10-28 01:00:00+00:00 1 2018-10-28 02:00:00 2018-10-28 02:00:00+00:00
35 2018-10-28 3 2018-10-28 03:00:00 2018-10-28 02:00:00+00:00 -1 2018-10-28 01:00:00 NaT
36 2018-10-28 4 2018-10-28 04:00:00 2018-10-28 03:00:00+00:00 -1 2018-10-28 02:00:00 2018-10-28 02:00:00+00:00
37 2018-10-28 5 2018-10-28 05:00:00 2018-10-28 04:00:00+00:00 -1 2018-10-28 03:00:00 2018-10-28 03:00:00+00:00
38 2018-10-28 6 2018-10-28 06:00:00 2018-10-28 05:00:00+00:00 -1 2018-10-28 04:00:00 2018-10-28 04:00:00+00:00
39 2018-10-28 7 2018-10-28 07:00:00 2018-10-28 06:00:00+00:00 -1 2018-10-28 05:00:00 2018-10-28 05:00:00+00:00
40 2018-10-28 8 2018-10-28 08:00:00 2018-10-28 07:00:00+00:00 -1 2018-10-28 06:00:00 2018-10-28 06:00:00+00:00
41 2018-10-28 9 2018-10-28 09:00:00 2018-10-28 08:00:00+00:00 -1 2018-10-28 07:00:00 2018-10-28 07:00:00+00:00
42 2018-10-28 10 2018-10-28 10:00:00 2018-10-28 09:00:00+00:00 -1 2018-10-28 08:00:00 2018-10-28 08:00:00+00:00
43 2018-10-28 11 2018-10-28 11:00:00 2018-10-28 10:00:00+00:00 -1 2018-10-28 09:00:00 2018-10-28 09:00:00+00:00
44 2018-10-28 12 2018-10-28 12:00:00 2018-10-28 11:00:00+00:00 -1 2018-10-28 10:00:00 2018-10-28 10:00:00+00:00
45 2018-10-28 13 2018-10-28 13:00:00 2018-10-28 12:00:00+00:00 -1 2018-10-28 11:00:00 2018-10-28 11:00:00+00:00
46 2018-10-28 14 2018-10-28 14:00:00 2018-10-28 13:00:00+00:00 -1 2018-10-28 12:00:00 2018-10-28 12:00:00+00:00
47 2018-10-28 15 2018-10-28 15:00:00 2018-10-28 14:00:00+00:00 -1 2018-10-28 13:00:00 2018-10-28 13:00:00+00:00
48 2018-10-28 16 2018-10-28 16:00:00 2018-10-28 15:00:00+00:00 -1 2018-10-28 14:00:00 2018-10-28 14:00:00+00:00
49 2018-10-28 17 2018-10-28 17:00:00 2018-10-28 16:00:00+00:00 -1 2018-10-28 15:00:00 2018-10-28 15:00:00+00:00
50 2018-10-28 18 2018-10-28 18:00:00 2018-10-28 17:00:00+00:00 -1 2018-10-28 16:00:00 2018-10-28 16:00:00+00:00
51 2018-10-28 19 2018-10-28 19:00:00 2018-10-28 18:00:00+00:00 -1 2018-10-28 17:00:00 2018-10-28 17:00:00+00:00
52 2018-10-28 20 2018-10-28 20:00:00 2018-10-28 19:00:00+00:00 -1 2018-10-28 18:00:00 2018-10-28 18:00:00+00:00
53 2018-10-28 21 2018-10-28 21:00:00 2018-10-28 20:00:00+00:00 -1 2018-10-28 19:00:00 2018-10-28 19:00:00+00:00
54 2018-10-28 22 2018-10-28 22:00:00 2018-10-28 21:00:00+00:00 -1 2018-10-28 20:00:00 2018-10-28 20:00:00+00:00
55 2018-10-28 23 2018-10-28 23:00:00 2018-10-28 22:00:00+00:00 -1 2018-10-28 21:00:00 2018-10-28 21:00:00+00:00
56 2018-10-28 24 2018-10-29 00:00:00 2018-10-28 23:00:00+00:00 -1 2018-10-28 22:00:00 2018-10-28 22:00:00+00:00
57 2018-10-28 25 2018-10-29 01:00:00 2018-10-29 00:00:00+00:00 -1 2018-10-28 23:00:00 2018-10-28 23:00:00+00:00
58 2018-10-29 1 2018-10-29 01:00:00 2018-10-29 00:00:00+00:00 -1 2018-10-28 23:00:00 2018-10-28 23:00:00+00:00
59 2018-10-29 2 2018-10-29 02:00:00 2018-10-29 01:00:00+00:00 -1 2018-10-29 00:00:00 2018-10-29 00:00:00+00:00
我需要的:我需要将这两列合并为datetime列,然后将时区从'Europe/London'
转换为'UTC'
(或其他方式:在time
列以适合'UTC'
,然后与date
列合并)
我的逻辑:1年的时间为24h * 365天= 8760小时。如果我采用上述全年的时间序列数据,则应该得到363天,每条记录24条,1天23条记录,和1天25条记录,总共8712 + 23 + 25 = 8760条记录,因此,每条记录一年中的小时。
我失败了:将我的逻辑翻译为代码:P。我对如何补偿这些日期没有好主意,因此一切都会有意义,这意味着DST切换日期之间的平滑过渡,没有重复的时间序列值,也没有时间序列中的值(空洞)。
预期结果:
date time dt_utc
0 2018-03-24 23 2018-03-24 22:00:00+00:00
1 2018-03-24 24 2018-03-24 23:00:00+00:00
2 2018-03-25 1 2018-03-25 00:00:00+00:00
3 2018-03-25 2 2018-03-25 01:00:00+00:00
4 2018-03-25 3 2018-03-25 02:00:00+00:00
5 2018-03-25 4 2018-03-25 03:00:00+00:00
6 2018-03-25 5 2018-03-25 04:00:00+00:00
7 2018-03-25 6 2018-03-25 05:00:00+00:00
8 2018-03-25 7 2018-03-25 06:00:00+00:00
9 2018-03-25 8 2018-03-25 07:00:00+00:00
10 2018-03-25 9 2018-03-25 08:00:00+00:00
11 2018-03-25 10 2018-03-25 09:00:00+00:00
12 2018-03-25 11 2018-03-25 10:00:00+00:00
13 2018-03-25 12 2018-03-25 11:00:00+00:00
14 2018-03-25 13 2018-03-25 12:00:00+00:00
15 2018-03-25 14 2018-03-25 13:00:00+00:00
16 2018-03-25 15 2018-03-25 14:00:00+00:00
17 2018-03-25 16 2018-03-25 15:00:00+00:00
18 2018-03-25 17 2018-03-25 16:00:00+00:00
19 2018-03-25 18 2018-03-25 17:00:00+00:00
20 2018-03-25 19 2018-03-25 18:00:00+00:00
21 2018-03-25 20 2018-03-25 19:00:00+00:00
22 2018-03-25 21 2018-03-25 20:00:00+00:00
23 2018-03-25 22 2018-03-25 21:00:00+00:00
24 2018-03-25 23 2018-03-25 22:00:00+00:00
25 2018-03-26 1 2018-03-25 23:00:00+00:00
26 2018-03-26 2 2018-03-26 00:00:00+00:00
27 2018-03-26 3 2018-03-26 01:00:00+00:00
28 2018-03-26 4 2018-03-26 02:00:00+00:00
29 2018-03-26 5 2018-03-26 03:00:00+00:00
30 2018-03-26 6 2018-03-26 04:00:00+00:00
31 2018-10-27 23 2018-10-27 21:00:00+00:00
32 2018-10-27 24 2018-10-27 22:00:00+00:00
33 2018-10-28 1 2018-10-27 23:00:00+00:00
34 2018-10-28 2 2018-10-28 00:00:00+00:00
35 2018-10-28 3 2018-10-28 01:00:00+00:00
36 2018-10-28 4 2018-10-28 02:00:00+00:00
37 2018-10-28 5 2018-10-28 03:00:00+00:00
38 2018-10-28 6 2018-10-28 04:00:00+00:00
39 2018-10-28 7 2018-10-28 05:00:00+00:00
40 2018-10-28 8 2018-10-28 06:00:00+00:00
41 2018-10-28 9 2018-10-28 07:00:00+00:00
42 2018-10-28 10 2018-10-28 08:00:00+00:00
43 2018-10-28 11 2018-10-28 09:00:00+00:00
44 2018-10-28 12 2018-10-28 10:00:00+00:00
45 2018-10-28 13 2018-10-28 11:00:00+00:00
46 2018-10-28 14 2018-10-28 12:00:00+00:00
47 2018-10-28 15 2018-10-28 13:00:00+00:00
48 2018-10-28 16 2018-10-28 14:00:00+00:00
49 2018-10-28 17 2018-10-28 15:00:00+00:00
50 2018-10-28 18 2018-10-28 16:00:00+00:00
51 2018-10-28 19 2018-10-28 17:00:00+00:00
52 2018-10-28 20 2018-10-28 18:00:00+00:00
53 2018-10-28 21 2018-10-28 19:00:00+00:00
54 2018-10-28 22 2018-10-28 20:00:00+00:00
55 2018-10-28 23 2018-10-28 21:00:00+00:00
56 2018-10-28 24 2018-10-28 22:00:00+00:00
57 2018-10-28 25 2018-10-28 23:00:00+00:00
58 2018-10-29 1 2018-10-29 00:00:00+00:00
59 2018-10-29 2 2018-10-29 01:00:00+00:00
请帮助:)
答案 0 :(得分:1)
该问题中的优秀MCVE。让datetime,timezone和timedeltas处理DST。我没有检查结果,但这应该很好。
import pandas as pd
from pandas.compat import StringIO
print(pd.__version__)
data = """index date hour
0 2018-03-24 23
1 2018-03-24 24
2 2018-03-25 1
3 2018-03-25 2
4 2018-03-25 3
5 2018-03-25 4
6 2018-03-25 5
7 2018-03-25 6
8 2018-03-25 7
9 2018-03-25 8
10 2018-03-25 9
11 2018-03-25 10
12 2018-03-25 11
13 2018-03-25 12
14 2018-03-25 13
15 2018-03-25 14
16 2018-03-25 15
17 2018-03-25 16
18 2018-03-25 17
19 2018-03-25 18
20 2018-03-25 19
21 2018-03-25 20
22 2018-03-25 21
23 2018-03-25 22
24 2018-03-25 23
25 2018-03-26 1
26 2018-03-26 2
27 2018-03-26 3
28 2018-03-26 4
29 2018-03-26 5
30 2018-03-26 6
31 2018-10-27 23
32 2018-10-27 24
33 2018-10-28 1
34 2018-10-28 2
35 2018-10-28 3
36 2018-10-28 4
37 2018-10-28 5
38 2018-10-28 6
39 2018-10-28 7
40 2018-10-28 8
41 2018-10-28 9
42 2018-10-28 10
43 2018-10-28 11
44 2018-10-28 12
45 2018-10-28 13
46 2018-10-28 14
47 2018-10-28 15
48 2018-10-28 16
49 2018-10-28 17
50 2018-10-28 18
51 2018-10-28 19
52 2018-10-28 20
53 2018-10-28 21
54 2018-10-28 22
55 2018-10-28 23
56 2018-10-28 24
57 2018-10-28 25
58 2018-10-29 1
59 2018-10-29 2"""
df = pd.read_csv(StringIO(data), sep='\s+', index_col=0)
df['hour'] = pd.to_timedelta(df['hour'] - 1, 'h')
df['date'] = pd.to_datetime(df['date'])
df['naive_datetime'] = df['date'] + df['hour']
df.set_index(df['naive_datetime'], inplace=True)
df.index = df.index.tz_localize('Europe/London').tz_convert('UTC')
print(df)
产生
pytz.exceptions.NonExistentTimeError: 2018-03-25 01:00:00
因此,必须处理不存在的日期时间。有许多选项可以执行此操作,其中一种是忽略每年两次跳转时间的本地DST时区中不存在的日期时间。
# receives non-existent time exception because of naive datetime that does not exist in Europe/London
#df.index = df.index.tz_localize('Europe/London').tz_convert('UTC')
# receives AmbiguousTimeError: Cannot infer dst time from 2018-10-28 01:00:00 as there are no repeated times
#df.index = df.index.tz_localize('Europe/London', ambiguous='infer').tz_convert('UTC')
df.index = df.index.tz_localize('Europe/London', ambiguous='NaT', nonexistent='NaT').tz_convert('UTC')
df.index.name = "datetime Europe/London"
# if there is timestamped data in the dataframe, something has to be done with it.
# The data for the missing time is probably best dropped
#df = df[df.index.notnull()]
# interpolate doesn't work: https://github.com/pandas-dev/pandas/issues/11701, but then again the time does not exist in local tz...
#df['datetime Europe/London interpolated'] = df.index.to_series().interpolate(method='linear')
答案 1 :(得分:0)
我最终写了一个函数calc_hour_offset
,该函数映射到date
列上,以产生int
偏移量,然后将其用于调整time
列中的值匹配UTC时区。解决方案适用于我所有的极端情况
import pandas as pd
from pandas.compat import StringIO
from pytz import timezone
def calc_hour_offset(date, to_timezone='UTC'):
tz = timezone('Europe/London')
dst_switch_start, dst_switch_end = [
tzdt.date()
for tzdt
in tz._utc_transition_times
if tzdt.year == date.year]
dst_switch_date_range = pd.date_range(dst_switch_start,
dst_switch_end,
freq='h',
tz=to_timezone)
if date.date() not in dst_switch_date_range:
return -1
elif date.date() == dst_switch_start:
return -1
elif date.date() == dst_switch_end:
return -2
elif date.date() in dst_switch_date_range:
return -2
else:
raise
str_df = r"""date time target_dt_utc
0 2018-03-24 23 2018-03-24 22:00:00+00:00
1 2018-03-24 24 2018-03-24 23:00:00+00:00
2 2018-03-25 1 2018-03-25 00:00:00+00:00
3 2018-03-25 2 2018-03-25 01:00:00+00:00
4 2018-03-25 3 2018-03-25 02:00:00+00:00
5 2018-03-25 4 2018-03-25 03:00:00+00:00
6 2018-03-25 5 2018-03-25 04:00:00+00:00
7 2018-03-25 6 2018-03-25 05:00:00+00:00
8 2018-03-25 7 2018-03-25 06:00:00+00:00
9 2018-03-25 8 2018-03-25 07:00:00+00:00
10 2018-03-25 9 2018-03-25 08:00:00+00:00
11 2018-03-25 10 2018-03-25 09:00:00+00:00
12 2018-03-25 11 2018-03-25 10:00:00+00:00
13 2018-03-25 12 2018-03-25 11:00:00+00:00
14 2018-03-25 13 2018-03-25 12:00:00+00:00
15 2018-03-25 14 2018-03-25 13:00:00+00:00
16 2018-03-25 15 2018-03-25 14:00:00+00:00
17 2018-03-25 16 2018-03-25 15:00:00+00:00
18 2018-03-25 17 2018-03-25 16:00:00+00:00
19 2018-03-25 18 2018-03-25 17:00:00+00:00
20 2018-03-25 19 2018-03-25 18:00:00+00:00
21 2018-03-25 20 2018-03-25 19:00:00+00:00
22 2018-03-25 21 2018-03-25 20:00:00+00:00
23 2018-03-25 22 2018-03-25 21:00:00+00:00
24 2018-03-25 23 2018-03-25 22:00:00+00:00
25 2018-03-26 1 2018-03-25 23:00:00+00:00
26 2018-03-26 2 2018-03-26 00:00:00+00:00
27 2018-03-26 3 2018-03-26 01:00:00+00:00
28 2018-03-26 4 2018-03-26 02:00:00+00:00
29 2018-03-26 5 2018-03-26 03:00:00+00:00
30 2018-03-26 6 2018-03-26 04:00:00+00:00
31 2018-10-27 23 2018-10-27 21:00:00+00:00
32 2018-10-27 24 2018-10-27 22:00:00+00:00
33 2018-10-28 1 2018-10-27 23:00:00+00:00
34 2018-10-28 2 2018-10-28 00:00:00+00:00
35 2018-10-28 3 2018-10-28 01:00:00+00:00
36 2018-10-28 4 2018-10-28 02:00:00+00:00
37 2018-10-28 5 2018-10-28 03:00:00+00:00
38 2018-10-28 6 2018-10-28 04:00:00+00:00
39 2018-10-28 7 2018-10-28 05:00:00+00:00
40 2018-10-28 8 2018-10-28 06:00:00+00:00
41 2018-10-28 9 2018-10-28 07:00:00+00:00
42 2018-10-28 10 2018-10-28 08:00:00+00:00
43 2018-10-28 11 2018-10-28 09:00:00+00:00
44 2018-10-28 12 2018-10-28 10:00:00+00:00
45 2018-10-28 13 2018-10-28 11:00:00+00:00
46 2018-10-28 14 2018-10-28 12:00:00+00:00
47 2018-10-28 15 2018-10-28 13:00:00+00:00
48 2018-10-28 16 2018-10-28 14:00:00+00:00
49 2018-10-28 17 2018-10-28 15:00:00+00:00
50 2018-10-28 18 2018-10-28 16:00:00+00:00
51 2018-10-28 19 2018-10-28 17:00:00+00:00
52 2018-10-28 20 2018-10-28 18:00:00+00:00
53 2018-10-28 21 2018-10-28 19:00:00+00:00
54 2018-10-28 22 2018-10-28 20:00:00+00:00
55 2018-10-28 23 2018-10-28 21:00:00+00:00
56 2018-10-28 24 2018-10-28 22:00:00+00:00
57 2018-10-28 25 2018-10-28 23:00:00+00:00
58 2018-10-29 1 2018-10-29 00:00:00+00:00
59 2018-10-29 2 2018-10-29 01:00:00+00:00"""
df = pd.read_csv(StringIO(str_df), sep='\s{2,}', index_col=0)
df['target_dt_utc'] = pd.to_datetime(df['target_dt_utc'])
df['date'] = pd.to_datetime(df['date'])
df['time_utc'] = df['date'].map(calc_hour_offset) + df['time']
df['dt_utc_calculated'] = (pd.to_datetime(df['date']) + pd.to_timedelta(df['time_utc'], 'h')).dt.tz_localize('UTC')
df['is dt_utc_calculated equal to target_dt_utc'] = df['target_dt_utc'] == df['dt_utc_calculated']
print(df)
退出:
date time target_dt_utc time_utc dt_utc_calculated is dt_utc_calculated equal to target_dt_utc
0 2018-03-24 23 2018-03-24 22:00:00+00:00 22 2018-03-24 22:00:00+00:00 True
1 2018-03-24 24 2018-03-24 23:00:00+00:00 23 2018-03-24 23:00:00+00:00 True
2 2018-03-25 1 2018-03-25 00:00:00+00:00 0 2018-03-25 00:00:00+00:00 True
3 2018-03-25 2 2018-03-25 01:00:00+00:00 1 2018-03-25 01:00:00+00:00 True
4 2018-03-25 3 2018-03-25 02:00:00+00:00 2 2018-03-25 02:00:00+00:00 True
5 2018-03-25 4 2018-03-25 03:00:00+00:00 3 2018-03-25 03:00:00+00:00 True
6 2018-03-25 5 2018-03-25 04:00:00+00:00 4 2018-03-25 04:00:00+00:00 True
7 2018-03-25 6 2018-03-25 05:00:00+00:00 5 2018-03-25 05:00:00+00:00 True
8 2018-03-25 7 2018-03-25 06:00:00+00:00 6 2018-03-25 06:00:00+00:00 True
9 2018-03-25 8 2018-03-25 07:00:00+00:00 7 2018-03-25 07:00:00+00:00 True
10 2018-03-25 9 2018-03-25 08:00:00+00:00 8 2018-03-25 08:00:00+00:00 True
11 2018-03-25 10 2018-03-25 09:00:00+00:00 9 2018-03-25 09:00:00+00:00 True
12 2018-03-25 11 2018-03-25 10:00:00+00:00 10 2018-03-25 10:00:00+00:00 True
13 2018-03-25 12 2018-03-25 11:00:00+00:00 11 2018-03-25 11:00:00+00:00 True
14 2018-03-25 13 2018-03-25 12:00:00+00:00 12 2018-03-25 12:00:00+00:00 True
15 2018-03-25 14 2018-03-25 13:00:00+00:00 13 2018-03-25 13:00:00+00:00 True
16 2018-03-25 15 2018-03-25 14:00:00+00:00 14 2018-03-25 14:00:00+00:00 True
17 2018-03-25 16 2018-03-25 15:00:00+00:00 15 2018-03-25 15:00:00+00:00 True
18 2018-03-25 17 2018-03-25 16:00:00+00:00 16 2018-03-25 16:00:00+00:00 True
19 2018-03-25 18 2018-03-25 17:00:00+00:00 17 2018-03-25 17:00:00+00:00 True
20 2018-03-25 19 2018-03-25 18:00:00+00:00 18 2018-03-25 18:00:00+00:00 True
21 2018-03-25 20 2018-03-25 19:00:00+00:00 19 2018-03-25 19:00:00+00:00 True
22 2018-03-25 21 2018-03-25 20:00:00+00:00 20 2018-03-25 20:00:00+00:00 True
23 2018-03-25 22 2018-03-25 21:00:00+00:00 21 2018-03-25 21:00:00+00:00 True
24 2018-03-25 23 2018-03-25 22:00:00+00:00 22 2018-03-25 22:00:00+00:00 True
25 2018-03-26 1 2018-03-25 23:00:00+00:00 -1 2018-03-25 23:00:00+00:00 True
26 2018-03-26 2 2018-03-26 00:00:00+00:00 0 2018-03-26 00:00:00+00:00 True
27 2018-03-26 3 2018-03-26 01:00:00+00:00 1 2018-03-26 01:00:00+00:00 True
28 2018-03-26 4 2018-03-26 02:00:00+00:00 2 2018-03-26 02:00:00+00:00 True
29 2018-03-26 5 2018-03-26 03:00:00+00:00 3 2018-03-26 03:00:00+00:00 True
30 2018-03-26 6 2018-03-26 04:00:00+00:00 4 2018-03-26 04:00:00+00:00 True
31 2018-10-27 23 2018-10-27 21:00:00+00:00 21 2018-10-27 21:00:00+00:00 True
32 2018-10-27 24 2018-10-27 22:00:00+00:00 22 2018-10-27 22:00:00+00:00 True
33 2018-10-28 1 2018-10-27 23:00:00+00:00 -1 2018-10-27 23:00:00+00:00 True
34 2018-10-28 2 2018-10-28 00:00:00+00:00 0 2018-10-28 00:00:00+00:00 True
35 2018-10-28 3 2018-10-28 01:00:00+00:00 1 2018-10-28 01:00:00+00:00 True
36 2018-10-28 4 2018-10-28 02:00:00+00:00 2 2018-10-28 02:00:00+00:00 True
37 2018-10-28 5 2018-10-28 03:00:00+00:00 3 2018-10-28 03:00:00+00:00 True
38 2018-10-28 6 2018-10-28 04:00:00+00:00 4 2018-10-28 04:00:00+00:00 True
39 2018-10-28 7 2018-10-28 05:00:00+00:00 5 2018-10-28 05:00:00+00:00 True
40 2018-10-28 8 2018-10-28 06:00:00+00:00 6 2018-10-28 06:00:00+00:00 True
41 2018-10-28 9 2018-10-28 07:00:00+00:00 7 2018-10-28 07:00:00+00:00 True
42 2018-10-28 10 2018-10-28 08:00:00+00:00 8 2018-10-28 08:00:00+00:00 True
43 2018-10-28 11 2018-10-28 09:00:00+00:00 9 2018-10-28 09:00:00+00:00 True
44 2018-10-28 12 2018-10-28 10:00:00+00:00 10 2018-10-28 10:00:00+00:00 True
45 2018-10-28 13 2018-10-28 11:00:00+00:00 11 2018-10-28 11:00:00+00:00 True
46 2018-10-28 14 2018-10-28 12:00:00+00:00 12 2018-10-28 12:00:00+00:00 True
47 2018-10-28 15 2018-10-28 13:00:00+00:00 13 2018-10-28 13:00:00+00:00 True
48 2018-10-28 16 2018-10-28 14:00:00+00:00 14 2018-10-28 14:00:00+00:00 True
49 2018-10-28 17 2018-10-28 15:00:00+00:00 15 2018-10-28 15:00:00+00:00 True
50 2018-10-28 18 2018-10-28 16:00:00+00:00 16 2018-10-28 16:00:00+00:00 True
51 2018-10-28 19 2018-10-28 17:00:00+00:00 17 2018-10-28 17:00:00+00:00 True
52 2018-10-28 20 2018-10-28 18:00:00+00:00 18 2018-10-28 18:00:00+00:00 True
53 2018-10-28 21 2018-10-28 19:00:00+00:00 19 2018-10-28 19:00:00+00:00 True
54 2018-10-28 22 2018-10-28 20:00:00+00:00 20 2018-10-28 20:00:00+00:00 True
55 2018-10-28 23 2018-10-28 21:00:00+00:00 21 2018-10-28 21:00:00+00:00 True
56 2018-10-28 24 2018-10-28 22:00:00+00:00 22 2018-10-28 22:00:00+00:00 True
57 2018-10-28 25 2018-10-28 23:00:00+00:00 23 2018-10-28 23:00:00+00:00 True
58 2018-10-29 1 2018-10-29 00:00:00+00:00 0 2018-10-29 00:00:00+00:00 True
59 2018-10-29 2 2018-10-29 01:00:00+00:00 1 2018-10-29 01:00:00+00:00 True