使用dbplyr时as.Date指定时区报错,如何让Postgres返回指定时区日期?
在PostgreSQL端通过dbplyr按指定时区转换日期的解决方案
直接用PostgreSQL原生语法实现
dbplyr的as.Date()确实不支持tz参数,因为它对应的PostgreSQL日期转换逻辑没有参数化的时区选项。要在数据库端完成时区转换,直接调用PostgreSQL的AT TIME ZONE语法即可:
# 方法1:直接嵌入SQL片段 my_table %>% mutate(date = sql("CAST(created_at AT TIME ZONE 'Asia/Dhaka' AS DATE)")) %>% head() %>% pull(date) # 方法2:用dbplyr的sql_expr更安全(避免硬编码列名) my_table %>% mutate(date = sql_expr(CAST(!!sym("created_at") AT TIME ZONE 'Asia/Dhaka' AS DATE))) %>% head() %>% pull(date)
为什么原方法报错,collect后却可行
- dbplyr的
as.Date()会被翻译成PostgreSQL的CAST(created_at AS DATE),这个SQL语句没有时区参数,所以R端传入的tz="Asia/Dhaka"在数据库层面没有对应的实现,直接报错“unused argument”。 - 执行
collect()后,数据被拉取到R本地环境,此时调用的是R原生的as.Date()函数,它支持tz参数,所以能正常运行,但这种方式需要加载全量数据,大数据集下性能很差。
关于timezone_out参数的说明
dbConnect()中的timezone_out是控制R端接收datetime类型数据时的显示时区,它不会改变PostgreSQL服务器端的日期转换逻辑——数据库依然会用当前会话的默认时区将timestamp转为date,只是取回R后显示的时区不同,所以无法实现你要的“在数据库端按指定时区生成日期”的需求。
全局会话时区设置(可选)
如果你的所有日期转换都需要用同一个时区,可以在建立连接后设置会话时区,之后as.Date()就能自动用这个时区转换:
# 建立连接后执行 dbExecute(conn, "SET TIME ZONE 'Asia/Dhaka';") # 之后直接用as.Date即可 my_table %>% mutate(date = as.Date(created_at)) %>% head() %>% pull(date)
注意这个设置是会话级的,关闭连接后失效,且会影响当前会话的所有时区相关操作。
内容的提问来源于stack exchange,提问作者dfrankow
相关产品推荐
相关产品推荐

