diff --git a/DESCRIPTION b/DESCRIPTION index e679317..5fde1f5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,9 +2,17 @@ Package: shinyTime Type: Package Title: A Time Input Widget for Shiny Version: 1.0.3.9000 -Authors@R: person("Gerhard", "Burger", email = "burger.ga@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-1062-5576")) +Authors@R: c( + person("Gerhard", "Burger", + email = "burger.ga@gmail.com", + role = c("aut", "cre"), + comment = c(ORCID = "0000-0003-1062-5576")), + person("Nick", "Youngblut", + role = c("aut"), + comment = c(ORCID = "0000-0002-7424-5276")) + ) Description: Provides a time input widget for Shiny. This widget allows intuitive time input in the - '[hh]:[mm]:[ss]' or '[hh]:[mm]' (24H) format by using a separate numeric input for each time + '[hh]:[mm]:[ss]' or '[hh]:[mm]' (24H and 12H) format by using a separate numeric input for each time component. The interface with R uses date-time objects. See the project page for more information and examples. License: GPL-3 | file LICENSE @@ -14,10 +22,11 @@ Imports: URL: https://burgerga.github.io/shinyTime/, https://github.com/burgerga/shinyTime BugReports: https://github.com/burgerga/shinyTime/issues -RoxygenNote: 7.2.1 +RoxygenNote: 7.3.1 Encoding: UTF-8 Language: en-US Suggests: testthat (>= 2.1.0), spelling, - hms + hms, + bslib diff --git a/R/input-time.R b/R/input-time.R index c0311b9..320e6a3 100644 --- a/R/input-time.R +++ b/R/input-time.R @@ -15,6 +15,7 @@ #' @param seconds Show input for seconds. Defaults to TRUE. #' @param minute.steps Round time to multiples of \code{minute.steps} (should be a whole number). #' If not NULL sets \code{seconds} to \code{FALSE}. +#' @param use.civilian Use civilian time (12-hour format) instead of 24-hour format. #' #' @returns Returns a \code{POSIXlt} object, which can be converted to #' a \code{POSIXct} object with \code{as.POSIXct} for more efficient storage. @@ -46,7 +47,10 @@ #' timeInput("time6", "Time:", seconds = FALSE), #' #' # Use multiples of 5 minutes -#' timeInput("time7", "Time:", minute.steps = 5) +#' timeInput("time7", "Time:", minute.steps = 5), +#' +#' # Use civilian (non-military time) +#' timeInput("time8", "Time:", use.civilian = TRUE) #' ) #' #' shinyApp(ui, server = function(input, output) { }) @@ -54,7 +58,8 @@ #' #' @importFrom htmltools tagList singleton tags #' @export -timeInput <- function(inputId, label, value = NULL, seconds = TRUE, minute.steps = NULL) { +timeInput <- function(inputId, label, value = NULL, seconds = TRUE, + minute.steps = NULL, use.civilian = FALSE, width = NULL) { if(is.null(value)) value <- getDefaultTime() if(is.character(value)) value <- strptime(value, format = "%T") if(!is.null(minute.steps)) { @@ -63,21 +68,75 @@ timeInput <- function(inputId, label, value = NULL, seconds = TRUE, minute.steps value <- roundTime(value, minute.steps) } value_list <- dateToTimeList(value) - style <- "width: 8ch" + + div_style <- htmltools::css(width = shiny::validateCssUnit(width)) + el_width <- "65px" + el_style <- htmltools::css(`min-width` = shiny::validateCssUnit(el_width), + flex = "1 1 auto") + input.class <- "form-control" + # Set hour values + if(use.civilian){ + min_hour <- "1" + max_hour <- "12" + value_hour <- as.numeric(value_list$hour) + if(value_hour == 0){ + value_hour <- 12 + } else if(value_hour > 12){ + value_hour <- value_hour - 12 + } + } else { + min_hour <- "0" + max_hour <- "23" + value_hour = as.character(value_list$hour) + } + # Create UI input tagList( singleton(tags$head( tags$script(src = "shinyTime/input_binding_time.js") )), - tags$div(id = inputId, class = "my-shiny-time-input form-group shiny input-container", + tags$div( + id = inputId, + class = "my-shiny-time-input form-group shiny-input-container", + style = div_style, shinyInputLabel(inputId, label, control = TRUE), - tags$div(class = "input-group", - tags$input(type="number", min="0", max="23", step="1", value = value_list$hour, - style = style, class = paste(c(input.class, 'shinytime-hours'), collapse = " ")), - tags$input(type="number", min="0", max="59", step=minute.steps, value = value_list$min, - style = style, class = paste(c(input.class, 'shinytime-mins'), collapse = " ")), - if(seconds) tags$input(type="number", min="0", max="59", step="1", value = value_list$sec, - style = style, class = paste(c(input.class, 'shinytime-secs'), collapse = " ")) else NULL + tags$div( + class = "input-group", + style = htmltools::css(display = "flex", + `flex-direction` = "row", + `flex-wrap` = "nowrap"), + tags$input( + type="number", min = min_hour, max = max_hour, step = "1", + value = value_hour, style = el_style, + class = paste(c(input.class, 'shinytime-hours'), collapse = " ") + ), + tags$input( + type="number", min = "0", max = "59", step = minute.steps, + value = value_list$min, style = el_style, + class = paste(c(input.class, 'shinytime-mins'), collapse = " ") + ), + if(seconds){ + tags$input( + type="number", min = "0", max = "59", step = "1", + value = value_list$sec, style = el_style, + class = paste(c(input.class, 'shinytime-secs'), collapse = " ") + ) + } else NULL, + if(use.civilian){ + tags$select( + tags$option( + value = "AM", "AM", + selected = if(value_list$civilian == "AM") TRUE else NULL + ), + tags$option( + value = "PM", "PM", + selected = if(value_list$civilian == "PM") TRUE else NULL + ), + style = htmltools::css(`min-width` = shiny::validateCssUnit("70px"), + flex = "1 1 auto"), + class = paste(c(input.class, 'shinytime-civilian'), collapse = " ") + ) + } else NULL ) ) ) @@ -113,7 +172,7 @@ timeInput <- function(inputId, label, value = NULL, seconds = TRUE, minute.steps #' @export updateTimeInput <- function(session, inputId, label = NULL, value = NULL) { value <- dateToTimeList(value) - message <- dropNulls(list(label=label, value = value)) + message <- dropNulls(list(label = label, value = value)) session$sendInputMessage(inputId, message) } @@ -127,3 +186,12 @@ updateTimeInput <- function(session, inputId, label = NULL, value = NULL) { shinyTimeExample <- function() { runApp(system.file('example', package='shinyTime', mustWork=T), display.mode='showcase') } + +#' Show the shinyTime debug app +#' +#' App to test the input with a variety of options +#' +#' @importFrom shiny runApp +shinyTimeDebug <- function() { + runApp(system.file('debug', package='shinyTime', mustWork=T), display.mode='normal') +} \ No newline at end of file diff --git a/R/utils.R b/R/utils.R index 5740dfb..d7bc4c9 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,6 +1,11 @@ # Some utility functions # Copied from shiny/R/input-utils.R +#' Create a label tag for a given input +#' @param inputId The input ID +#' @param label The label text +#' @param control Whether the label is for a control (e.g., a checkbox) +#' @return A label tag shinyInputLabel <- function(inputId, label = NULL, control = FALSE) { classes <- c( if (is.null(label)) "shiny-label-null", @@ -15,34 +20,59 @@ shinyInputLabel <- function(inputId, label = NULL, control = FALSE) { # Given a vector or list, drop all the NULL items in it # Copied from shiny/R/utils.R +#' Drop NULL values from vector/lists +#' @param x A vector or list +#' @return A vector or list with all the NULL items removed dropNulls <- function(x) { x[!vapply(x, is.null, FUN.VALUE=logical(1))] } +#' Convert a time object to a list +#' @param value A time object +#' @return A list with the hour, minute and second components dateToTimeList <- function(value){ if(is.null(value)) return(NULL) posixlt_value <- unclass(as.POSIXlt(value)) time_list <- lapply(posixlt_value[c('hour', 'min', 'sec')], function(x) { sprintf("%02d", trunc(x)) }) + time_list[["civilian"]] <- ifelse(posixlt_value$hour < 12, "AM", "PM") return(time_list) } +#' Convert a list to a time object +#' @param value A list with the hour, minute and second components +#' @return A time object timeListToDate <- function(value) { timeStringToDate(paste(c(value$hour, value$min, value$sec), collapse = ':')) } +#' Convert a string to a time object +#' @param string A string with the time in the format "HH:MM:SS" +#' @return A time object timeStringToDate <- function(string) { strptime(string, format = "%T") } +#' Get the default time +#' @return A time object with the value "00:00:00" getDefaultTime <- function(){ timeStringToDate("00:00:00") } -# From ?is.integer -is.wholenumber <- function(x, tol = .Machine$double.eps^0.5) abs(x - round(x)) < tol +#' Round a time object to the nearest minute +#' From ?is.integer +#' @param x A time object +#' @param tol The tolerance for rounding +#' @return A time object rounded to the nearest minute +is.wholenumber <- function(x, tol = .Machine$double.eps^0.5){ + abs(x - round(x)) < tol +} +#' Round a time object to the nearest minute +#' @param time A time object +#' @param minutes The number of minutes to round to +#' @return A time object rounded to the nearest minute roundTime <- function(time, minutes) { stopifnot(any(class(time) %in% c("POSIXt", "hms"))) stopifnot(is.wholenumber(minutes)) diff --git a/R/zzz.R b/R/zzz.R index 7213e56..07e4485 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -10,6 +10,8 @@ .onLoad <- function(libname, pkgname) { # Add directory for static resources addResourcePath('shinyTime', system.file('www', package='shinyTime', mustWork = TRUE)) + # Make shinyTime work with running devtools::load_all(".") multiple times + removeInputHandler('my.shiny.timeInput') # Do some processing on the data we get from javascript before we pass it on to R registerInputHandler('my.shiny.timeInput', function(data, ...) { # Replace NULL by 0 diff --git a/inst/debug/app.R b/inst/debug/app.R new file mode 100644 index 0000000..59d45a1 --- /dev/null +++ b/inst/debug/app.R @@ -0,0 +1,85 @@ +library(shiny) +library(bslib) +library(shinyTime) + +start_time <- "23:34:56" + +getTimeInput <- local({ + nTimeInputs <- 0 + timeInputs <- c() + function(label = NULL, value = strptime(start_time, "%T"), ...) { + nTimeInputs <<- nTimeInputs + 1 + if(is.null(label)) label <- paste("genTimeInput", nTimeInputs) + id <- paste0("gen_time_input", nTimeInputs) + timeInputs <<- c(timeInputs, id) + timeInput(id, label, value, ...) + } +}) + +getTimeInputs <- function(widths, ...) { + purrr::map(widths, \(x) getTimeInput(width = paste0(x, "px"), ...)) +} + +widths <- seq(100,500,50) + +cards <- list( + card( + full_screen = TRUE, + card_header("Width"), + layout_column_wrap( + width = 1/3, + card( + card_header("5-minute steps"), + !!!getTimeInputs(widths = widths, minute.steps = 5) + ), + card( + card_header("24H"), + !!!getTimeInputs(widths = widths) + ), + card( + card_header("12H"), + !!!getTimeInputs(widths = widths, use.civilian = TRUE) + ) + ) + ), + card( + full_screen = TRUE, + card_header("Alignment"), + card( + textInput("text_example", 'Example text input'), + getTimeInput(label = "Enter time"), + getTimeInput(label = "Enter time (5 minute steps)", minute.steps = 5), + getTimeInput(label = "Enter time (civilian)", use.civilian = TRUE) + ) + ) +) + +sb <- sidebar( + timeInput("source_time", "Desired time", + value = strptime("00:00:00", "%T")), + + actionButton("to_desired_time", "Apply desired time"), + actionButton("to_current_time", "Set to current time") +) + +ui <- page_navbar( + title = "shinyTimeDebug", + sidebar = sb, + nav_spacer(), + nav_panel("Width", cards[[1]]), + nav_panel("Alignment", cards[[2]]) +) + +server <- function(input, output, session) { + updateAllTimeInputs <- function(time, update_source = F) { + timeInputIds <- get("timeInputs", envir = environment(getTimeInput)) + if(update_source) timeInputIds <- c("source_time",timeInputIds) + purrr::map(timeInputIds, \(x) updateTimeInput(session, x, value = time)) + } + + observeEvent(input$to_current_time, updateAllTimeInputs(Sys.time(), update_source = T)) + observeEvent(input$to_desired_time, updateAllTimeInputs(input$source_time)) + +} + +shinyApp(ui, server) \ No newline at end of file diff --git a/inst/example/app.R b/inst/example/app.R index 2b4af20..dc24abd 100644 --- a/inst/example/app.R +++ b/inst/example/app.R @@ -9,20 +9,40 @@ library(shiny) library(shinyTime) +start_time <- "23:34:56" + ui <- fluidPage( titlePanel("shinyTime Example App"), sidebarLayout( + sidebarPanel( - timeInput("time_input1", "Enter time", value = strptime("12:34:56", "%T")), - timeInput("time_input2", "Enter time (5 minute steps)", value = strptime("12:34:56", "%T"), minute.steps = 5), + width = 4, + timeInput( + "time_input1", "Enter time", + value = strptime(start_time, "%T") + ), + timeInput( + "time_input2", "Enter time (5 minute steps)", + value = strptime(start_time, "%T"), + minute.steps = 5, + width = "100px" + ), + timeInput( + "time_input3", "Enter time", + value = strptime(start_time, "%T"), + use.civilian = TRUE, + width = "300px" + ), actionButton("to_current_time", "Current time") ), mainPanel( + width = 8, textOutput("time_output1"), - textOutput("time_output2") + textOutput("time_output2"), + textOutput("time_output3") ) ) ) @@ -30,10 +50,12 @@ ui <- fluidPage( server <- function(input, output, session) { output$time_output1 <- renderText(strftime(input$time_input1, "%T")) output$time_output2 <- renderText(strftime(input$time_input2, "%R")) + output$time_output3 <- renderText(strftime(input$time_input3, "%r")) observeEvent(input$to_current_time, { updateTimeInput(session, "time_input1", value = Sys.time()) updateTimeInput(session, "time_input2", value = Sys.time()) + updateTimeInput(session, "time_input3", value = Sys.time()) }) } diff --git a/inst/www/input_binding_time.js b/inst/www/input_binding_time.js index e8e763b..bc560b8 100644 --- a/inst/www/input_binding_time.js +++ b/inst/www/input_binding_time.js @@ -24,6 +24,9 @@ var zeroPad = function(num) { var correctInputValue = function(el) { var $el = $(el); + // if class is shinytime-civilian, return + if($el.hasClass('shinytime-civilian')) return; + // format as float var val = parseFloat($el.val()); // Check if number is integer, if so put to fixed form (0.1e1 will become 1), else make 0 var newVal = (val % 1 === 0) ? val.toFixed() : 0; @@ -53,7 +56,11 @@ var roundTime = function(value, minutesToRound) { }; roundedDate = roundTimeDate((new Date()).setHours(value.hour, value.min, value.sec)); - return {hour: zeroPad(roundedDate.getHours()), min: zeroPad(roundedDate.getMinutes()), sec: zeroPad(roundedDate.getSeconds())}; + return { + hour: zeroPad(roundedDate.getHours()), + min: zeroPad(roundedDate.getMinutes()), + sec: zeroPad(roundedDate.getSeconds()) + }; }; var timeInputBinding = new Shiny.InputBinding(); @@ -75,19 +82,63 @@ $.extend(timeInputBinding, { else values.push(numberVal); }); + // format hour for civilian time + var $civilian = $(el).find('.shinytime-civilian'); + if ($civilian.length > 0) { + var civilian = $civilian.val(); + var hour = parseInt(values[0], 10); + if (civilian == 'AM') { + if (hour == 12) { + // 12:00 AM is 00:00 in 24-hour notation + hour = 0; + } + } else if (civilian == 'PM') { + if (hour < 12) { + // 12:00 PM is 12:00 in 24-hour notation + hour += 12; + } + } + values[0] = hour; + } else { + var civilian = null; + } + // Return object with hour, min, sec and civilian return { hour: values[0], min: values[1], - sec: (values.length > 2) ? values[2] : 0 + sec: (values.length > 2) ? values[2] : 0, + civilian: civilian }; }, setValue: function(el, value) { var $inputs = $(el).find('input'); + // format minute step minuteSteps = $inputs.eq(1).attr("step"); if(minuteSteps && minuteSteps != 1) value = roundTime(value, minuteSteps); - $inputs.eq(0).val(value.hour); + // set min and sec values $inputs.eq(1).val(value.min); - $inputs.eq(2).val(value.sec); + if ($inputs.length > 2) $inputs.eq(2).val(value.sec); + // Set to civilian time from military time + var $civilian = $(el).find('.shinytime-civilian'); + if ($civilian.length > 0 && value.civilian) { + var hour = parseInt(value.hour, 10); + if(value.civilian == 'AM') { + if (hour == 0) { + hour = 12; + } + } else if (value.civilian == 'PM') { + if (hour > 12) { + hour -= 12; + } + } + // set hour value + $inputs.eq(0).val(hour); + // set civilian value + $civilian.val(value.civilian); + } else { + // set hour value + $inputs.eq(0).val(value.hour); + } }, receiveMessage: function(el, data) { // To get updateTimeInput working @@ -106,13 +157,27 @@ $.extend(timeInputBinding, { return "my.shiny.timeInput"; }, subscribe: function(el, callback) { + // Bind change event for input elements $(el).on("change.timeInputBinding", function(e) { correctInputValue(e.target); callback(); }); + // Bind change event for civilian time + var $civilian = $(el).find('.shinytime-civilian'); + if ($civilian.length > 0) { + $civilian.on("change.shinytime-civilian", function(e) { + callback(); + }); + } }, unsubscribe: function(el) { + // Unbind change event for input elements $(el).off(".timeInputBinding"); + // Unbind change event for civilian time + var $civilian = $(el).find('.shinytime-civilian'); + if ($civilian.length > 0) { + $civilian.off(".shinytime-civilian"); + } } }); diff --git a/man/dateToTimeList.Rd b/man/dateToTimeList.Rd new file mode 100644 index 0000000..5f1d596 --- /dev/null +++ b/man/dateToTimeList.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{dateToTimeList} +\alias{dateToTimeList} +\title{Convert a time object to a list} +\usage{ +dateToTimeList(value) +} +\arguments{ +\item{value}{A time object} +} +\value{ +A list with the hour, minute and second components +} +\description{ +Convert a time object to a list +} diff --git a/man/dropNulls.Rd b/man/dropNulls.Rd new file mode 100644 index 0000000..0601413 --- /dev/null +++ b/man/dropNulls.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{dropNulls} +\alias{dropNulls} +\title{Drop NULL values from vector/lists} +\usage{ +dropNulls(x) +} +\arguments{ +\item{x}{A vector or list} +} +\value{ +A vector or list with all the NULL items removed +} +\description{ +Drop NULL values from vector/lists +} diff --git a/man/getDefaultTime.Rd b/man/getDefaultTime.Rd new file mode 100644 index 0000000..3d71509 --- /dev/null +++ b/man/getDefaultTime.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{getDefaultTime} +\alias{getDefaultTime} +\title{Get the default time} +\usage{ +getDefaultTime() +} +\value{ +A time object with the value "00:00:00" +} +\description{ +Get the default time +} diff --git a/man/is.wholenumber.Rd b/man/is.wholenumber.Rd new file mode 100644 index 0000000..877b0e9 --- /dev/null +++ b/man/is.wholenumber.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{is.wholenumber} +\alias{is.wholenumber} +\title{Round a time object to the nearest minute +From ?is.integer} +\usage{ +is.wholenumber(x, tol = .Machine$double.eps^0.5) +} +\arguments{ +\item{x}{A time object} + +\item{tol}{The tolerance for rounding} +} +\value{ +A time object rounded to the nearest minute +} +\description{ +Round a time object to the nearest minute +From ?is.integer +} diff --git a/man/roundTime.Rd b/man/roundTime.Rd new file mode 100644 index 0000000..c115bf4 --- /dev/null +++ b/man/roundTime.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{roundTime} +\alias{roundTime} +\title{Round a time object to the nearest minute} +\usage{ +roundTime(time, minutes) +} +\arguments{ +\item{time}{A time object} + +\item{minutes}{The number of minutes to round to} +} +\value{ +A time object rounded to the nearest minute +} +\description{ +Round a time object to the nearest minute +} diff --git a/man/shinyInputLabel.Rd b/man/shinyInputLabel.Rd new file mode 100644 index 0000000..b096a4a --- /dev/null +++ b/man/shinyInputLabel.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{shinyInputLabel} +\alias{shinyInputLabel} +\title{Create a label tag for a given input} +\usage{ +shinyInputLabel(inputId, label = NULL, control = FALSE) +} +\arguments{ +\item{inputId}{The input ID} + +\item{label}{The label text} + +\item{control}{Whether the label is for a control (e.g., a checkbox)} +} +\value{ +A label tag +} +\description{ +Create a label tag for a given input +} diff --git a/man/shinyTime-package.Rd b/man/shinyTime-package.Rd index 86cf62b..c2aa14b 100644 --- a/man/shinyTime-package.Rd +++ b/man/shinyTime-package.Rd @@ -6,7 +6,7 @@ \alias{shinyTime-package} \title{shinyTime: A Time Input Widget for Shiny} \description{ -Provides a time input widget for Shiny. This widget allows intuitive time input in the '[hh]:[mm]:[ss]' or '[hh]:[mm]' (24H) format by using a separate numeric input for each time component. The interface with R uses date-time objects. See the project page for more information and examples. +Provides a time input widget for Shiny. This widget allows intuitive time input in the '[hh]:[mm]:[ss]' or '[hh]:[mm]' (24H and 12H) format by using a separate numeric input for each time component. The interface with R uses date-time objects. See the project page for more information and examples. } \seealso{ Useful links: @@ -20,5 +20,10 @@ Useful links: \author{ \strong{Maintainer}: Gerhard Burger \email{burger.ga@gmail.com} (\href{https://orcid.org/0000-0003-1062-5576}{ORCID}) +Authors: +\itemize{ + \item Nick Youngblut (\href{https://orcid.org/0000-0002-7424-5276}{ORCID}) +} + } \keyword{internal} diff --git a/man/shinyTimeDebug.Rd b/man/shinyTimeDebug.Rd new file mode 100644 index 0000000..74973e7 --- /dev/null +++ b/man/shinyTimeDebug.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/input-time.R +\name{shinyTimeDebug} +\alias{shinyTimeDebug} +\title{Show the shinyTime debug app} +\usage{ +shinyTimeDebug() +} +\description{ +App to test the input with a variety of options +} diff --git a/man/timeInput.Rd b/man/timeInput.Rd index 36680e6..b56fb44 100644 --- a/man/timeInput.Rd +++ b/man/timeInput.Rd @@ -4,7 +4,15 @@ \alias{timeInput} \title{Create a time input} \usage{ -timeInput(inputId, label, value = NULL, seconds = TRUE, minute.steps = NULL) +timeInput( + inputId, + label, + value = NULL, + seconds = TRUE, + minute.steps = NULL, + use.civilian = FALSE, + width = NULL +) } \arguments{ \item{inputId}{The \code{input} slot that will be used to access the value.} @@ -17,6 +25,11 @@ timeInput(inputId, label, value = NULL, seconds = TRUE, minute.steps = NULL) \item{minute.steps}{Round time to multiples of \code{minute.steps} (should be a whole number). If not NULL sets \code{seconds} to \code{FALSE}.} + +\item{use.civilian}{Use civilian time (12-hour format) instead of 24-hour format.} + +\item{width}{The width of the input, e.g. \code{'400px'}, or \code{'100\%'}; +see \code{\link[shiny:validateCssUnit]{validateCssUnit()}}.} } \value{ Returns a \code{POSIXlt} object, which can be converted to @@ -54,7 +67,10 @@ ui <- fluidPage( timeInput("time6", "Time:", seconds = FALSE), # Use multiples of 5 minutes - timeInput("time7", "Time:", minute.steps = 5) + timeInput("time7", "Time:", minute.steps = 5), + + # Use civilian (non-military time) + timeInput("time8", "Time:", use.civilian = TRUE) ) shinyApp(ui, server = function(input, output) { }) diff --git a/man/timeListToDate.Rd b/man/timeListToDate.Rd new file mode 100644 index 0000000..3d9f752 --- /dev/null +++ b/man/timeListToDate.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{timeListToDate} +\alias{timeListToDate} +\title{Convert a list to a time object} +\usage{ +timeListToDate(value) +} +\arguments{ +\item{value}{A list with the hour, minute and second components} +} +\value{ +A time object +} +\description{ +Convert a list to a time object +} diff --git a/man/timeStringToDate.Rd b/man/timeStringToDate.Rd new file mode 100644 index 0000000..cb69690 --- /dev/null +++ b/man/timeStringToDate.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{timeStringToDate} +\alias{timeStringToDate} +\title{Convert a string to a time object} +\usage{ +timeStringToDate(string) +} +\arguments{ +\item{string}{A string with the time in the format "HH:MM:SS"} +} +\value{ +A time object +} +\description{ +Convert a string to a time object +}