2013-04-04 5 views
2

Я использую пакет fasttime для его функции fastPOSIXct, которая может эффективно считывать данные о символах. Моя проблема заключается в том, что он может читать только даты персонажа, КОТОРЫЕ ЯВЛЯЮТСЯ В Гринвизе.Как правильно преобразовать часовые пояса

R) fastPOSIXct("2010-03-15 12:37:17.223",tz="GMT") #very fast 
[1] "2010-03-15 12:31:16.223 GMT" 
R) as.POSIXct("2010-03-15 12:37:17.223",tz="GMT") #very slow 
[1] "2010-03-15 12:31:16.223 GMT" 

Теперь у меня есть файл с DateTimes, выраженные в «America/Montral» часовой пояс, план, чтобы загрузить их (неявным, делая вид, что они находятся в GMT) и модифицирование впоследствии атрибут временной зоны без изменения базового значения ,

Если я использую эту функцию, refered в другом посте:

forceTZ = function(x,tz){ 
    return(as.POSIXct(as.numeric(x), origin=as.POSIXct("1970-01-01",tz=tz), tz=tz)) 
} 

Я вижу ошибку ...

R) forceTZ(as.POSIXct("2010-03-15 12:37:17.223",tz="GMT"),"America/Montreal") 
    [1] "2010-03-15 13:37:17.223 EDT" 

... потому что я хотел бы, чтобы это было

R) as.POSIXct("2010-03-15 12:37:17.223",format="%Y-%m-%d %H:%M:%OS",tz="America/Montreal") 
    [1] "2010-03-15 12:37:17.223 EDT" 

Есть ли обходной путь?

EDIT: Я знаю о lubridate::force_tz, но это слишком медленно (не указывать, используя fasttime::fastPOSIXct больше)

+0

Итак, у вас есть вход «character»: «2010-03-15 12: 31: 16.223 GMT», и вы хотите, чтобы объект POSIXct выглядел как? – GSee

+0

Нет, у меня есть символ в файле, который выглядит как '' 2010-03-15 12: 37: 17.223 «Я знаю, что часовой пояс« Америка/Монреаль », но я хочу загрузить его и преобразовать его в' POSIXct 'с' fasttime', этот пакет считает, что строка представляет собой дату-время в «GMT», поэтому я должен сказать R, что результирующий объект POSIXct не является «GMT», а «America/Montreal» – statquant

+0

И что вы хотите получить быть? то, что не так с решением 'as.POSIXct', которое вы показываете выше? – GSee

ответ

8

Умная вещь, чтобы сделать здесь почти наверняка писать читаемый, легкий в обслуживании код, и выбросить больше оборудования на проблему, если ваш код слишком медленно.

Если вы отчаянно нуждаетесь в ускорении кода, вы можете написать настраиваемую функцию настройки часового пояса. Это некрасиво, поэтому, если вам нужно преобразовать многие часовые пояса, вы получите код спагетти. Вот мое решение для конкретного случая конвертации из GMT в Монреальское время.

Сначала предопределите список дат для летнего времени. Вам нужно будет продлить это до 2010 года/после 2013 года, чтобы соответствовать вашему набору данных. Я нашел здесь даты

http://www.timeanddate.com/worldclock/timezone.html?n=165

montreal_tz_data <- cbind(
    start = fastPOSIXct(
    c("2010-03-14 07:00:00", "2011-03-13 07:00:00", "2012-03-11 07:00:00", "2013-03-10 07:00:00") 
), 
    end = fastPOSIXct(
    c("2010-11-07 06:00:00", "2011-11-06 06:00:00", "2012-11-04 06:00:00", "2013-11-03 06:00:00") 
) 
) 

Для скорости, функция для изменения часовых поясов трактует раз как числа.

to_montreal_tz <- function(x) 
{ 
    x <- as.numeric(x) 
    is_dst <- logical(length(x)) #initialise as FALSE 
    #Loop over DST periods in each year 
    for(row in seq_len(nrow(montreal_tz_data))) 
    { 
    is_dst[x > montreal_tz_data[row, 1] & x < montreal_tz_data[row, 2]] <- TRUE 
    } 
    #Hard-coded numbers are 4/5 hours in seconds 
    ans <- ifelse(is_dst, x + 14400, x + 18000) 
    class(ans) <- c("POSIXct", "POSIXt") 
    ans 
} 

Теперь для сравнения раз:

#A million dates 
ch <- rep("2010-03-15 12:37:17.223", 1e6) 
#The easy way (no conversion of time zones afterwards) 
system.time(as.POSIXct(ch, tz="America/Montreal")) 
# user system elapsed 
# 28.96 0.05 29.00 

#A slight performance gain by specifying the format 
system.time(as.POSIXct(ch, format = "%Y-%m-%d %H:%M:%S", tz="America/Montreal")) 
# user system elapsed 
# 13.77 0.01 13.79 

#Using the fast functions 
library(fasttime) 
system.time(to_montreal_tz(fastPOSIXct(ch)))  
# user system elapsed 
# 0.51 0.02 0.53 

Как и все трюки оптимизации, вы либо получили 27-кратное ускорение (яй!) или вы сохранили время обработки в 13 секунд, но добавили 3 дня времени обслуживания кода из неясной ошибки, когда у вас заканчивается таблица DST в 2035 году (boo!).

4

Это вопрос декретное: http://www.timeanddate.com/time/dst/2010a.html

В 2010 году она началась 14 марта в Канаде, но не до 28 марта в Великобритании.

Вы можете использовать POSIXlt объекты для изменения часовых поясов непосредственно:

lt <- as.POSIXlt(as.POSIXct("2010-03-15 12:37:17.223",tz="GMT")) 
attr(lt,"tzone") <- "America/Montreal" 
as.POSIXct(lt) 
[1] "2010-03-15 12:37:17 EDT" 

Или вы можете использовать format для преобразования в строку и установить часовой пояс в вызове as.POSIXct. Таким образом, вы можете изменить forceTZ:

forceTZ <- function(x,tz) 
{ 
    return(as.POSIXct(format(x),tz=tz)) 
} 


forceTZ(as.POSIXct("2010-03-15 12:37:17.223",tz="GMT"),"America/Montreal") 
[1] "2010-03-15 12:37:17 EDT" 
+0

@statquant А, попробуйте отредактированное решение, использующее формат. – James

+1

@statquant Похоже, что 'format' отличает' POSIXlt'. Я не думаю, что вы сможете это сделать без какого-либо разбора текста, иначе вам нужно было бы рассчитать и исправить как смещения времени, так и изменения DST, если вы хотите использовать чисто числовое решение, используя только 'POSIXct'. – James

+0

Согласны ли мы с тем, что единственное, что мне нужно изменить, это атрибут 'timezone', но если я получаю доступ к нему в объекте POSIXct, базовое значение изменяется и если я получаю его доступ к объекту POSIXlt, тогда ... Я должен использовать что дорого? – statquant

1

Не могли бы вы просто добавить соответствующее количество секунд, чтобы исправить смещение от GMT?

# Original problem 
fastPOSIXct("2010-03-15 12:37:17.223",tz="America/Montreal") 
# [1] "2010-03-15 08:37:17 EDT" 

# Add 4 hours worth of seconds to the data. This should be very quick. 
fastPOSIXct("2010-03-15 12:37:17.223",tz="America/Montreal") + 14400 
# [1] "2010-03-15 12:37:17 EDT" 
+0

@statquant Нужно ли вам учитывать и летнее время? –

+0

Привет, Саймон, да, я делаю, поэтому это немного сложнее ... – statquant

Смежные вопросы