Я знаю, что это давняя, глубоко укоренившаяся проблема, но с этим я сталкиваюсь так регулярно, и я вижу, как начинающие R
борются так регулярно, что я бы хотел иметь удовлетворительное решение. Мои поиски в Google и SO пока пусты, но, пожалуйста, укажите мне правильное направление, если это повторяется в другом месте.
TL; DR: Есть ли способ использовать что-то вроде POSIXct
класса без часового пояса? Я обычно использую tz="UTC"
независимо от фактического часового пояса набора данных, но это беспорядочный взлом IMO, и мне это не особо нравится. То, что я хочу, это что-то вроде tz=NULL
, которое будет вести себя так же, как UTC, но без фактического добавления «UTC» в качестве атрибута tzone
.
Проблема
Я начну с примера (есть много) типичных проблем с часовым поясом. Создание объекта со значениями POSIXct
:
df <- data.frame( timestamp = as.POSIXct( c( "2018-01-01 03:00:00",
"2018-01-01 12:00:00" ) ),
a = 1:2 )
df
# timestamp a
# 1 2018-01-01 03:00:00 1
# 2 2018-01-01 12:00:00 2
Всё нормально, но потом я пытаюсь преобразовать метки времени в даты:
df$date <- as.Date( df$timestamp )
df
# timestamp a date
# 1 2018-01-01 03:00:00 1 2017-12-31
# 2 2018-01-01 12:00:00 2 2018-01-01
Даты были преобразованы неправильно, потому что языковой стандарт моего компьютера указан по восточному времени Австралии, а это означает, что числовые значения временных меток были смещены на смещение, относящееся к моему языковому стандарту (в данном случае -11 часов). Мы можем убедиться в этом, переведя часовой пояс в UTC, а затем сравнив значения до и после:
df$timestamp[1]
# [1] "2018-01-01 03:00:00 AEDT"
x <- lubridate::force_tz( df$timestamp[1], "UTC" ); x
# [1] "2018-01-01 03:00:00 UTC"
difftime( df$timestamp[1], x )
# Time difference of -11 hours
Это только один пример проблем, вызванных часовыми поясами. Есть и другие, но я не буду вдаваться в них здесь.
Мое хакерское решение
Я не хочу такого поведения, поэтому мне нужно убедить as.POSIXct
не связываться с моими отметками времени. Обычно я делаю это с помощью tz="UTC"
, который работает нормально, за исключением того, что я добавляю информацию, которая не является реальной. Эти времена НЕ в UTC, я просто говорю это, чтобы избежать проблем со смещением времени. Это хак, и каждый раз, когда я передаю свои данные кому-то другому, их можно простить за то, что они думают, что метки времени указаны в UTC, а их нет. Чтобы избежать этого, я обычно добавляю фактический часовой пояс к имени объекта / столбца и надеюсь, что любой, кому я передаю свои данные, поймет, почему кто-то помечает объект с часовым поясом, отличным от часового пояса самого объекта:
df <- data.frame( timestamp.AET = as.POSIXct( c( "2018-01-01 03:00:00",
"2018-01-01 12:00:00" ),
tz = "UTC" ),
a = 1:2 )
df$date <- as.Date( df$timestamp )
df
# timestamp.AET a date
# 1 2018-01-01 03:00:00 1 2018-01-01
# 2 2018-01-01 12:00:00 2 2018-01-01
На что я надеюсь
Что я действительно хочу, так это способ использования POSIXct
без указания часового пояса. Я не хочу, чтобы время было испорчено никоим образом. Делайте все так, как если бы значения были в UTC, и оставляйте пользователю любые данные о часовом поясе, такие как смещения, летнее время и т. Только не притворяйся, что они на самом деле в UTC. Вот мой идеал:
x <- as.POSIXct( "2018-01-01 03:00:00" ); x
# [1] "2018-01-01 03:00:00"
attr( x, "tzone" )
# [1] NULL
shifted <- lubridate::force_tz( x, "UTC" )
shifted == x
# [1] TRUE
as.numeric( shifted ) == as.numeric( x )
# [1] TRUE
as.Date( x )
# [1] "2018-01-01"
Так что на объекте вообще нет атрибута часового пояса. Преобразование даты работает так, как можно было бы ожидать от напечатанного значения. Если есть переходы на летнее время или какие-либо другие специфические для региона проблемы, пользователь (я или кто-то еще) должен решить эту проблему самостоятельно.
Я верю что-то похожее на это возможно в POSIXlt
, но я действительно не хочу переходить к этому. chron
или другой пакет, ориентированный на серию времени, может быть другим решением, но я думаю, что POSIXct
более широко используется и принимается, и это похоже на то, что должно быть возможно в base::
. POSIXct
объект с tz="UTC"
- это именно то, что мне нужно, я просто не хочу лгать о часовых поясах, чтобы заставить его вести себя так, как я хочу (и я полагаю, что большинство новичков ожидают R
) .
Так что же здесь делают другие? Есть ли простой способ использовать POSIXct
без часового пояса, который я пропустил? Есть ли лучший обходной путь, чем tz="UTC"
? Это то, что делают другие?