背景
在很多CMIP6的模式数据中,时间储存都是采用的cftime的格式,而python对这种格式的时间支持并不是很友好。因此在后需的处理中需要转换cftime为datetime
核心代码
这一段代码本意就是从cftime中逐个提取年月日,时分秒信息,然后再使用datetime函数重新组装。并且这个代码输入的cftime_obj
必须是单个的不能是list
。
import cftime
from datetime import datetime
def convert_cftime_to_datetime(cftime_obj):
year = cftime_obj.year
month = cftime_obj.month
day = cftime_obj.day
hour = getattr(cftime_obj, 'hour', 0)
minute = getattr(cftime_obj, 'minute', 0)
second = getattr(cftime_obj, 'second', 0)
return datetime(year=year, month=month, day=day,
hour=hour, minute=minute, second=second)
完整示例
本次测试使用的CMIP6文件为:sfo3_AERhr_CESM2-WACCM_ssp126_r1i1p1f1_gn_201501010000-202412312300.nc
大家可以自行在CMIP6官网下载
大家下载好的文件可以直接放到同一个文件夹下,例如:F:\CMIP6
(文件路径按需自行修改)代码中的变量名称:sfo3
、lat
等请根据实际的变量名称修改!!!
随后只需要运行本程序即可
import os
import pandas as pd
import numpy as np
import xarray as xr
import cftime
import warnings
warnings.filterwarnings("ignore")
from datetime import datetime
def convert_cftime_to_datetime(cftime_obj):
year = cftime_obj.year
month = cftime_obj.month
day = cftime_obj.day
hour = getattr(cftime_obj, 'hour', 0)
minute = getattr(cftime_obj, 'minute', 0)
second = getattr(cftime_obj, 'second', 0)
return datetime(year=year, month=month, day=day,
hour=hour, minute=minute, second=second)
path = r'F:\CMIP6/'
FileList = os.listdir(r'F:\CMIP6/')
for i in range(len(FileList)):
print("正在处理:{}".format(FileList[i]))
ds = xr.open_dataset(r'F:\CMIP6/'+FileList[i])
sfo3 = ds['sfo3'].values
# 判断日期格式
if isinstance(ds['time'].values[0], cftime.datetime):
# 如果是cftime格式那么遍历每一个时间节点并转为datetime格式
time = []
for j in range(len(ds['time'].values)):
time_tmp = convert_cftime_to_datetime(ds['time'].values[j])
time.append(time_tmp)
time = pd.to_datetime(time)
else:
#如果不是cftime格式,那么直接使用pandas的to_datetime函数
time = ds['time'].values
time = pd.to_datetime(time) # 直接转换为pandas datetime
try:
lat = ds['lat'].values
lon = ds['lon'].values
except:
lat = ds['latitude'].values
lon = ds['longitude'].values
ds.close()
ds_new = xr.Dataset(data_vars={'sfo3': (('time', 'lat', 'lon'), sfo3)},
coords={'time': time, 'lat': lat, 'lon': lon})
ds_new['sfo3'].attrs['units'] = 'ug/m3'
ds_new['lat'].attrs['units'] = 'degrees_north'
ds_new['lon'].attrs['units'] = 'degrees_east'
ds_new.to_netcdf(r'F:\CMIP6_DELED/' + FileList[i]) # 设置输出文件路径