r,write_csv正在将所有时间/日期更改为UTC。

8

我发现一个非常恼人的问题,希望与社区分享。这是一个我已经找到了可接受解决方案的问题(详见下文),但现在我有几个后续问题。我的时间戳和POSIX变量知识有限,特别是plyr、dplyr和readr如何处理它们。

使用POSIX变量(即日期和时间戳)时,我发现readr的write_csv会将这些变量改为UTC时间。

我正在从API下载数据并保留时间戳。每次获取数据时,我将其绑定到现有文件并保存该文件。我的时区是MDT,并且我正在使用MDT时间请求数据,然后尝试将其绑定到UTC时间的文件中,但时间不匹配......这很混乱和令人沮丧。本质上,我试图创建的美丽的时间戳数据库正在变成一堆垃圾。

为解决这个问题,我将POSIX时间列转换为字符列,使用:

df.time <- as.character(df.time)

这使我能够按照API返回给我的时间戳一致的时区保存文件。
这引出了以下一系列问题:
  1. 是否有一个程序可以跨时区连接POSIX变量?例如,如果现在是MDT中午12点,那么在UTC时间为下午6点。我能否基于这些时间戳连接两个数据框而无需先将它们转换为相同的时区?
  2. 是否可能防止write_csv将POSIX变量更改为UTC?
  3. 是否有一个csv写入函数不会更改POSIX变量?
编辑:我已经包含了一些示例数据来说明我的意思。
> df1 <- as.data.frame(fromJSON("https://api.pro.coinbase.com/products/BTC-USD/candles?start=2018-07-23&12:57:00?stop=2018-07-23&19:34:58granularity=300"))
> colnames(df1) <- c("time", "low", "high", "open", "close", "volume")
> df1$time <- anytime(df1$time)
> df1Sort <- df1[order(df1$time),]
> head(df1Sort, 5)
                   time     low    high    open   close    volume
299 2018-07-23 16:13:00 7747.00 7747.01 7747.01 7747.01 9.2029168
298 2018-07-23 16:14:00 7743.17 7747.01 7747.00 7747.01 7.0205668
297 2018-07-23 16:15:00 7745.47 7745.73 7745.67 7745.73 0.9075707
296 2018-07-23 16:16:00 7745.72 7745.73 7745.72 7745.73 4.6715157
295 2018-07-23 16:17:00 7745.72 7745.73 7745.72 7745.72 2.4921921
> write_csv(df1Sort, "df1Sort.csv", col_names = TRUE)
> df2 <- read_csv("df1Sort.csv", col_names = TRUE)
Parsed with column specification:
cols(
  time = col_datetime(format = ""),
  low = col_double(),
  high = col_double(),
  open = col_double(),
  close = col_double(),
  volume = col_double()
)
> head(df2, 5)
# A tibble: 5 x 6
  time                  low  high  open close volume
  <dttm>              <dbl> <dbl> <dbl> <dbl>  <dbl>
1 2018-07-23 22:13:00  7747  7747  7747  7747  9.20 
2 2018-07-23 22:14:00  7743  7747  7747  7747  7.02 
3 2018-07-23 22:15:00  7745  7746  7746  7746  0.908
4 2018-07-23 22:16:00  7746  7746  7746  7746  4.67 
5 2018-07-23 22:17:00  7746  7746  7746  7746  2.49 

1
我认为这里可能有不同的问题;例如,对于x是一个POSIXct对象来说,as.Date(x)默认将tz =“UTC”; 因此,如果您在POSIXct对象上使用as.Date,并且没有明确匹配时区,则时间将转换为UTC。但这与write_csv无关。 - Maurits Evers
Maurits,这几乎就是发生的事情。我在我的代码中没有使用as.Data(),但我注意到我的数据是POSIX类,然后我删除了时区,它仍然被列为POSIX,并且当我保存并重新打开它时,它会返回UTC时间。 我将更新我的帖子。 - Phil_T
1
@MauritsEvers 真的吗?你在我的答案中的可重现示例中得到了不同的结果吗?(假设你不在GMT+3亚的斯亚贝巴时区...)如果它是特定于操作系统的,我也不会感到太惊讶 - 我目前正在使用Windows。 - Gregor Thomas
1
@Gregor 好的,我刚刚检查了一下。我在AEST时区,并且可以重现你的例子:read_csvt存储为UTC时间。我不确定之前我做了什么。我确实进行了检查,但可能做错了什么。对于造成的困惑,非常抱歉! - Maurits Evers
很奇怪,不是吗?我在多个API上都遇到了这个问题,不仅仅是我展示的Coinbase API。 - Phil_T
显示剩余3条评论
2个回答

5
  1. "有没有一个程序可以在不将 POSIX 变量转换为相同时区的情况下跨时区拼接它们?"

    可能吗?但如果是这样,它们几乎肯定是在幕后将其转换为 UTC 并仅向您隐藏。我不知道 R 中是否有任何类似的东西(data.table 是我所知道的唯一可以连接除精确相等之外的任何东西的软件包,但它没有此功能)。如果我是你,我会将所有内容都转换为一个时区 - 大概是 UTC。

    要了解更多最佳实践,请查看这个针对 SQL 的答案似乎非常好。

  2. "是否可以防止 write_csv 将 POSIX 变量更改为 UTC?"

    没有内置选项。 ?write_csv 文档非常清楚:它没有列出任何这方面的选项,并且确实说“POSIXct 格式为 ISO8601。”

  3. "是否有一个 csv 写入函数不更改 POSIX 变量?"

    当然,内置的write.csv不会更改为 UTC(我认为它使用系统设置),data.table::fwrite提供了相当多的选项。如果您想控制保存日期的方式,我认为最好的选择是将它们转换为您想要的任何格式的character,然后任何写入函数都应该可以很好地处理它们。您应该查看 ?data.table::fwrite文档,它有很好的信息。他们警告说"write.csv"选项可能会很慢。


您应该在问题中包含可重现的示例。 下面是这个问题的一个示例:

t = as.POSIXct("2018-01-01 01:30:00", tz = "Africa/Addis_Ababa")
t
# [1] "2018-01-01 01:30:00 EAT"

d = data.frame(t)

library(readr)
write_csv(d, "tz_test.csv")
system("head tz_test.csv")
# 2017-12-31T22:30:00Z

library(data.table)
fwrite(d, "tz_test_dt.csv", dateTimeAs = "write.csv")
system("head tz_test_dt.csv")
# t
# 2018-01-01 01:30:00

write.csv(d, "tz_test_base.csv")
system("head tz_test_base.csv")
# "","t"
# "1",2018-01-01 01:30:00

似乎在字符和 POSIX 之间切换是正确的方法。 - Phil_T
我认为使用协调世界时是最好的选择,但你可以从中得出自己的结论。 - Gregor Thomas

1

看起来你正在使用tidyverse库;你是否看过lubridate库?

使用as_date()函数的帮助文件可能会对你有所帮助,在将日期时间变量附加/连接到数据之前,将其转换为所需的时区。

例如:

> dt_utc <- ymd_hms("2010-08-03 00:50:50")
> dt_utc
[1] "2010-08-03 00:50:50 UTC"

> as_datetime(dt_utc, tz = "Australia/Melbourne")
[1] "2010-08-03 10:50:50 AEST"

感谢您的答案和库推荐。我在切换时区、字符和 Posix 方面没有问题。相反,我希望有一个解决方案来避免进行这些转换。 - Phil_T

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接