Python中将UTC气温数据转换为达卡LST(UTC+6)的实现方法
解决UTC气温数据转达卡时区(UTC+6)的问题
我有39年的3小时气温数据,数组形状为(39,12,31,8),维度依次对应39年、12个月、31天、8个UTC时间点(0000、0300、0600、0900、1200、1500、1800、2100)。需要将这些数据转换为达卡时区(UTC+6,即LST)。
示例输入(第一年1月前5天数据)
array([[15.4, 14.2, 14.7, 16.6, 23.4, 25. , 19.5, 17.7], [ 9.9, 8.2, 8. , 16.8, 22.2, 23.8, 17. , 12.5], [10.4, 9.6, 7.2, 15.4, 20.9, 22. , 15.8, 12. ], [11.5, 10. , 8. , 14.4, 22.1, 23.7, 19. , 12.1], [13.5, 11.8, 9. , 18.1, 24. , 26.2, 19. , 15. ]])
遇到的问题
之前尝试用numpy.roll函数,但UTC的1800、2100点转LST后会变成次日的0000、0300点,日期跨天,单纯滚动数组无法处理这种日期变化。
预期输出
array([[NaN, NaN, 15.4, 14.2, 14.7, 16.6, 23.4, 25. ], [19.5, 17.7, 9.9, 8.2, 8. , 16.8, 22.2, 23.8], [17. , 12.5, 10.4, 9.6, 7.2, 15.4, 20.9, 22.], [15.8, 12., 11.5, 10. , 8. , 14.4, 22.1, 23.7], [19. , 12.1, 13.5, 11.8, 9. , 18.1, 24., 26.2]])
解决方案:用Pandas处理时区转换与日期映射
因为涉及日期跨天,先把数组转换成带时间索引的DataFrame,再做时区转换,最后重新整理成目标形状。
具体代码
import numpy as np import pandas as pd from pandas import DatetimeIndex # 假设原始数据为temp_data,形状(39,12,31,8) # 定义起始年份,可根据实际数据调整 start_year = 1984 years = range(start_year, start_year + 39) utc_hours = [0, 3, 6, 9, 12, 15, 18, 21] # 生成所有UTC时间戳 timestamps = [] for year in years: for month in range(1, 13): # 按数据的31天维度生成日期,实际月份若不足31天可后续调整 for day in range(1, 32): for hour in utc_hours: timestamps.append(f"{year}-{month:02d}-{day:02d} {hour:02d}:00:00") # 转换为UTC时区的时间索引 utc_index = DatetimeIndex(timestamps, tz='UTC') # 转换为达卡时区 dhaka_index = utc_index.tz_convert('Asia/Dhaka') # 将原始数据展平为一维数组 flat_temp = temp_data.flatten() # 创建带达卡时区索引的DataFrame df = pd.DataFrame({'temp': flat_temp}, index=dhaka_index) # 构建达卡时区的完整日期列表 dhaka_dates = [] for year in years: for month in range(1,13): for day in range(1,32): dhaka_dates.append(f"{year}-{month:02d}-{day:02d}") dhaka_dates = DatetimeIndex(dhaka_dates).tz_localize('Asia/Dhaka') # 初始化结果数组,填充NaN target_shape = temp_data.shape result = np.full(target_shape, np.nan) # 遍历每个日期,映射对应时间点的数据 for y_idx in range(target_shape[0]): for m_idx in range(target_shape[1]): for d_idx in range(target_shape[2]): current_date = dhaka_dates[y_idx*12*31 + m_idx*31 + d_idx] # 填充当日8个时间点的数据 for h_idx, hour in enumerate(utc_hours): target_time = current_date + pd.Timedelta(hours=hour) if target_time in df.index: result[y_idx, m_idx, d_idx, h_idx] = df.loc[target_time, 'temp'] # 验证前5天数据 print(result[0,0,0:5,:])
关键说明
- 使用
Asia/Dhaka时区而非直接加6小时,是因为达卡无夏令时变更,用时区名称更规范(直接偏移6小时也可实现) - 自动处理跨天映射:UTC的18:00对应达卡次日00:00,UTC的21:00对应达卡次日03:00,这些数据会被自动分配到下一日的对应时间点
- 初始日期的00:00、03:00时间点无对应UTC数据,自动填充为NaN,符合预期输出
内容的提问来源于stack exchange,提问作者Abeda
相关产品推荐
相关产品推荐

