【问题标题】:Subtracting 1 Year from Date without Lubridate从没有润滑的日期减去 1 年
【发布时间】:2021-05-16 15:49:14
【问题描述】:

我在数据库中有一个数据框,其中包含我使用 RPostgres 提取的日期维度。每个“日期”的格式为“YYYY-MM-DD”。我想添加比初始日期早一年的新日期列(标记为“lookback_date”)。

需要明确的是,如果观察的“日期”是“2000-01-01”,我想在该观察中添加一个新的“回顾日期”“1999-01-01”。不幸的是,我不知道该怎么做。通常,我会使用 Lubridate,但据我所知,它不适用于 dbplyr。到目前为止,这是我的代码的简化版本。在 mutate 函数之前,我的实际代码中的所有内容都可以正常工作。

# Packages
library(dbplyr)
library(RPostgres)

# Connect to db 
drv <- dbDriver("Postgres")

# Setup connect to db
conn <- dbConnect(drv,
                  dbname = etc,)

# Define table to use in db
table <- tbl(conn, in_schema("xyz", "abc"))

#Select columns and filter
base_data <- table %>%
  #Filter for pertinent data
  filter(date > as.Date("2018-01-01") & date <= as.Date("2020-01-01"))

modified_data <- base_data %>%
mutate(lookback_date = date - 365)

还有其他方法可以创建这个新的日期列吗?

谢谢!

【问题讨论】:

  • 您是否正在寻找一种从日期中减去一年的方法?或者您是否正在寻找一种方法来从 dbplyr 将转换为 SQL 并在服务器端执行的日期中减去一年?后者是我假设您不想使用 lubridate 的原因。
  • @Adam 我想从日期中删除一年。有没有办法用 dbplyr 做到这一点?运行该 mutate 函数后打印“modified_data”会引发错误。当我在本地数据帧上使用该代码时,我没有这个问题。希望我在这里使用了正确的术语。

标签: r date dbplyr rpostgresql


【解决方案1】:

您可以使用字符串将年份减去 1 并将其与日期和月份连接起来。我不确定这是否会转化为 sql!这也将防止闰年扰乱日子。

base_data %>%
  mutate(lookback_date = as.Date(paste0((as.numeric(substr(date,1,4)))-1,substr(date,5,10)),format="%Y-%m-%d"))

【讨论】:

  • 感谢您的回复!当我尝试 glimpse() modified_data 时,我收到以下错误:“as.Date(paste0((as.numeric(substr(service_date, 1, 4))) - 1, 中的错误:未使用的参数 (format = "% Y-%m-%d") "知道为什么会这样吗?感谢您的帮助!
  • 嗯,我没有这个问题。 Rows: 3 Columns: 2 $ date &lt;date&gt; 2020-01-01, 1999-03-21, 1876-02-01 $ lookback_date &lt;date&gt; 2019-01-01, 1998-03-21, 1875-02-01 。但是,您实际上不需要指定格式,因为格式已经在 ISO-8601 中,所以也许只需完全删除格式参数并试一试
【解决方案2】:

你是正确的,lubridate 和 dbplyr 不能很好地一起玩(现在)。因此,我使用 sql 片段进行大部分 dbplyr 日期操作。

基于this answerthis site,从日期中添加/减去时间的postgresql 语法是:

SELECT old_date + INTERVAL '1 day' AS new_date;

基于此,我会尝试以下方法:

output = base_data %>% mutate(lookback_date = date - sql("INTERVAL '1 year'"))

当我使用模拟连接执行此操作时,它会产生正确的语法:

library(dplyr)
library(dbplyr)

df = data.frame(my_num = c(1,2,3), my_dates = as.Date(c('2000-01-01','2000-02-02','2000-03-03')))
df = tbl_lazy(df, con = simulate_postgres())

output = df %>% mutate(new_date = my_dates - sql("INTERVAL '1 year'"))

show_query(output)
# <SQL>
# SELECT `my_num`, `my_dates`, `my_dates` - INTERVAL '1 year' AS `new_date`
# FROM `df`

更新:从评论中,您首先要从日期时间转换为日期。

dbplyr 似乎确实支持将as.Date 转换为 PostgreSQL(as.Date 是基础 R 的一部分,而不是 lubridate 的一部分)。因此,您可以使用以下内容将列转换(转换)为日期:

library(dplyr)
library(dbplyr)

df = data.frame(my_str = c('2000-01-01','2000-02-02','2000-03-03'))
df = tbl_lazy(df, con = simulate_postgres())

output = df %>% mutate(my_date = as.Date(my_str))

show_query(output)
# <SQL>
# SELECT `my_str`, CAST(`my_str` AS DATE) AS `my_date`
# FROM `df`

似乎 PostgreSQL 不允许您添加一年的间隔。一种替代方法是从日期中提取年、月和日,将年加一,然后重新组合。

按照这两个参考(postgre date referencesdate_part fuction)和 this 的回答,您可能想要以下内容:

output = df %>%
  mutate(the_year = DATE_PART('year', my_date),
         the_month = DATE_PART('month', my_date),
         the_day = DATE_PART('day', my_date)) %>%
  mutate(new_date = MAKE_DATE(the_year + 1, the_month, the_day)

【讨论】:

  • 感谢您的回复!当我运行 mutate 代码时,我收到以下错误:“错误:无法获取行:错误:不支持包含月份或年份部分的间隔值”(这可能是 Redshift 问题吗?)。当我将“1 年”更改为“365 天”时,它似乎解决了这个问题,但日期计算似乎不适用于闰年。例如,日期为 2020 年 9 月 8 日的观察收到“2019 年 9 月 9 日”的“新日期”。有什么办法可以解决这个问题吗?感谢您的帮助!@Simon.SA 编辑:新的日期在“dttm”中。如何在没有 lubridate 的情况下使它们成为“日期”?
  • 很高兴您发现它有帮助。我已扩展答案以解决您的评论。您可能仍然会遇到一些错误 - 因为我无法复制您的 R 和 SQL 环境,如果您将其复制并粘贴到您的环境中,则无法确保我的答案有效。但希望这是一个很好的适应起点。
猜你喜欢
  • 2010-12-31
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 2016-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多