Невозможно изменить часовой пояс при создании даты из datetime - PullRequest
0 голосов
/ 07 августа 2020

Сегодня я столкнулся с интересной проблемой, когда пытался создать столбец даты из столбца datetime и не мог сохранить правильный часовой пояс. В приведенном ниже примере возникает вопрос, почему не представляется возможным изменить часовой пояс столбца «дата»?

Вот воспроизводимый пример:

library(lubridate)

# create a short datetime sequence
df <- data.frame(datetime = seq(ymd_hm("2020-1-1 0:00"), ymd_hm("2020-1-3 12:00"), by = "hour"))

# check the timezone -- it is UTC
tz(df$datetime)

# convert to PST
df$datetime <- force_tz(df$datetime, "US/Pacific")

# confirm -- OK
tz(df$datetime) # [1] "US/Pacific"

# now create a date column based on the datetime column
df$date <- as.Date(df$datetime)

# might think it would be PST, but it's UTC
tz(df$date)

# attempt to change it manually to PST
df$date <- force_tz(df$date, tz="US/Pacific")

# doesn't work
tz(df$date) # [1] "UTC"

# seems we're stuck -- the date column reflects UTC and changes to January 2nd at 4PM on 1/1
# in the datetime column
df[15:20,]

Технически результат правильно (например, смещение 8 часов), но кажется ужасно запутанным наличие двух разных часовых поясов в двух столбцах.

              datetime       date
15 2020-01-01 14:00:00 2020-01-01
16 2020-01-01 15:00:00 2020-01-01
17 2020-01-01 16:00:00 2020-01-02
18 2020-01-01 17:00:00 2020-01-02
19 2020-01-01 18:00:00 2020-01-02
20 2020-01-01 19:00:00 2020-01-02

Ответы [ 2 ]

0 голосов
/ 07 августа 2020

После еще нескольких экспериментов я не верю, что есть способ сначала преобразовать столбец datetime в PST, а затем создать столбец даты (на основе datetime в PST), который имеет правильный часовой пояс И дает право результаты построчно. Вместо этого, если я сначала создам оба столбца в UT C, а затем конвертирую оба в PST, это, похоже, сработает. Конечно, я все еще озадачен, почему предыдущий подход не работает, если вы посмотрите на окончательный результат (даже если часовой пояс столбца даты кажется правильным).


library(lubridate)

# create a short datetime sequence
df <- data.frame(datetime = seq(ymd_hm("2020-1-1 0:00"), ymd_hm("2020-1-3 12:00"), by = "hour"))

# check the timezone on datetime -- it is UTC
tz(df$datetime)

# now create a date column based on the datetime column in UTC
df$date <- as.Date(df$datetime)

# check date timezone -- also UTC
tz(df$date)

# now manually change both
df$datetime <- force_tz(df$datetime, tz="US/Pacific")
df$date <- force_tz(df$date, tz="US/Pacific")

# check -- both correctly register 'US/Pacific'
tz(df$datetime)
tz(df$date)

# now the two columns seem to match up
df[1:30,]

Вот результаты - обратите внимание, что даты совпадают с датами.

              datetime       date
1  2020-01-01 00:00:00 2020-01-01
2  2020-01-01 01:00:00 2020-01-01
3  2020-01-01 02:00:00 2020-01-01
4  2020-01-01 03:00:00 2020-01-01
5  2020-01-01 04:00:00 2020-01-01
6  2020-01-01 05:00:00 2020-01-01
7  2020-01-01 06:00:00 2020-01-01
8  2020-01-01 07:00:00 2020-01-01
9  2020-01-01 08:00:00 2020-01-01
10 2020-01-01 09:00:00 2020-01-01
11 2020-01-01 10:00:00 2020-01-01
12 2020-01-01 11:00:00 2020-01-01
13 2020-01-01 12:00:00 2020-01-01
14 2020-01-01 13:00:00 2020-01-01
15 2020-01-01 14:00:00 2020-01-01
16 2020-01-01 15:00:00 2020-01-01
17 2020-01-01 16:00:00 2020-01-01
18 2020-01-01 17:00:00 2020-01-01
19 2020-01-01 18:00:00 2020-01-01
20 2020-01-01 19:00:00 2020-01-01
21 2020-01-01 20:00:00 2020-01-01
22 2020-01-01 21:00:00 2020-01-01
23 2020-01-01 22:00:00 2020-01-01
24 2020-01-01 23:00:00 2020-01-01
25 2020-01-02 00:00:00 2020-01-02
26 2020-01-02 01:00:00 2020-01-02
27 2020-01-02 02:00:00 2020-01-02
28 2020-01-02 03:00:00 2020-01-02
29 2020-01-02 04:00:00 2020-01-02
30 2020-01-02 05:00:00 2020-01-02

Вот информация о сеансе:

R version 3.6.2 (2019-12-12)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.6
0 голосов
/ 07 августа 2020

Это мерзко. Я не могу объяснить, почему аргумент tz не работает так, как вы его пробовали. Я бы так поступил. После небольших экспериментов я обнаружил, что замена

df$date <- as.Date(df$datetime)

на

df$date <- with_tz(date(df$datetime), tz="US/Pacific")

дает желаемый результат:

tz(df$date)
[1] "US/Pacific"

[df$date <- with_tz(as.Date(df$datetime), tz="US/Pacific") также работает.]

@ heds1: force_tz у меня не работает, как и для OP. Выбранный результат sessionInfo():

R version 3.6.3 (2020-02-29)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.6
lubridate_1.7.4 

Обновление

Никто не дал достаточно ясных ответов в своих комментариях, чтобы быть уверенным точно какой код выполняется для получения каждого набора результатов. Но я думаю, что у меня может быть источник путаницы: это df$date <- force_tz(df$date, tz="US/Pacific").

Из онлайн do c для force_tz: «force_tz возвращает дату- время, которое имеет то же время, что и время ввода, но в новом часовом поясе ", тогда как то же предложение для with_tz читает" with_tz возвращает дату и время, как это было бы в другом часовой пояс ».

Разница небольшая, но важная: force_tz просто заменяет значение поля часового пояса, оставляя время на часах неизменным, тогда как with_tz отображает время часов на соответствующее время часов в новый часовой пояс в тот же момент.

Немного переработан код OP для ясности:

# create a short datetime sequence
df <- data.frame(utc_datetime = seq(ymd_hm("2020-1-1 0:00"), ymd_hm("2020-1-3 12:00"), by = "hour"))
# check the timezone -- it is UTC
tz(df$utc_datetime)
[1] "UTC"
# convert to PST
df$pst_datetime <- with_tz(df$utc_datetime, tz="US/Pacific")
# confirm -- OK
tz(df$pst_datetime) # [1] "US/Pacific"
[1] "US/Pacific"
# Convert UTC datetime to Date
df$utc_date <- with_tz(date(df$utc_datetime))
tz(df$utc_date)
[1] "UTC"
# Convert PST datetime to Date
df$pst_date <- with_tz(date(df$pst_datetime), tz="US/Pacific")
tz(df$pst_date)
[1] "US/Pacific"
# List to show behaviour around midnight for both UTC and PST
df[22:35,]
          utc_datetime        pst_datetime   utc_date   pst_date
22 2020-01-01 21:00:00 2020-01-01 13:00:00 2020-01-01 2020-01-01
23 2020-01-01 22:00:00 2020-01-01 14:00:00 2020-01-01 2020-01-01
24 2020-01-01 23:00:00 2020-01-01 15:00:00 2020-01-01 2020-01-01
25 2020-01-02 00:00:00 2020-01-01 16:00:00 2020-01-02 2020-01-01
26 2020-01-02 01:00:00 2020-01-01 17:00:00 2020-01-02 2020-01-01
27 2020-01-02 02:00:00 2020-01-01 18:00:00 2020-01-02 2020-01-01
28 2020-01-02 03:00:00 2020-01-01 19:00:00 2020-01-02 2020-01-01
29 2020-01-02 04:00:00 2020-01-01 20:00:00 2020-01-02 2020-01-01
30 2020-01-02 05:00:00 2020-01-01 21:00:00 2020-01-02 2020-01-01
31 2020-01-02 06:00:00 2020-01-01 22:00:00 2020-01-02 2020-01-01
32 2020-01-02 07:00:00 2020-01-01 23:00:00 2020-01-02 2020-01-01
33 2020-01-02 08:00:00 2020-01-02 00:00:00 2020-01-02 2020-01-02
34 2020-01-02 09:00:00 2020-01-02 01:00:00 2020-01-02 2020-01-02
35 2020-01-02 10:00:00 2020-01-02 02:00:00 2020-01-02 2020-01-02
...