SQL Server 的时区从 UTC 到本地日期时间通过 dbplyr

问题描述

我正在尝试将 UTC 日期时间转换为本地时区,并且我尝试了以下代码,但没有得到我想要的结果。希望 today_aest_dttm 列将 2021-06-28 13:57 显示为 dttm 格式。

请帮忙

transmute(
  tz = current_timezone(),today_getdate = getdate(),today_getutcdate = GETUTCDATE(),today_cast_utc_as_aest = sql("cast(GETUTCDATE() as datetime) AT TIME ZONE 'AUS Eastern Standard Time'"),today_convert_utc_as_aest = sql("CONVERT(datetime,GETUTCDATE()) AT TIME ZONE 'UTC' AT TIME ZONE 'AUS Eastern Standard Time'"),today_aest_dttm = as_datetime(today_convert_utc_as_aest)
# Source:   lazy query [?? x 6]
# Database: Microsoft sql Server 12.00.2148[connection details]
  tz                               today_getdate       today_getutcdate    today_cast_utc_as_aest         today_convert_utc_as_aest      today_aest_dttm    
  <chr>                            <dttm>              <dttm>              <chr>                          <chr>                          <dttm>             
1 (UTC) Coordinated Universal Time 2021-06-27 17:57:40 2021-06-27 17:57:40 2021-06-28 03:57:40.693 +10:00 2021-06-28 13:57:40.693 +10:00 2021-06-28 03:57:40
2 (UTC) Coordinated Universal Time 2021-06-27 17:57:40 2021-06-27 17:57:40 2021-06-28 03:57:40.693 +10:00 2021-06-28 13:57:40.693 +10:00 2021-06-28 03:57:40
3 (UTC) Coordinated Universal Time 2021-06-27 17:57:40 2021-06-27 17:57:40 2021-06-28 03:57:40.693 +10:00 2021-06-28 13:57:40.693 +10:00 2021-06-28 03:57:40
4 (UTC) Coordinated Universal Time 2021-06-27 17:57:40 2021-06-27 17:57:40 2021-06-28 03:57:40.693 +10:00 2021-06-28 13:57:40.693 +10:00 2021-06-28 03:57:40
5 (UTC) Coordinated Universal Time 2021-06-27 17:57:40 2021-06-27 17:57:40 2021-06-28 03:57:40.693 +10:00 2021-06-28 13:57:40.693 +10:00 2021-06-28 03:57:40
6 (UTC) Coordinated Universal Time 2021-06-27 17:57:40 2021-06-27 17:57:40 2021-06-28 03:57:40.693 +10:00 2021-06-28 13:57:40.693 +10:00 2021-06-28 03:57:40

解决方法

您可能想直接在 R 中检查 today_aest_dttm 的内容,因为它在内部可能是正确的,只是没有以您期望的时区显示。例如,如果显示的 2021-06-28 03:57:40 代表 "2021-06-28 03:57:40 UTC"(类似于我在下面键入 df_local$today_datetime 时所看到的),那么您实际上已经拥有 2021-06-28 13:57:40.693 +10:00

以下使用 PostgreSQL(我无权访问 SQL Server),但我认为它说明了显示的数据可能是正确的,只是不在您期望的时区中(例如,它对我来说总是正确的,但是UTC 而不是我本地的 EDT)。

library(DBI)
library(dplyr,warn.conflicts = FALSE)

Sys.setenv(TZ="Australia/Sydney")
Sys.timezone()
#> [1] "Australia/Sydney"
pg <- dbConnect(RPostgres::Postgres())

rs <- dbExecute(pg,"SET TIME ZONE 'Australia/Sydney'")

df <- tbl(pg,sql("SELECT 1 AS temp"))

df %>%
  transmute(today_datetime = sql("CURRENT_TIMESTAMP")) %>%
  mutate(today_datetime_chr = as.character(today_datetime))
#> # Source:   lazy query [?? x 2]
#> # Database: postgres [igow@/var/run/postgresql:5434/crsp]
#>   today_datetime      today_datetime_chr           
#>   <dttm>              <chr>                        
#> 1 2021-06-28 16:43:44 2021-06-29 02:43:44.241253+10

rs <- dbExecute(pg,"SET TIME ZONE 'UTC'")

df %>%
  transmute(today_datetime = sql("CURRENT_TIMESTAMP")) %>%
  mutate(today_datetime_chr = as.character(today_datetime))
#> # Source:   lazy query [?? x 2]
#> # Database: postgres [igow@/var/run/postgresql:5434/crsp]
#>   today_datetime      today_datetime_chr          
#>   <dttm>              <chr>                       
#> 1 2021-06-28 16:43:44 2021-06-28 16:43:44.30767+00


rs <- dbExecute(pg,"SET TIME ZONE 'America/New_York'")

df %>%
  transmute(today_datetime = sql("CURRENT_TIMESTAMP")) %>%
  mutate(today_datetime_chr = as.character(today_datetime))
#> # Source:   lazy query [?? x 2]
#> # Database: postgres [igow@/var/run/postgresql:5434/crsp]
#>   today_datetime      today_datetime_chr           
#>   <dttm>              <chr>                        
#> 1 2021-06-28 16:43:44 2021-06-28 12:43:44.403916-04

df_local <-
  df %>%
  transmute(today_datetime = sql("CURRENT_TIMESTAMP")) %>%
  collect()

df_local$today_datetime
#> [1] "2021-06-28 16:43:44 UTC"

# Do it again,but from EDT
Sys.setenv(TZ="America/New_York")
Sys.timezone()
#> [1] "America/New_York"
pg <- dbConnect(RPostgres::Postgres())

rs <- dbExecute(pg,sql("SELECT 1 AS temp"))

df %>%
  transmute(today_datetime = sql("CURRENT_TIMESTAMP")) %>%
  mutate(today_datetime_chr = as.character(today_datetime))
#> # Source:   lazy query [?? x 2]
#> # Database: postgres [igow@/var/run/postgresql:5434/crsp]
#>   today_datetime      today_datetime_chr           
#>   <dttm>              <chr>                        
#> 1 2021-06-28 16:43:44 2021-06-29 02:43:44.487741+10

rs <- dbExecute(pg,"SET TIME ZONE 'UTC'")

df %>%
  transmute(today_datetime = sql("CURRENT_TIMESTAMP")) %>%
  mutate(today_datetime_chr = as.character(today_datetime))
#> # Source:   lazy query [?? x 2]
#> # Database: postgres [igow@/var/run/postgresql:5434/crsp]
#>   today_datetime      today_datetime_chr           
#>   <dttm>              <chr>                        
#> 1 2021-06-28 16:43:44 2021-06-28 16:43:44.518931+00

rs <- dbExecute(pg,"SET TIME ZONE 'America/New_York'")

df %>%
  transmute(today_datetime = sql("CURRENT_TIMESTAMP")) %>%
  mutate(today_datetime_chr = as.character(today_datetime))
#> # Source:   lazy query [?? x 2]
#> # Database: postgres [igow@/var/run/postgresql:5434/crsp]
#>   today_datetime      today_datetime_chr           
#>   <dttm>              <chr>                        
#> 1 2021-06-28 16:43:44 2021-06-28 12:43:44.549623-04

df_local <-
  df %>%
  transmute(today_datetime = sql("CURRENT_TIMESTAMP")) %>%
  collect()

df_local$today_datetime
#> [1] "2021-06-28 16:43:44 UTC"

reprex package (v2.0.0) 于 2021 年 6 月 28 日创建

,

答案在于 dbplyr 的 dbconnect 选项。特别是下面的时区组件。

con <-
dbConnect(
  odbc(),driver = "ODBC Driver 17 for SQL Server",server = "<server details>",database = "<database details>",UID = <user email>,Authentication = "ActiveDirectoryInteractive",timezone = Sys.timezone(),timezone_out = Sys.timezone()
)

运行上述相同代码的结果;

transmute(
  tz = current_timezone(),today_getdate = getdate(),today_getutcdate = GETUTCDATE(),today_convert_utc_as_aest = sql("CONVERT(datetime,GETUTCDATE()) AT TIME ZONE 'UTC' AT TIME ZONE 'AUS Eastern Standard Time'"),today_aest_dttm = as_datetime(today_convert_utc_as_aest))

# Source:   lazy query [?? x 5]
# Database: Microsoft SQL Server 12.00.2148[<connection details>]
  tz                               today_getdate       today_getutcdate    today_convert_utc_as_aest      today_aest_dttm    
  <chr>                            <dttm>              <dttm>              <chr>                          <dttm>             
1 (UTC) Coordinated Universal Time 2021-06-29 23:21:40 2021-06-29 23:21:40 2021-06-30 09:21:40.430 +10:00 2021-06-30 09:21:40
2 (UTC) Coordinated Universal Time 2021-06-29 23:21:40 2021-06-29 23:21:40 2021-06-30 09:21:40.430 +10:00 2021-06-30 09:21:40
3 (UTC) Coordinated Universal Time 2021-06-29 23:21:40 2021-06-29 23:21:40 2021-06-30 09:21:40.430 +10:00 2021-06-30 09:21:40
4 (UTC) Coordinated Universal Time 2021-06-29 23:21:40 2021-06-29 23:21:40 2021-06-30 09:21:40.430 +10:00 2021-06-30 09:21:40
5 (UTC) Coordinated Universal Time 2021-06-29 23:21:40 2021-06-29 23:21:40 2021-06-30 09:21:40.430 +10:00 2021-06-30 09:21:40
6 (UTC) Coordinated Universal Time 2021-06-29 23:21:40 2021-06-29 23:21:40 2021-06-30 09:21:40.430 +10:00 2021-06-30 09:21:40
> Sys.time()
[1] "2021-06-30 09:22:07 AEST"
> Sys.timezone()
[1] "Australia/Sydney"