From 09ffb6f1283ca1b6d2db8d3eafe9e1acd623b468 Mon Sep 17 00:00:00 2001 From: m7pr Date: Wed, 9 Aug 2023 12:00:54 +0200 Subject: [PATCH 01/20] add dates and times restore on slice_restore --- R/teal_slice-store.R | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index 5bc570dd2..ed84948f3 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -52,6 +52,23 @@ slices_restore <- function(file) { tss_json <- jsonlite::fromJSON(file, simplifyDataFrame = FALSE) + tss_json$slices <- + lapply(tss_json$slices, function(slice) { + if(!is.null(slice$selected)) { + slice$selected <- + if(all(grepl('[0-9]{4}-[0-9]{2}-[0-9]{2}', slice$selected))) { + if(all(grepl('[0-9]{1,2}:[0-9]{2}:[0-9]{2}', slice$selected))) { + as.POSIXct(slice$selected) + } else { + as.Date(slice$selected) + } + } else { + slice$selected + } + } + slice + }) + tss_elements <- lapply(tss_json$slices, as.teal_slice) do.call(teal_slices, c(tss_elements, tss_json$attributes)) From d09db50df2e4265e413827bcf2c12b95fea1545d Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 10:05:55 +0000 Subject: [PATCH 02/20] [skip actions] Restyle files --- R/teal_slice-store.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index ed84948f3..74d6388f7 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -54,10 +54,10 @@ slices_restore <- function(file) { tss_json$slices <- lapply(tss_json$slices, function(slice) { - if(!is.null(slice$selected)) { + if (!is.null(slice$selected)) { slice$selected <- - if(all(grepl('[0-9]{4}-[0-9]{2}-[0-9]{2}', slice$selected))) { - if(all(grepl('[0-9]{1,2}:[0-9]{2}:[0-9]{2}', slice$selected))) { + if (all(grepl("[0-9]{4}-[0-9]{2}-[0-9]{2}", slice$selected))) { + if (all(grepl("[0-9]{1,2}:[0-9]{2}:[0-9]{2}", slice$selected))) { as.POSIXct(slice$selected) } else { as.Date(slice$selected) From 52df52f3d5665a9ef7f38b2399dc41126aa75895 Mon Sep 17 00:00:00 2001 From: m7pr Date: Wed, 9 Aug 2023 12:55:10 +0200 Subject: [PATCH 03/20] unify storage timezones to UTC --- R/teal_slice-store.R | 4 ++-- R/teal_slice.R | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index ed84948f3..80dbd2cc5 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -57,8 +57,8 @@ slices_restore <- function(file) { if(!is.null(slice$selected)) { slice$selected <- if(all(grepl('[0-9]{4}-[0-9]{2}-[0-9]{2}', slice$selected))) { - if(all(grepl('[0-9]{1,2}:[0-9]{2}:[0-9]{2}', slice$selected))) { - as.POSIXct(slice$selected) + if(all(grepl('[0-9]{2}:[0-9]{2}:[0-9]{2}', slice$selected))) { + as.POSIXct(slice$selected, tz = 'UTC') } else { as.Date(slice$selected) } diff --git a/R/teal_slice.R b/R/teal_slice.R index 938c04e6f..73c9dab5a 100644 --- a/R/teal_slice.R +++ b/R/teal_slice.R @@ -276,7 +276,7 @@ to_json <- function(x) { } } - jsonlite::toJSON(no_unbox(x), pretty = TRUE, auto_unbox = TRUE, digits = 16, null = "null") + jsonlite::toJSON(no_unbox(x), pretty = TRUE, auto_unbox = TRUE, digits = 16, null = "null", UTC = TRUE) } #' Justify Colons in `JSON` String From c915a3df581703fbfde4135743ee8942a39911ea Mon Sep 17 00:00:00 2001 From: m7pr Date: Wed, 9 Aug 2023 12:56:22 +0200 Subject: [PATCH 04/20] space --- R/teal_slice-store.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index e6305f806..2a64e409e 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -56,8 +56,8 @@ slices_restore <- function(file) { lapply(tss_json$slices, function(slice) { if (!is.null(slice$selected)) { slice$selected <- - if(all(grepl('[0-9]{4}-[0-9]{2}-[0-9]{2}', slice$selected))) { - if(all(grepl('[0-9]{2}:[0-9]{2}:[0-9]{2}', slice$selected))) { + if (all(grepl('[0-9]{4}-[0-9]{2}-[0-9]{2}', slice$selected))) { + if (all(grepl('[0-9]{2}:[0-9]{2}:[0-9]{2}', slice$selected))) { as.POSIXct(slice$selected, tz = 'UTC') } else { as.Date(slice$selected) From 7c2873e6a81b955a76bbc51e1b24057f74e43fd6 Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 4 Sep 2023 15:18:54 +0200 Subject: [PATCH 05/20] #373 convert dates/posixt to ISO standard --- R/teal_slice-store.R | 4 +++- R/teal_slice.R | 2 +- man/slices_store.Rd | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index 2a64e409e..e319f0d46 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -9,6 +9,8 @@ #' @param file (`character(1)`) The file path where `teal_slices` object will be saved. #' The file extension should be `".json"`. #' +#' @details `Date` and `POSIXt` classes are stored in `"ISO8601"` format and are converted to `UTC` timezone. +#' #' @return `NULL`, invisibly. #' #' @examples @@ -57,7 +59,7 @@ slices_restore <- function(file) { if (!is.null(slice$selected)) { slice$selected <- if (all(grepl('[0-9]{4}-[0-9]{2}-[0-9]{2}', slice$selected))) { - if (all(grepl('[0-9]{2}:[0-9]{2}:[0-9]{2}', slice$selected))) { + if (all(grepl('T[0-9]{2}:[0-9]{2}:[0-9]{2}', slice$selected))) { as.POSIXct(slice$selected, tz = 'UTC') } else { as.Date(slice$selected) diff --git a/R/teal_slice.R b/R/teal_slice.R index 73c9dab5a..81946454a 100644 --- a/R/teal_slice.R +++ b/R/teal_slice.R @@ -276,7 +276,7 @@ to_json <- function(x) { } } - jsonlite::toJSON(no_unbox(x), pretty = TRUE, auto_unbox = TRUE, digits = 16, null = "null", UTC = TRUE) + jsonlite::toJSON(no_unbox(x), pretty = TRUE, auto_unbox = TRUE, digits = 16, null = "null", UTC = TRUE, POSIXt = "ISO8601") } #' Justify Colons in `JSON` String diff --git a/man/slices_store.Rd b/man/slices_store.Rd index 1d16c1ccb..0703d9cb0 100644 --- a/man/slices_store.Rd +++ b/man/slices_store.Rd @@ -21,6 +21,9 @@ The \code{teal_slices} object contains information about filter states and can b create, modify, and delete filter states. The saved file can be later loaded using the \code{slices_restore} function. } +\details{ +\code{Date} and \code{POSIXt} classes are stored in \code{"ISO8601"} format and are converted to \code{UTC} timezone. +} \examples{ # Create a teal_slices object tss <- teal_slices( From d4c18774acbaf2afa548d707f860081fe5769e2b Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 4 Sep 2023 15:43:57 +0200 Subject: [PATCH 06/20] #373 remove time startpoint and endpoint at the restore --- R/teal_slice-store.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index e319f0d46..bc7523aa2 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -53,14 +53,13 @@ slices_restore <- function(file) { checkmate::assert_file_exists(file, access = "r", extension = "json") tss_json <- jsonlite::fromJSON(file, simplifyDataFrame = FALSE) - tss_json$slices <- lapply(tss_json$slices, function(slice) { if (!is.null(slice$selected)) { slice$selected <- if (all(grepl('[0-9]{4}-[0-9]{2}-[0-9]{2}', slice$selected))) { if (all(grepl('T[0-9]{2}:[0-9]{2}:[0-9]{2}', slice$selected))) { - as.POSIXct(slice$selected, tz = 'UTC') + as.POSIXct(gsub('T|Z', ' ', slice$selected), tz = 'UTC') } else { as.Date(slice$selected) } From 9bf3e70afd3e71e6874be16c5d4463d68a233325 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:42:17 +0200 Subject: [PATCH 07/20] Update R/teal_slice-store.R MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com> Signed-off-by: Marcin <133694481+m7pr@users.noreply.github.com> --- R/teal_slice-store.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index bc7523aa2..4ca59d34d 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -57,9 +57,9 @@ slices_restore <- function(file) { lapply(tss_json$slices, function(slice) { if (!is.null(slice$selected)) { slice$selected <- - if (all(grepl('[0-9]{4}-[0-9]{2}-[0-9]{2}', slice$selected))) { - if (all(grepl('T[0-9]{2}:[0-9]{2}:[0-9]{2}', slice$selected))) { - as.POSIXct(gsub('T|Z', ' ', slice$selected), tz = 'UTC') + if (all(grepl("[0-9]{4}-[0-9]{2}-[0-9]{2}", slice$selected))) { + if (all(grepl("T[0-9]{2}:[0-9]{2}:[0-9]{2}", slice$selected))) { + as.POSIXct(gsub("T|Z", " ", slice$selected), tz = "UTC") } else { as.Date(slice$selected) } From d88262c1a5bf7124b4178d004295ae78e860f9b1 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Wed, 13 Sep 2023 14:02:49 +0200 Subject: [PATCH 08/20] 373 adds tests to slices_restore (#465) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Veríssimo <211358+averissimo@users.noreply.github.com> --- tests/testthat/test-teal_slice-store.R | 111 +++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 tests/testthat/test-teal_slice-store.R diff --git a/tests/testthat/test-teal_slice-store.R b/tests/testthat/test-teal_slice-store.R new file mode 100644 index 000000000..1b59a00ca --- /dev/null +++ b/tests/testthat/test-teal_slice-store.R @@ -0,0 +1,111 @@ +test_that("teal_slice store/restore supports saving `POSIXct` timestamps in selected", { + slices_path <- withr::local_file("slices.json") + + time_stamps <- Sys.time() + c(-10 * 60 * 60 * 24, -30, 0) + + # ISO8601 does not keep milliseconds + time_stamps <- as.POSIXct( + ceiling(as.double(time_stamps)), + tz = "UTC" + ) + + tss <- teal_slices( + teal_slice( + dataname = "ADSL", + varname = "EOSDTM", + selected = time_stamps, + fixed = TRUE + ) + ) + + # Store the teal_slices object to a file + slices_store(tss, slices_path) + tss_restored <- slices_restore(slices_path) + + tss_restored_list <- shiny::isolate(shiny::reactiveValuesToList(tss_restored[[1]])) + expect_s3_class(tss_restored_list$selected, "POSIXct") + + expect_identical_slice(tss[[1]], tss_restored[[1]]) +}) + +test_that("teal_slice store/restore supports saving `Date` dates in selected", { + slices_path <- withr::local_file("slices.json") + + time_stamps <- Sys.Date() + c(-10 * 600, -30, 0) + + tss <- teal_slices( + teal_slice( + dataname = "ADSL", + varname = "EOSDT", + selected = time_stamps, + fixed = TRUE + ) + ) + + # Store the teal_slices object to a file + slices_store(tss, slices_path) + tss_restored <- slices_restore(slices_path) + + tss_restored_list <- shiny::isolate(shiny::reactiveValuesToList(tss_restored[[1]])) + expect_s3_class(tss_restored_list$selected, "Date") + + expect_identical_slice(tss[[1]], tss_restored[[1]]) +}) + +test_that("teal_slice store/restore supports saving `POSIXct` timestamps in choices", { + skip("Storing `POSIXct` on choices not yet supported") + slices_path <- withr::local_file("slices.json") + + time_stamps <- Sys.time() + c(-10 * 60 * 60 * 24, -30, 0) + + # ISO8601 does not keep milliseconds + time_stamps <- as.POSIXct( + ceiling(as.double(time_stamps)), + tz = "UTC" + ) + + tss <- teal_slices( + teal_slice( + dataname = "ADSL", + varname = "EOSDTM", + selected = sample(time_stamps, 2), + choices = time_stamps, + fixed = TRUE + ) + ) + + # Store the teal_slices object to a file + slices_store(tss, slices_path) + tss_restored <- slices_restore(slices_path) + + tss_restored_list <- shiny::isolate(shiny::reactiveValuesToList(tss_restored[[1]])) + expect_s3_class(tss_restored_list$choices, "POSIXct") + + expect_identical_slice(tss[[1]], tss_restored[[1]]) +}) + +test_that("teal_slice store/restore supports saving `Date` timestamps in choices", { + skip("Storing `Date` on choices not yet supported") + slices_path <- withr::local_file("slices.json") + + time_stamps <- Sys.Date() + c(-10 * 600, -30, 0) + + tss <- teal_slices( + teal_slice( + dataname = "ADSL", + varname = "EOSDT", + selected = sample(time_stamps, 2), + choices = time_stamps, + fixed = TRUE + ) + ) + + # Store the teal_slices object to a file + slices_store(tss, slices_path) + tss_restored <- slices_restore(slices_path) + + tss_restored_list <- shiny::isolate(shiny::reactiveValuesToList(tss_restored[[1]])) + expect_s3_class(tss_restored_list$choices, "Date") + + expect_identical_slice(tss[[1]], tss_restored[[1]]) +}) From d7aebc9cac60ac4979719ef40888fdbd0d2d4b13 Mon Sep 17 00:00:00 2001 From: m7pr Date: Wed, 13 Sep 2023 14:25:41 +0200 Subject: [PATCH 09/20] #373 extend dates/times class in restore for choices and selected --- R/teal_slice-store.R | 20 +++++++++++--------- tests/testthat/test-teal_slice-store.R | 2 -- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index 4ca59d34d..c16169699 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -55,17 +55,19 @@ slices_restore <- function(file) { tss_json <- jsonlite::fromJSON(file, simplifyDataFrame = FALSE) tss_json$slices <- lapply(tss_json$slices, function(slice) { - if (!is.null(slice$selected)) { - slice$selected <- - if (all(grepl("[0-9]{4}-[0-9]{2}-[0-9]{2}", slice$selected))) { - if (all(grepl("T[0-9]{2}:[0-9]{2}:[0-9]{2}", slice$selected))) { - as.POSIXct(gsub("T|Z", " ", slice$selected), tz = "UTC") + for (field in c("selected", "choices")) { + if (!is.null(slice[[field]])) { + slice[[field]] <- + if (all(grepl("[0-9]{4}-[0-9]{2}-[0-9]{2}", slice[[field]]))) { + if (all(grepl("T[0-9]{2}:[0-9]{2}:[0-9]{2}", slice[[field]]))) { + as.POSIXct(gsub("T|Z", " ", slice[[field]]), tz = "UTC") + } else { + as.Date(slice[[field]]) + } } else { - as.Date(slice$selected) + slice[[field]] } - } else { - slice$selected - } + } } slice }) diff --git a/tests/testthat/test-teal_slice-store.R b/tests/testthat/test-teal_slice-store.R index 1b59a00ca..2fa637ef3 100644 --- a/tests/testthat/test-teal_slice-store.R +++ b/tests/testthat/test-teal_slice-store.R @@ -53,7 +53,6 @@ test_that("teal_slice store/restore supports saving `Date` dates in selected", { }) test_that("teal_slice store/restore supports saving `POSIXct` timestamps in choices", { - skip("Storing `POSIXct` on choices not yet supported") slices_path <- withr::local_file("slices.json") time_stamps <- Sys.time() + c(-10 * 60 * 60 * 24, -30, 0) @@ -85,7 +84,6 @@ test_that("teal_slice store/restore supports saving `POSIXct` timestamps in choi }) test_that("teal_slice store/restore supports saving `Date` timestamps in choices", { - skip("Storing `Date` on choices not yet supported") slices_path <- withr::local_file("slices.json") time_stamps <- Sys.Date() + c(-10 * 600, -30, 0) From 98e6b5645dd159bda314dd3470e2ee520981c558 Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 25 Sep 2023 12:12:23 +0200 Subject: [PATCH 10/20] ensure dates mixed in a character are not returned as Dates --- R/teal_slice-store.R | 16 +++++++++------- man/slices_store.Rd | 3 ++- tests/testthat/test-teal_slice-store.R | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index c16169699..746f95f53 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -9,7 +9,8 @@ #' @param file (`character(1)`) The file path where `teal_slices` object will be saved. #' The file extension should be `".json"`. #' -#' @details `Date` and `POSIXt` classes are stored in `"ISO8601"` format and are converted to `UTC` timezone. +#' @details `Date` and `POSIX*t` classes are stored in `"ISO8601"` format and are converted to `UTC` timezone +#' (`YYYY-MM-DD` for `Date` and `YYYY-MM-DDT{N}{N}:{N}{N}:{N}{N}Z` for `POSIX*t`, where `{N} = [0-9]` is a number). #' #' @return `NULL`, invisibly. #' @@ -57,13 +58,14 @@ slices_restore <- function(file) { lapply(tss_json$slices, function(slice) { for (field in c("selected", "choices")) { if (!is.null(slice[[field]])) { + date_partial_regex <- "^[0-9]{4}-[0-9]{2}-[0-9]{2}" + time_stamp_regex <- paste0(date_partial_regex, "T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$") + slice[[field]] <- - if (all(grepl("[0-9]{4}-[0-9]{2}-[0-9]{2}", slice[[field]]))) { - if (all(grepl("T[0-9]{2}:[0-9]{2}:[0-9]{2}", slice[[field]]))) { - as.POSIXct(gsub("T|Z", " ", slice[[field]]), tz = "UTC") - } else { - as.Date(slice[[field]]) - } + if (all(grepl(paste0(date_partial_regex, "$"), slice[[field]]))) { + as.Date(slice[[field]]) + } else if (all(grepl(time_stamp_regex, slice[[field]]))) { + as.POSIXct(gsub("T|Z", " ", slice[[field]]), tz = "UTC") } else { slice[[field]] } diff --git a/man/slices_store.Rd b/man/slices_store.Rd index 0703d9cb0..09e588fd7 100644 --- a/man/slices_store.Rd +++ b/man/slices_store.Rd @@ -22,7 +22,8 @@ create, modify, and delete filter states. The saved file can be later loaded usi the \code{slices_restore} function. } \details{ -\code{Date} and \code{POSIXt} classes are stored in \code{"ISO8601"} format and are converted to \code{UTC} timezone. +\code{Date} and \code{POSIX*t} classes are stored in \code{"ISO8601"} format and are converted to \code{UTC} timezone +(\code{YYYY-MM-DD} for \code{Date} and \verb{YYYY-MM-DDT\{N\}\{N\}:\{N\}\{N\}:\{N\}\{N\}Z} for \code{POSIX*t}, where \verb{\{N\} = [0-9]} is a number). } \examples{ # Create a teal_slices object diff --git a/tests/testthat/test-teal_slice-store.R b/tests/testthat/test-teal_slice-store.R index 2fa637ef3..93d125b72 100644 --- a/tests/testthat/test-teal_slice-store.R +++ b/tests/testthat/test-teal_slice-store.R @@ -107,3 +107,24 @@ test_that("teal_slice store/restore supports saving `Date` timestamps in choices expect_identical_slice(tss[[1]], tss_restored[[1]]) }) + + +test_that("teal_slice store/restore restores mixed `Date`-characters as characters in selected", { + slices_path <- withr::local_file("slices.json") + tss <- teal_slices( + teal_slice( + dataname = "ADSL", + varname = "EOSDTM", + selected = c( + "beta 2023-09-11", + "release candidate 2023-09-21", + "release 2023-09-21" + ), + fixed = TRUE + ) + ) + + slices_store(tss, slices_path) + tss_restored <- slices_restore(slices_path) + expect_identical_slice(tss[[1]], tss_restored[[1]]) +}) From fc855c36f7bc5122c90edc5a4e860b9f3732c047 Mon Sep 17 00:00:00 2001 From: m7pr Date: Mon, 25 Sep 2023 12:18:26 +0200 Subject: [PATCH 11/20] superlintr fixes --- R/teal_slice.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/teal_slice.R b/R/teal_slice.R index 81946454a..baf0b92dd 100644 --- a/R/teal_slice.R +++ b/R/teal_slice.R @@ -276,7 +276,10 @@ to_json <- function(x) { } } - jsonlite::toJSON(no_unbox(x), pretty = TRUE, auto_unbox = TRUE, digits = 16, null = "null", UTC = TRUE, POSIXt = "ISO8601") + jsonlite::toJSON( + no_unbox(x), + pretty = TRUE, auto_unbox = TRUE, digits = 16, null = "null", UTC = TRUE, POSIXt = "ISO8601" + ) } #' Justify Colons in `JSON` String From c288b7c50fa91ba2b2b48755a9ff7850f06329db Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Fri, 29 Sep 2023 11:40:41 +0200 Subject: [PATCH 12/20] #467 change factors to characters for selected and choices at teal_slice creation (#469) Alternative for #468 that closes #467 as a consequence of #373 We changed the behavior of `teal_slice` that converts `factors` to `characters` for the unified result of `store/restore`. ```r > slices_path <- withr::local_file("slices.json") > tss <- teal_slices( + teal_slice( + dataname = "ADSL", + varname = "EOSDTM", + choices = factor(c("a", "b", "c")), + selected = factor(c("a", "b")) + ) + ) > > slices_store(tss, slices_path) > tss_restored <- slices_restore(slices_path) > > class(shiny::isolate(tss_restored[[1]]$selected)) [1] "character" > class(shiny::isolate(tss_restored[[1]]$choices)) [1] "character" > class(shiny::isolate(tss[[1]]$selected)) [1] "character" > class(shiny::isolate(tss[[1]]$choices)) [1] "character" ``` --- R/teal_slice.R | 6 +++-- man/teal_slice.Rd | 4 +-- tests/testthat/test-teal_slice-store.R | 37 +++++++++++++++++++------- tests/testthat/test-teal_slice.R | 18 +++++++++++++ 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/R/teal_slice.R b/R/teal_slice.R index baf0b92dd..2663d4419 100644 --- a/R/teal_slice.R +++ b/R/teal_slice.R @@ -58,9 +58,9 @@ #' requires `dataname` prefix, *e.g.* `data$var == "x"`. #' @param choices (optional `vector`) specifying allowed choices; #' When specified it should be a subset of values in variable denoted by `varname`; -#' Type and size depends on variable type. +#' Type and size depends on variable type. Factors are coerced to character. #' @param selected (optional `vector`) of selected values from `choices`; -#' Type and size depends on variable type. +#' Type and size depends on variable type. Factors are coerced to character. #' @param multiple (optional `logical(1)`) flag specifying whether more than one value can be selected; #' only applicable to `ChoicesFilterState` and `LogicalFilterState` #' @param keep_na (optional `logical(1)`) flag specifying whether to keep missing values @@ -155,6 +155,8 @@ teal_slice <- function(dataname, ) formal_args <- formal_args[ts_var_args] args <- c(formal_args, list(...)) + args[c("choices", "selected")] <- + lapply(args[c("choices", "selected")], function(x) if (is.factor(x)) as.character(x) else x) if (missing(id)) { args$id <- get_default_slice_id(args) } else { diff --git a/man/teal_slice.Rd b/man/teal_slice.Rd index bab8f4c9d..5624377d5 100644 --- a/man/teal_slice.Rd +++ b/man/teal_slice.Rd @@ -50,10 +50,10 @@ requires \code{dataname} prefix, \emph{e.g.} \code{data$var == "x"}.} \item{choices}{(optional \code{vector}) specifying allowed choices; When specified it should be a subset of values in variable denoted by \code{varname}; -Type and size depends on variable type.} +Type and size depends on variable type. Factors are coerced to character.} \item{selected}{(optional \code{vector}) of selected values from \code{choices}; -Type and size depends on variable type.} +Type and size depends on variable type. Factors are coerced to character.} \item{keep_na}{(optional \code{logical(1)}) flag specifying whether to keep missing values} diff --git a/tests/testthat/test-teal_slice-store.R b/tests/testthat/test-teal_slice-store.R index 93d125b72..1f5c1df73 100644 --- a/tests/testthat/test-teal_slice-store.R +++ b/tests/testthat/test-teal_slice-store.R @@ -1,4 +1,4 @@ -test_that("teal_slice store/restore supports saving `POSIXct` timestamps in selected", { +testthat::test_that("teal_slice store/restore supports saving `POSIXct` timestamps in selected", { slices_path <- withr::local_file("slices.json") time_stamps <- Sys.time() + c(-10 * 60 * 60 * 24, -30, 0) @@ -23,12 +23,12 @@ test_that("teal_slice store/restore supports saving `POSIXct` timestamps in sele tss_restored <- slices_restore(slices_path) tss_restored_list <- shiny::isolate(shiny::reactiveValuesToList(tss_restored[[1]])) - expect_s3_class(tss_restored_list$selected, "POSIXct") + testthat::expect_s3_class(tss_restored_list$selected, "POSIXct") expect_identical_slice(tss[[1]], tss_restored[[1]]) }) -test_that("teal_slice store/restore supports saving `Date` dates in selected", { +testthat::test_that("teal_slice store/restore supports saving `Date` dates in selected", { slices_path <- withr::local_file("slices.json") time_stamps <- Sys.Date() + c(-10 * 600, -30, 0) @@ -47,12 +47,12 @@ test_that("teal_slice store/restore supports saving `Date` dates in selected", { tss_restored <- slices_restore(slices_path) tss_restored_list <- shiny::isolate(shiny::reactiveValuesToList(tss_restored[[1]])) - expect_s3_class(tss_restored_list$selected, "Date") + testthat::expect_s3_class(tss_restored_list$selected, "Date") expect_identical_slice(tss[[1]], tss_restored[[1]]) }) -test_that("teal_slice store/restore supports saving `POSIXct` timestamps in choices", { +testthat::test_that("teal_slice store/restore supports saving `POSIXct` timestamps in choices", { slices_path <- withr::local_file("slices.json") time_stamps <- Sys.time() + c(-10 * 60 * 60 * 24, -30, 0) @@ -78,12 +78,12 @@ test_that("teal_slice store/restore supports saving `POSIXct` timestamps in choi tss_restored <- slices_restore(slices_path) tss_restored_list <- shiny::isolate(shiny::reactiveValuesToList(tss_restored[[1]])) - expect_s3_class(tss_restored_list$choices, "POSIXct") + testthat::expect_s3_class(tss_restored_list$choices, "POSIXct") expect_identical_slice(tss[[1]], tss_restored[[1]]) }) -test_that("teal_slice store/restore supports saving `Date` timestamps in choices", { +testthat::test_that("teal_slice store/restore supports saving `Date` timestamps in choices", { slices_path <- withr::local_file("slices.json") time_stamps <- Sys.Date() + c(-10 * 600, -30, 0) @@ -103,13 +103,13 @@ test_that("teal_slice store/restore supports saving `Date` timestamps in choices tss_restored <- slices_restore(slices_path) tss_restored_list <- shiny::isolate(shiny::reactiveValuesToList(tss_restored[[1]])) - expect_s3_class(tss_restored_list$choices, "Date") + testthat::expect_s3_class(tss_restored_list$choices, "Date") expect_identical_slice(tss[[1]], tss_restored[[1]]) }) -test_that("teal_slice store/restore restores mixed `Date`-characters as characters in selected", { +testthat::test_that("teal_slice store/restore restores mixed `Date`-characters as characters in selected", { slices_path <- withr::local_file("slices.json") tss <- teal_slices( teal_slice( @@ -128,3 +128,22 @@ test_that("teal_slice store/restore restores mixed `Date`-characters as characte tss_restored <- slices_restore(slices_path) expect_identical_slice(tss[[1]], tss_restored[[1]]) }) + +testthat::test_that("teal_slice store/restore restores characters as characters in selected and choices", { + slices_path <- withr::local_file("slices.json") + tss <- teal_slices( + teal_slice( + dataname = "ADSL", + varname = "EOSDTM", + choices = c("a", "b", "c"), + selected = c("a", "b") + ) + ) + + slices_store(tss, slices_path) + tss_restored <- slices_restore(slices_path) + + testthat::expect_type(shiny::isolate(tss_restored[[1]]$selected), "character") + testthat::expect_type(shiny::isolate(tss_restored[[1]]$choices), "character") + expect_identical_slice(tss[[1]], tss_restored[[1]]) +}) diff --git a/tests/testthat/test-teal_slice.R b/tests/testthat/test-teal_slice.R index b0996b7b2..5c05b8242 100644 --- a/tests/testthat/test-teal_slice.R +++ b/tests/testthat/test-teal_slice.R @@ -219,3 +219,21 @@ testthat::test_that("teal_slice dataname has to be a string when expr is specifi teal_slice(dataname = character(0), id = "x", title = "x", expr = "x == 'x'"), "length" ) }) + +test_that( + "teal_slice converts factors to characters for 'selected' and 'choices' parameters", + { + slices_path <- withr::local_file("slices.json") + tss <- teal_slices( + teal_slice( + dataname = "ADSL", + varname = "EOSDTM", + choices = factor(c("a", "b", "c")), + selected = factor(c("a", "b")) + ) + ) + + expect_identical(class(shiny::isolate(tss_restored[[1]]$selected)), "character") + expect_identical(class(shiny::isolate(tss_restored[[1]]$choices)), "character") + } +) From b68af399d3c37869beabaed0e8ea7a276cb977f1 Mon Sep 17 00:00:00 2001 From: m7pr Date: Fri, 29 Sep 2023 11:41:48 +0200 Subject: [PATCH 13/20] Empty-Commit From b6db13d9539f5265d45feebea9dd910362b975a9 Mon Sep 17 00:00:00 2001 From: m7pr Date: Fri, 29 Sep 2023 13:19:51 +0200 Subject: [PATCH 14/20] fix testthat:: for teal_slice factor conversion --- tests/testthat/test-teal_slice.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-teal_slice.R b/tests/testthat/test-teal_slice.R index 5c05b8242..579319798 100644 --- a/tests/testthat/test-teal_slice.R +++ b/tests/testthat/test-teal_slice.R @@ -220,7 +220,7 @@ testthat::test_that("teal_slice dataname has to be a string when expr is specifi ) }) -test_that( +testthat::test_that( "teal_slice converts factors to characters for 'selected' and 'choices' parameters", { slices_path <- withr::local_file("slices.json") @@ -233,7 +233,7 @@ test_that( ) ) - expect_identical(class(shiny::isolate(tss_restored[[1]]$selected)), "character") - expect_identical(class(shiny::isolate(tss_restored[[1]]$choices)), "character") + testthat::expect_type(shiny::isolate(tss[[1]]$selected), "character") + testthat::expect_type(shiny::isolate(tss[[1]]$choices), "character") } ) From 2d246e04cd300696cfa62ff80bf4f382a0bae276 Mon Sep 17 00:00:00 2001 From: m7pr Date: Tue, 17 Oct 2023 15:02:06 +0200 Subject: [PATCH 15/20] format appends timezone to POSIX classes, restores assumes timezone is added to a timestamp --- R/teal_slice-store.R | 9 +++++---- R/teal_slice.R | 15 ++++++++++----- man/slices_store.Rd | 5 +++-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index 746f95f53..2b94fbe25 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -9,8 +9,9 @@ #' @param file (`character(1)`) The file path where `teal_slices` object will be saved. #' The file extension should be `".json"`. #' -#' @details `Date` and `POSIX*t` classes are stored in `"ISO8601"` format and are converted to `UTC` timezone -#' (`YYYY-MM-DD` for `Date` and `YYYY-MM-DDT{N}{N}:{N}{N}:{N}{N}Z` for `POSIX*t`, where `{N} = [0-9]` is a number). +#' @details `Date` classes is stored in `"ISO8601"` format (`YYYY-MM-DD`). `POSIX*t` classes are converted to a +#' character with the usage of `format.POSIX*t(usetz = TRUE)` (`YYYY-MM-DD {N}{N}:{N}{N}:{N}{N} TZN`, where +#' `{N} = [0-9]` is a number and `TZN` is the timezone short-code). This format is assumed during `slices_restore`. #' #' @return `NULL`, invisibly. #' @@ -59,13 +60,13 @@ slices_restore <- function(file) { for (field in c("selected", "choices")) { if (!is.null(slice[[field]])) { date_partial_regex <- "^[0-9]{4}-[0-9]{2}-[0-9]{2}" - time_stamp_regex <- paste0(date_partial_regex, "T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$") + time_stamp_regex <- paste0(date_partial_regex, "\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\s[A-Z]{2,4}$") slice[[field]] <- if (all(grepl(paste0(date_partial_regex, "$"), slice[[field]]))) { as.Date(slice[[field]]) } else if (all(grepl(time_stamp_regex, slice[[field]]))) { - as.POSIXct(gsub("T|Z", " ", slice[[field]]), tz = "UTC") + as.POSIXct(substr(slice[[field]], 1, 19), tz = substr(slice[[field]], 21, nchar(slice[[field]]))[1]) } else { slice[[field]] } diff --git a/R/teal_slice.R b/R/teal_slice.R index 2663d4419..e696bb61f 100644 --- a/R/teal_slice.R +++ b/R/teal_slice.R @@ -270,7 +270,7 @@ to_json <- function(x) { vars <- c("selected", "choices") if (is.list(x)) { for (var in vars) { - if (!is.null(x[[var]])) x[[var]] <- I(x[[var]]) + if (!is.null(x[[var]])) x[[var]] <- I(format_time(x[[var]])) } lapply(x, no_unbox) } else { @@ -278,10 +278,15 @@ to_json <- function(x) { } } - jsonlite::toJSON( - no_unbox(x), - pretty = TRUE, auto_unbox = TRUE, digits = 16, null = "null", UTC = TRUE, POSIXt = "ISO8601" - ) + jsonlite::toJSON(no_unbox(x), pretty = TRUE, auto_unbox = TRUE, digits = 16, null = "null") +} + +format_time <- function(x) { + if ("POSIXt" %in% class(x)) { + format(x, usetz = TRUE) + } else { + x + } } #' Justify Colons in `JSON` String diff --git a/man/slices_store.Rd b/man/slices_store.Rd index 09e588fd7..2082977d5 100644 --- a/man/slices_store.Rd +++ b/man/slices_store.Rd @@ -22,8 +22,9 @@ create, modify, and delete filter states. The saved file can be later loaded usi the \code{slices_restore} function. } \details{ -\code{Date} and \code{POSIX*t} classes are stored in \code{"ISO8601"} format and are converted to \code{UTC} timezone -(\code{YYYY-MM-DD} for \code{Date} and \verb{YYYY-MM-DDT\{N\}\{N\}:\{N\}\{N\}:\{N\}\{N\}Z} for \code{POSIX*t}, where \verb{\{N\} = [0-9]} is a number). +\code{Date} classes is stored in \code{"ISO8601"} format (\code{YYYY-MM-DD}). \code{POSIX*t} classes are converted to a +character with the usage of \code{format.POSIX*t(usetz = TRUE)} (\verb{YYYY-MM-DD \{N\}\{N\}:\{N\}\{N\}:\{N\}\{N\} TZN}, where +\verb{\{N\} = [0-9]} is a number and \code{TZN} is the timezone short-code). This format is assumed during \code{slices_restore}. } \examples{ # Create a teal_slices object From cd218bf66ba1e96d45c21d863a5ac547458dff20 Mon Sep 17 00:00:00 2001 From: m7pr Date: Tue, 17 Oct 2023 17:30:11 +0200 Subject: [PATCH 16/20] change POSIXct to POXIXlt in slices_restore for POSIX classes /timestamps --- R/teal_slice-store.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index 2b94fbe25..93a4103d2 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -66,7 +66,8 @@ slices_restore <- function(file) { if (all(grepl(paste0(date_partial_regex, "$"), slice[[field]]))) { as.Date(slice[[field]]) } else if (all(grepl(time_stamp_regex, slice[[field]]))) { - as.POSIXct(substr(slice[[field]], 1, 19), tz = substr(slice[[field]], 21, nchar(slice[[field]]))[1]) + as.POSIXlt(slice[[field]]) + # as.POSIXct(substr(slice[[field]], 1, 19), tz = substr(slice[[field]], 21, nchar(slice[[field]]))[1]) } else { slice[[field]] } From 55781e9346286437e3a408dae7ced84ec1039449 Mon Sep 17 00:00:00 2001 From: m7pr Date: Wed, 18 Oct 2023 11:07:53 +0200 Subject: [PATCH 17/20] try format = "%Y-%m-%d %H:%M:%S %z", usetz = FALSE --- R/teal_slice-store.R | 4 ++-- R/teal_slice.R | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index 93a4103d2..bff76c8f7 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -60,13 +60,13 @@ slices_restore <- function(file) { for (field in c("selected", "choices")) { if (!is.null(slice[[field]])) { date_partial_regex <- "^[0-9]{4}-[0-9]{2}-[0-9]{2}" - time_stamp_regex <- paste0(date_partial_regex, "\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\s[A-Z]{2,4}$") + time_stamp_regex <- paste0(date_partial_regex, "\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\s\\+[0-9]{4}$") slice[[field]] <- if (all(grepl(paste0(date_partial_regex, "$"), slice[[field]]))) { as.Date(slice[[field]]) } else if (all(grepl(time_stamp_regex, slice[[field]]))) { - as.POSIXlt(slice[[field]]) + as.POSIXct(slice[[field]], tryFormats = "%Y-%m-%d %H:%M:%S %z") # as.POSIXct(substr(slice[[field]], 1, 19), tz = substr(slice[[field]], 21, nchar(slice[[field]]))[1]) } else { slice[[field]] diff --git a/R/teal_slice.R b/R/teal_slice.R index e696bb61f..3204ea5f5 100644 --- a/R/teal_slice.R +++ b/R/teal_slice.R @@ -283,7 +283,7 @@ to_json <- function(x) { format_time <- function(x) { if ("POSIXt" %in% class(x)) { - format(x, usetz = TRUE) + format(x, format = "%Y-%m-%d %H:%M:%S %z", usetz = FALSE) } else { x } From df99d7eeb9d4daedd573a1eb7ff7a88b427f4e1b Mon Sep 17 00:00:00 2001 From: m7pr Date: Wed, 18 Oct 2023 16:34:08 +0200 Subject: [PATCH 18/20] convert all POSIX*t in teal_slice(s) to UTC in print and format. use this assumption for store and restore --- R/teal_slice-store.R | 9 +++++---- R/teal_slice.R | 6 +++++- R/teal_slices.R | 4 ++++ man/slices_store.Rd | 6 ++++-- man/teal_slice.Rd | 5 +++++ man/teal_slices.Rd | 5 +++++ 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index bff76c8f7..22e7bfc14 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -10,8 +10,10 @@ #' The file extension should be `".json"`. #' #' @details `Date` classes is stored in `"ISO8601"` format (`YYYY-MM-DD`). `POSIX*t` classes are converted to a -#' character with the usage of `format.POSIX*t(usetz = TRUE)` (`YYYY-MM-DD {N}{N}:{N}{N}:{N}{N} TZN`, where -#' `{N} = [0-9]` is a number and `TZN` is the timezone short-code). This format is assumed during `slices_restore`. +#' character with the usage of `format.POSIX*t(usetz = TRUE, tz = "UTC")` (`YYYY-MM-DD {N}{N}:{N}{N}:{N}{N} UTC`, where +#' `{N} = [0-9]` is a number and `UTC` is `Coordinated Universal Time` timezone short-code). +#' This format is assumed during `slices_restore`. All `teal_slices` containing `teal_slice`s that have `selected` or +#' `choices` fields of `POSIX*t` class are always converted to `UTC` timezone during `print` and `format` as well. #' #' @return `NULL`, invisibly. #' @@ -66,8 +68,7 @@ slices_restore <- function(file) { if (all(grepl(paste0(date_partial_regex, "$"), slice[[field]]))) { as.Date(slice[[field]]) } else if (all(grepl(time_stamp_regex, slice[[field]]))) { - as.POSIXct(slice[[field]], tryFormats = "%Y-%m-%d %H:%M:%S %z") - # as.POSIXct(substr(slice[[field]], 1, 19), tz = substr(slice[[field]], 21, nchar(slice[[field]]))[1]) + as.POSIXct(slice[[field]], tz = "UTC") } else { slice[[field]] } diff --git a/R/teal_slice.R b/R/teal_slice.R index 3204ea5f5..c24fef7f5 100644 --- a/R/teal_slice.R +++ b/R/teal_slice.R @@ -78,6 +78,10 @@ #' @return A `teal.slice` object. Depending on whether `varname` or `expr` was specified, the resulting #' `teal_slice` also receives class `teal_slice_var` or `teal_slice_expr`, respectively. #' +#' @note When `teal_slice` is printed and contains a `POSIX*t` class in `selected` or `choices` fields, then those +#' fields are converted to `UTC` timezone, for enhanced and unified storage and restoring with `slices_store()` and +#' `slices_restore()`. +#' #' @examples #' x1 <- teal_slice( #' dataname = "data", @@ -283,7 +287,7 @@ to_json <- function(x) { format_time <- function(x) { if ("POSIXt" %in% class(x)) { - format(x, format = "%Y-%m-%d %H:%M:%S %z", usetz = FALSE) + format(x, format = "%Y-%m-%d %H:%M:%S", usetz = TRUE, tz = "UTC") } else { x } diff --git a/R/teal_slices.R b/R/teal_slices.R index ec0a7dbb5..9686ff79b 100644 --- a/R/teal_slices.R +++ b/R/teal_slices.R @@ -30,6 +30,10 @@ #' @param i (`character` or `numeric` or `logical`) indicating which elements to extract #' @param recursive (`logical(1)`) flag specifying whether to also convert to list the elements of this `teal_slices` #' +#' @note When `teal_slices` are printed and any of `teal_slice` elements contain a `POSIX*t` class in `selected` or +#' `choices` fields, then those fields are converted to `UTC` timezone, for enhanced and unified storage and restoring +#' with `slices_store()` and `slices_restore()`. +#' #' @return #' `teal_slices`, which is an unnamed list of `teal_slice` objects. #' diff --git a/man/slices_store.Rd b/man/slices_store.Rd index 2082977d5..5722a4cb0 100644 --- a/man/slices_store.Rd +++ b/man/slices_store.Rd @@ -23,8 +23,10 @@ the \code{slices_restore} function. } \details{ \code{Date} classes is stored in \code{"ISO8601"} format (\code{YYYY-MM-DD}). \code{POSIX*t} classes are converted to a -character with the usage of \code{format.POSIX*t(usetz = TRUE)} (\verb{YYYY-MM-DD \{N\}\{N\}:\{N\}\{N\}:\{N\}\{N\} TZN}, where -\verb{\{N\} = [0-9]} is a number and \code{TZN} is the timezone short-code). This format is assumed during \code{slices_restore}. +character with the usage of \code{format.POSIX*t(usetz = TRUE, tz = "UTC")} (\verb{YYYY-MM-DD \{N\}\{N\}:\{N\}\{N\}:\{N\}\{N\} UTC}, where +\verb{\{N\} = [0-9]} is a number and \code{UTC} is \verb{Coordinated Universal Time} timezone short-code). +This format is assumed during \code{slices_restore}. All \code{teal_slices} containing \code{teal_slice}s that have \code{selected} or +\code{choices} fields of \code{POSIX*t} class are always converted to \code{UTC} timezone during \code{print} and \code{format} as well. } \examples{ # Create a teal_slices object diff --git a/man/teal_slice.Rd b/man/teal_slice.Rd index 5624377d5..b94c3ec0d 100644 --- a/man/teal_slice.Rd +++ b/man/teal_slice.Rd @@ -121,6 +121,11 @@ In a \code{FilterState} instantiated with \code{fixed = TRUE} the features Note that a \code{FilterStateExpr} is always considered to have \code{fixed = TRUE}. A \code{FilterState} instantiated with \code{anchored = TRUE} cannot be removed. } +\note{ +When \code{teal_slice} is printed and contains a \code{POSIX*t} class in \code{selected} or \code{choices} fields, then those +fields are converted to \code{UTC} timezone, for enhanced and unified storage and restoring with \code{slices_store()} and +\code{slices_restore()}. +} \section{Filters in \code{SumarizedExperiment} and \code{MultiAssayExperiment} objects}{ diff --git a/man/teal_slices.Rd b/man/teal_slices.Rd index 681db4e65..befc8e2c6 100644 --- a/man/teal_slices.Rd +++ b/man/teal_slices.Rd @@ -83,6 +83,11 @@ The former enumerates allowed variables, the latter enumerates forbidden values. Since these could be mutually exclusive, it is impossible to set both allowed and forbidden variables for one data set in one \code{teal_slices}. } +\note{ +When \code{teal_slices} are printed and any of \code{teal_slice} elements contain a \code{POSIX*t} class in \code{selected} or +\code{choices} fields, then those fields are converted to \code{UTC} timezone, for enhanced and unified storage and restoring +with \code{slices_store()} and \code{slices_restore()}. +} \examples{ filter_1 <- teal_slice( dataname = "dataname1", From d41e446bdb1fa7493e168d0a1d4e76060df42075 Mon Sep 17 00:00:00 2001 From: m7pr Date: Wed, 18 Oct 2023 16:40:45 +0200 Subject: [PATCH 19/20] update final regex assuming timestamp are stored in UTC --- R/teal_slice-store.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/teal_slice-store.R b/R/teal_slice-store.R index 22e7bfc14..39faebc00 100644 --- a/R/teal_slice-store.R +++ b/R/teal_slice-store.R @@ -62,7 +62,7 @@ slices_restore <- function(file) { for (field in c("selected", "choices")) { if (!is.null(slice[[field]])) { date_partial_regex <- "^[0-9]{4}-[0-9]{2}-[0-9]{2}" - time_stamp_regex <- paste0(date_partial_regex, "\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\s\\+[0-9]{4}$") + time_stamp_regex <- paste0(date_partial_regex, "\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\sUTC$") slice[[field]] <- if (all(grepl(paste0(date_partial_regex, "$"), slice[[field]]))) { From 7f0020cb2a219a02b877915805ea716094c5af22 Mon Sep 17 00:00:00 2001 From: m7pr Date: Wed, 18 Oct 2023 20:52:11 +0200 Subject: [PATCH 20/20] append origin to as.POSIXct.numeric tests --- tests/testthat/test-teal_slice-store.R | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-teal_slice-store.R b/tests/testthat/test-teal_slice-store.R index 1f5c1df73..30e251130 100644 --- a/tests/testthat/test-teal_slice-store.R +++ b/tests/testthat/test-teal_slice-store.R @@ -6,7 +6,8 @@ testthat::test_that("teal_slice store/restore supports saving `POSIXct` timestam # ISO8601 does not keep milliseconds time_stamps <- as.POSIXct( ceiling(as.double(time_stamps)), - tz = "UTC" + tz = "UTC", + origin = "1970-01-01" ) tss <- teal_slices( @@ -60,7 +61,8 @@ testthat::test_that("teal_slice store/restore supports saving `POSIXct` timestam # ISO8601 does not keep milliseconds time_stamps <- as.POSIXct( ceiling(as.double(time_stamps)), - tz = "UTC" + tz = "UTC", + origin = "1970-01-01" ) tss <- teal_slices(