处理 POSIXct 时区和截断 POSIXct 对象的时间时遇到问题
Trouble dealing with POSIXct timezones and truncating the time out of POSIXct objects
我有以下一段 R 代码:
formatString = "%Y-%m-%d %H:%M:%OS"
x = as.POSIXct(strptime("2013-11-23 23:10:38.000000", formatString))
y = as.POSIXct(strptime("2015-07-17 01:43:38.000000", formatString))
我有一个问题,当我执行 as.Date(y)
然后我得到 2015-07-16
(尽管它的日期晚了一天!)。显然问题是时区。所以我检查了时区:
> x
[1] "2013-11-23 23:10:38 CET"
> y
[1] "2015-07-17 01:43:38 CEST"
>
好的,所以他们的时区有偏差。这很奇怪,因为为什么 R 决定一个时间戳(完全没有任何时区)与另一个时间戳(完全没有任何时区)位于不同的时区?
好的,让我们设置时区。谷歌搜索显示 attr(y, "tzone") <- "CET"
应该做这笔交易。让我们试试这个:
> attr(y, "tzone") <- "CET"
> y
[1] "2015-07-17 01:43:38 CEST"
>
好的,那没有用。让我们看看开始时的时区实际是什么:
> formatString = "%Y-%m-%d %H:%M:%OS"
> x = as.POSIXct(strptime("2013-11-23 23:10:38.000000", formatString))
> y = as.POSIXct(strptime("2015-07-17 01:43:38.000000", formatString))
> unclass(x)
[1] 1385244638
attr(,"tzone")
[1] ""
> unclass(y)
[1] 1437090218
attr(,"tzone")
[1] ""
>
所以...他们根本没有时区,但他们的时区不同????
--> 这是我的自然问题:
1) 当我根本没有指定时区时,为什么它们用不同的时区初始化?
2) 为什么两个对象显然都没有时区,而且在同一时间...为什么它们有不同的时区?
3) 如何使 as.Date(y) == "2015-07-17"
为真? IE。如何将两者都设置为当前时区? Sys.timezone()
结果为 'NA'...(编辑:我的时区 [德国] 似乎是 "CET" --> 我如何将两者都设置为 CET?)
我在这里挠头...感谢您与我分享对此的任何想法:-)
转发
如果您没有指定时区,那么 R 将使用您系统的区域设置,因为 POSIXct 对象必须有一个时区。 CEST 和 CET 的区别在于一个是夏令时,一个不是。这意味着如果您在定义为夏令时的一年中定义一个日期,那么 R 将决定使用时区的夏令时版本。如果您想设置不使用夏令时版本的日期,那么从一开始就将它们定义为 GMT。
formatString = "%Y-%m-%d %H:%M:%OS"
x = as.POSIXct(strptime("2013-11-23 23:10:38.000000", formatString), tz="GMT")
y = as.POSIXct(strptime("2015-07-17 01:43:38.000000", formatString), tz="GMT")
如果您想截断时间,请不要在 POSIXct 对象上使用 as.Date
,因为 as.Date
用于将字符对象转换为 Date 对象(这与POSIXct 对象)。如果你想用基数 R 截断 POSIXct 对象,那么你必须将 round
或 trunc
包装在 as.POSIXct
中,但我建议检查 lubridate
包进行处理带有日期和时间(特别是 POSIXct 对象)。
如果您想保留 CET 但从不使用 CEST,您可以使用不遵守夏令时的位置。根据 http://www.timeanddate.com/time/zones/cet your only options are Algeria and Tunisia. According to https://en.wikipedia.org/wiki/List_of_tz_database_time_zones,有效的 tz 将是 "Africa/Algiers"。因此你可以
formatString = "%Y-%m-%d %H:%M:%OS"
x = as.POSIXct(strptime("2013-11-23 23:10:38.000000", formatString), tz="Africa/Algiers")
y = as.POSIXct(strptime("2015-07-17 01:43:38.000000", formatString), tz="Africa/Algiers")
并且 x 和 y 都将是 CET。
关于设置时区的另一件事。如果您告诉 R 您想要一个通用时区,那么它不会覆盖夏令时设置。这就是设置 attr(y, "tzone") <- "CET"
没有得到预期结果的原因。如果你做了 attr(y, "tzone") <- "Africa/Algiers"
那么它就会像你预期的那样工作。但是请注意转换,因为当您更改时区时,它会更改时间以适应新时区。软件包 lubridate
具有函数 force_tz
,它在初始时区设置错误但时间正确的情况下更改时区而不更改时间。
补充回答:
1) 从一开始就使用正确的时区。由于我住在德国汉堡,对我来说正确的时区是 "Europe/Berlin",请参阅 Dean 所说的 this list。
2)为了从POSIXct中提取信息,例如日期,我使用
as.Date(format(timeStamp, "%Y-%m-%d"))
这很慢,但似乎给出了正确的答案...而且我不必安装新软件包[这在我的情况下有点复杂]。
我 运行 遇到了同样的问题并在这里找到了你的问题。
虽然所有给出的答案都是有效的并且得到了我的赞成票,但我想分享另一个——不太优雅——但有效的解决方案:
当您想从 class 'Date' 转换为 'POSIXct' 或相反时,请在转换前使用 as.character():
x = as.POSIXct("2022-01-01")
y = as.POSIXct("2022-06-01")
x_Date <- as.Date(x)
x_POSIXct_again <- as.POSIXct(x_Date)
identical(x, x_POSIXct_again)
# FALSE!
y_Date <- as.Date(y)
y_POSIXct_again <- as.POSIXct(y_Date)
identical(y, y_POSIXct_again)
# FALSE!
x_Date <- as.Date(as.character(x))
x_POSIXct_again <- as.POSIXct(as.character(x_Date))
identical(x, x_POSIXct_again)
# TRUE!
y_Date <- as.Date(as.character(y))
y_POSIXct_again <- as.POSIXct(as.character(y_Date))
identical(y, y_POSIXct_again)
# TRUE!
# little helpers
as_Date2 <- function(x, ...) {
if("POSIXct" %in% class(x)) x <- as.character(x)
as.Date(x, ...)
}
as_POSIXct2 <- function(x, ...) {
if("Date" %in% class(x)) x <- as.character(x)
as.POSIXct(x, ...)
}
显然 - 从 POSIXct 转换为 DATE 时,时间信息会丢失。但是终于没有了day-switching。
我有以下一段 R 代码:
formatString = "%Y-%m-%d %H:%M:%OS"
x = as.POSIXct(strptime("2013-11-23 23:10:38.000000", formatString))
y = as.POSIXct(strptime("2015-07-17 01:43:38.000000", formatString))
我有一个问题,当我执行 as.Date(y)
然后我得到 2015-07-16
(尽管它的日期晚了一天!)。显然问题是时区。所以我检查了时区:
> x
[1] "2013-11-23 23:10:38 CET"
> y
[1] "2015-07-17 01:43:38 CEST"
>
好的,所以他们的时区有偏差。这很奇怪,因为为什么 R 决定一个时间戳(完全没有任何时区)与另一个时间戳(完全没有任何时区)位于不同的时区?
好的,让我们设置时区。谷歌搜索显示 attr(y, "tzone") <- "CET"
应该做这笔交易。让我们试试这个:
> attr(y, "tzone") <- "CET"
> y
[1] "2015-07-17 01:43:38 CEST"
>
好的,那没有用。让我们看看开始时的时区实际是什么:
> formatString = "%Y-%m-%d %H:%M:%OS"
> x = as.POSIXct(strptime("2013-11-23 23:10:38.000000", formatString))
> y = as.POSIXct(strptime("2015-07-17 01:43:38.000000", formatString))
> unclass(x)
[1] 1385244638
attr(,"tzone")
[1] ""
> unclass(y)
[1] 1437090218
attr(,"tzone")
[1] ""
>
所以...他们根本没有时区,但他们的时区不同????
--> 这是我的自然问题:
1) 当我根本没有指定时区时,为什么它们用不同的时区初始化?
2) 为什么两个对象显然都没有时区,而且在同一时间...为什么它们有不同的时区?
3) 如何使 as.Date(y) == "2015-07-17"
为真? IE。如何将两者都设置为当前时区? Sys.timezone()
结果为 'NA'...(编辑:我的时区 [德国] 似乎是 "CET" --> 我如何将两者都设置为 CET?)
我在这里挠头...感谢您与我分享对此的任何想法:-)
转发
如果您没有指定时区,那么 R 将使用您系统的区域设置,因为 POSIXct 对象必须有一个时区。 CEST 和 CET 的区别在于一个是夏令时,一个不是。这意味着如果您在定义为夏令时的一年中定义一个日期,那么 R 将决定使用时区的夏令时版本。如果您想设置不使用夏令时版本的日期,那么从一开始就将它们定义为 GMT。
formatString = "%Y-%m-%d %H:%M:%OS"
x = as.POSIXct(strptime("2013-11-23 23:10:38.000000", formatString), tz="GMT")
y = as.POSIXct(strptime("2015-07-17 01:43:38.000000", formatString), tz="GMT")
如果您想截断时间,请不要在 POSIXct 对象上使用 as.Date
,因为 as.Date
用于将字符对象转换为 Date 对象(这与POSIXct 对象)。如果你想用基数 R 截断 POSIXct 对象,那么你必须将 round
或 trunc
包装在 as.POSIXct
中,但我建议检查 lubridate
包进行处理带有日期和时间(特别是 POSIXct 对象)。
如果您想保留 CET 但从不使用 CEST,您可以使用不遵守夏令时的位置。根据 http://www.timeanddate.com/time/zones/cet your only options are Algeria and Tunisia. According to https://en.wikipedia.org/wiki/List_of_tz_database_time_zones,有效的 tz 将是 "Africa/Algiers"。因此你可以
formatString = "%Y-%m-%d %H:%M:%OS"
x = as.POSIXct(strptime("2013-11-23 23:10:38.000000", formatString), tz="Africa/Algiers")
y = as.POSIXct(strptime("2015-07-17 01:43:38.000000", formatString), tz="Africa/Algiers")
并且 x 和 y 都将是 CET。
关于设置时区的另一件事。如果您告诉 R 您想要一个通用时区,那么它不会覆盖夏令时设置。这就是设置 attr(y, "tzone") <- "CET"
没有得到预期结果的原因。如果你做了 attr(y, "tzone") <- "Africa/Algiers"
那么它就会像你预期的那样工作。但是请注意转换,因为当您更改时区时,它会更改时间以适应新时区。软件包 lubridate
具有函数 force_tz
,它在初始时区设置错误但时间正确的情况下更改时区而不更改时间。
补充回答:
1) 从一开始就使用正确的时区。由于我住在德国汉堡,对我来说正确的时区是 "Europe/Berlin",请参阅 Dean 所说的 this list。
2)为了从POSIXct中提取信息,例如日期,我使用
as.Date(format(timeStamp, "%Y-%m-%d"))
这很慢,但似乎给出了正确的答案...而且我不必安装新软件包[这在我的情况下有点复杂]。
我 运行 遇到了同样的问题并在这里找到了你的问题。
虽然所有给出的答案都是有效的并且得到了我的赞成票,但我想分享另一个——不太优雅——但有效的解决方案:
当您想从 class 'Date' 转换为 'POSIXct' 或相反时,请在转换前使用 as.character():
x = as.POSIXct("2022-01-01")
y = as.POSIXct("2022-06-01")
x_Date <- as.Date(x)
x_POSIXct_again <- as.POSIXct(x_Date)
identical(x, x_POSIXct_again)
# FALSE!
y_Date <- as.Date(y)
y_POSIXct_again <- as.POSIXct(y_Date)
identical(y, y_POSIXct_again)
# FALSE!
x_Date <- as.Date(as.character(x))
x_POSIXct_again <- as.POSIXct(as.character(x_Date))
identical(x, x_POSIXct_again)
# TRUE!
y_Date <- as.Date(as.character(y))
y_POSIXct_again <- as.POSIXct(as.character(y_Date))
identical(y, y_POSIXct_again)
# TRUE!
# little helpers
as_Date2 <- function(x, ...) {
if("POSIXct" %in% class(x)) x <- as.character(x)
as.Date(x, ...)
}
as_POSIXct2 <- function(x, ...) {
if("Date" %in% class(x)) x <- as.character(x)
as.POSIXct(x, ...)
}
显然 - 从 POSIXct 转换为 DATE 时,时间信息会丢失。但是终于没有了day-switching。