Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set datetime time zone if TZID propery present #53

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
24 changes: 18 additions & 6 deletions R/ic_dataframe.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ic_dataframe <- function(x) {

if(methods::is(object = x, class2 = "data.frame")) {
return(x)

}

stopifnot(methods::is(object = x, class2 = "character") | methods::is(object = x, class2 = "list"))
Expand All @@ -35,16 +36,27 @@ ic_dataframe <- function(x) {
x_df <- ic_bind_list(x_list_named)

date_cols <- grepl(pattern = "VALUE=DATE", x = names(x_df))
datetime_cols <- names(x_df) %in% grep("^DT[A-Z]+$|CREATED|LAST-MODIFIED", names(x_df), value = TRUE) # include any column starting with DT
tzid_cols <- names(x_df) %in% grep(".*TZID=.*", names(x_df), value = TRUE) # find cols with TZID in name
timezones <- unlist(regmatches(names(x_df), gregexpr("(?<=TZID=).*", names(x_df), perl = TRUE))) # pull all tzones from col names into vector to apply separately to each column
# in case different events have differing tzones although
# think most calendar software only uses single tzone

if(any(date_cols)) {
x_df[date_cols] <- lapply(x_df[, date_cols], ic_date)
x_df[date_cols] <- lapply(x_df[date_cols], ic_date)
}
datetime_cols <- names(x_df) %in% c("DTSTART", "DTEND")

if(any(datetime_cols)) {
x_df[datetime_cols] <- lapply(x_df[, datetime_cols], ic_datetime)
if (any(tzid_cols)) {
x_df[tzid_cols] <- Map(function(x, y) ic_datetime(x, tzone = y), x_df[tzid_cols], timezones) # apply timezones to tzid_cols
x_df[tzid_cols] <- lapply(x_df[tzid_cols], function(x) {attr(x, "tzone") <- ""; x}) # change tzid_cols to local time zone
x_df[datetime_cols & !tzid_cols] <- lapply(x_df[datetime_cols & !tzid_cols], ic_datetime) # set time zone on datetime cols without TZID to local ic_datetime() does this by default
} else {
x_df[datetime_cols] <- lapply(x_df[datetime_cols], ic_datetime)
}
}

# names(x_df) <- gsub(pattern = ".VALUE.DATE", replacement = "", names(x_df))

names(x_df) <- gsub(pattern = ";VALUE=DATE", replacement = "", names(x_df))
names(x_df) <- gsub(pattern = ";TZID.*", replacement = "", names(x_df))
x_df
}

Expand Down
8 changes: 4 additions & 4 deletions R/ic_date.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#' @examples
#' ic_datetime("20180809T160000Z")
#' ic_date("20120103")
ic_datetime <- function(x) {
ic_datetime <- function(x, tzone = "") { # allow pass through of time zone to as.POSIXct

# TODO (LH): regex check x timestamp
if(any(!is.na(x) & !(x == "NA") & !grepl("^\\d{8}T\\d{6}Z?$", x))) {
Expand All @@ -18,13 +18,13 @@ ic_datetime <- function(x) {

plain <- gsub("[TZtz]", "", x)

# if time string has a trailing "Z" assign to zulu timezone
# if time string has a trailing "Z" assign to zulu timezone
if (any(grepl("Z$", x))) {
datetime <- as.POSIXct(plain, tz = "Zulu", format = "%Y%m%d%H%M%S")
attr(datetime, "tzone") <- "" # change tz to "" which defaults to local system timezone; this could be left out if not desired
attr(datetime, "tzone") <- "" # change tz to "" which defaults to local system timezone; this could be left out if not desired
# but as.POSIXct() uses tz = "" as standard argument and this is what is used below if not zulu time
} else {
datetime <- as.POSIXct(plain, format = "%Y%m%d%H%M%S")
datetime <- as.POSIXct(plain, tz = tzone, format = "%Y%m%d%H%M%S")
}
datetime
}
Expand Down
36 changes: 36 additions & 0 deletions inst/extdata/apple_calendar_test.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Apple Inc.//macOS 13.4.1//EN
VERSION:2.0
X-WR-CALNAME:Test
BEGIN:VTIMEZONE
TZID:Europe/London
BEGIN:DAYLIGHT
DTSTART:19810329T010000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
TZNAME:BST
TZOFFSETFROM:+0000
TZOFFSETTO:+0100
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19961027T020000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
TZNAME:GMT
TZOFFSETFROM:+0100
TZOFFSETTO:+0000
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20230320T213321Z
DESCRIPTION:Testing : 00:00\n
DTEND;TZID=Pacific/Auckland:20230630T160000
DTSTAMP:20230709T221931Z
DTSTART;TZID=Pacific/Auckland:20230630T120000
LAST-MODIFIED:20230320T213321Z
LOCATION:London
SEQUENCE:0
SUMMARY:This is test data
TRANSP:OPAQUE
UID:5C15BDCE-C77A-4A67-BBD3-8D5AD233A034
END:VEVENT
END:VCALENDAR
7 changes: 7 additions & 0 deletions tests/testthat/test-ic_datetime.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ test_that("ic_datetime works for 20180809T160000Z:", {
test_that("ic_datetime is NA for empty:", {
expect_output(ic_datetime(""), NA)
})

test_that("DTSTART & DTEND time zones equal local time zone ''", {
f <- system.file("extdata", "apple_calendar_test.ics", package = "calendar") # "Pacific/Auckland" chosen as original time zone as different to testers local time zone
ics_df = ic_read(f)
expect_equal(attributes(ics_df$DTSTART)$tzone, "")
expect_equal(attributes(ics_df$DTEND)$tzone, "")
})
Loading