You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用data.table与dplyr处理日期时部分结果变为NA?

问题:data.table/dplyr创建日期列时出现NA,base R无此问题

数据背景

数据存储在.txt文件中,格式如下:

"A" "M" "D" "Tmax" "Tmin"
"1" 1931 1 1 35.4 19.7
"2" 1931 1 2 35.8 20.7
"3" 1931 1 3 37.7 23.9
"4" 1931 1 4 39.5 25.8
"5" 1931 1 5 29 22.8
"6" 1931 1 6 27.5 18.6
"7" 1931 1 7 20.4 15.6
"8" 1931 1 8 28.2 15.1
"9" 1931 1 9 31.2 14.6
"10" 1931 1 10 31 18.5

其中:A=年份,M=月份,D=日期。

问题重现

使用data.table处理出现NA

用read.table加载数据后,通过data.table语法创建fecha日期列:

datos_diarios <- data.table(subset(datos_diarios, A >= 1971))
datos_diarios[, fecha := strptime(paste0(A,'-',M,'-',D), format= '%Y-%m-%d', tz = 'America/Argentina/Buenos_Aires')]

结果部分日期解析为NA:

which(is.na(datos_diarios$fecha))
[1]  1119  6545  6863  7234  7598  7962 13513 13807

datos_diarios[1118:1120,]
      A M  D Tmax Tmin      fecha
1: 1974 1 22 25.0 21.9 1974-01-22
2: 1974 1 23 25.4 20.6       <NA>
3: 1974 1 24 29.7 20.5 1974-01-24

dplyr存在同样异常,base R无问题

使用dplyr处理时也会出现相同的NA,但用base R直接赋值则所有日期都能正常解析:

datos_diarios <- subset(datos_diarios, A >= 1971)
datos_diarios$fecha <- strptime(paste0(datos_diarios$A,'-',datos_diarios$M,'-',datos_diarios$D),format= '%Y-%m-%d', tz = 'America/Argentina/Buenos_Aires')

> which(is.na(datos_diarios$fecha))
integer(0)

> datos_diarios[1118:1120,]
         A M  D Tmax Tmin      fecha
15728 1974 1 22 25.0 21.9 1974-01-22
15729 1974 1 23 25.4 20.6 1974-01-23
15730 1974 1 24 29.7 20.5 1974-01-24

问题原因

核心原因是时区America/Argentina/Buenos_Aires的夏令时切换规则:
这些NA对应的日期,是阿根廷当年夏令时开始/结束的过渡日期。以1974年1月23日为例,当时阿根廷的夏令时切换导致该日期的00:00:00时间点不存在(时钟从1月22日23:59直接跳到1月23日01:00)。

  • data.table和dplyr在执行strptime时,严格按照指定时区的规则解析时间字符串,当目标时间点在该时区不存在时,直接返回NA。
  • base R直接赋值时,strptime的解析逻辑存在差异:它会先将字符串解析为无时区的日期,再默认以UTC时区为基准转换到目标时区,或自动跳过时区有效性检查,从而避免了NA的产生。

解决方法

如果只需要日期信息而非精确时间,可以先通过as.Date解析(不涉及时区),再转换为带时区的POSIXct类型:

# data.table写法
datos_diarios[, fecha := as.POSIXct(as.Date(paste0(A,'-',M,'-',D)), tz = 'America/Argentina/Buenos_Aires')]

# base R写法同理
datos_diarios$fecha <- as.POSIXct(as.Date(paste0(datos_diarios$A,'-',datos_diarios$M,'-',datos_diarios$D)), tz = 'America/Argentina/Buenos_Aires')

这种方式会自动将日期映射到该时区的有效时间点,不会产生NA。

内容的提问来源于stack exchange,提问作者ezequiel elias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 12:19:53