I'm wondering if there is some clever way of getting the clients current time and time zone in order to use it in the server.R
part of a Shiny application. If not, what could be the easiest way of doing this?

- 4,827
- 4
- 29
- 29
5 Answers
I hadn't heard of Shiny until your post. Reading through the documentation, it would appear that the client-side portion of a Shiny application is written in R, but then renders as HTML/CSS/JavaScript so it can run in the browser. The information you're asking for would have to be sourced from JavaScript.
Getting the current time in JavaScript is quite simple:
var now = new Date();
The result is a Date
object that has the current date and time from the client's clock. Internally, it's tracked as the UTC time in milliseconds since Midnight 1/1/1970 UTC. However the Date
object will take the client's local time zone into account when producing output such as with .toString()
or when using many of the other functions. You can read more about the Date
object in the MDN reference documentation.
Now, if you actually need the time zone of the client, that's a different story. The Date
object can only give you the time zone offset of a particular date and time, using the .getTimezoneOffset()
function. For example, you can tell that the client is currently 420 minutes behind UTC, (UTC-07:00), but you cannot tell that the client is in the America/Los_Angeles
time zone - which alternates between UTC-07:00 and UTC-08:00 for daylight saving time. Read more in the timezone tag wiki.
There is one JavaScript library, jsTimeZoneDetect, that attempts to guess at the time zone, and it does a reasonably decent job.
So - now the question would be, how do you call custom JavaScript from a Shiny app in R? I'm no expert in this area, but it would appear to be covered by this part of the Shiny documentation.
All of this would be done client-side. You would then have to send it to the server to use the information in the server.R part of the application.

- 1
- 1

- 230,703
- 74
- 448
- 575
I found out a method that works and which is just a small modification of the stackoverflow answer to Reading javascript variable into shiny/R on app load. It does not retrieve the actuall time zone, but well the time zone offset.
In ui.R
HTML('<input type="text" id="client_time" name="client_time" style="display: none;"> '),
HTML('<input type="text" id="client_time_zone_offset" name="client_time_zone_offset" style="display: none;"> '),
tags$script('
$(function() {
var time_now = new Date()
$("input#client_time").val(time_now.getTime())
$("input#client_time_zone_offset").val(time_now.getTimezoneOffset())
});
')
This above created two div
s and the javascript code retrieves the clients time and time zone offset and put them in the div
s.
In server.R
client_time <- reactive(as.numeric(input$client_time) / 1000) # in s
time_zone_offset <- reactive(as.numeric(input$client_time_zone_offset) * 60 ) # in s
This above creates two reactive variables that can be used in the server code. For ease of handling I also transform input$client_time
from ms to s and input$client_time_zone_offset
from min to s.

- 1
- 1

- 4,827
- 4
- 29
- 29
You could fetch it over socket communication, but with much overhead, or if your time between the client is synchronized, you could trust your local time, fetch their timezone, evaluate the timezone difference between the server and the client, plus/minus the difference, then you would fetch their time and timezone without much work. (Somehow probably but in most case, by doing this, would lose a precision of 2 to 3 seconds due to computer keep up)

- 3,019
- 3
- 19
- 29
Another way to do it : send a message to the client at any time and retrieve the result with the input object. You will also measuring latency. (Or if the user changed of time zone during the shiny session...).
Get server time and time zone, send it to client via sendCustomMessage.
# R
triggerClientTime <- function(session=shiny::getDefaultReactiveDomain()){
serverTime <- Sys.time()
serverTimeZone <- as.integer(strftime(serverTime,"%z"))/100
session$sendCustomMessage(
type="getClientTime",
message=list(
serverPosix = as.numeric(serverTime),
serverTimeZone = serverTimeZone
)
)
}
Put this function in server file.
In javascript, get the message, retrieve time and zone offset, send it back to server as a new input entry :
// js
Shiny.addCustomMessageHandler("getClientTime",
function(s){
var d = new Date()
var clientPosix = parseInt(d.getTime()/1000);
var clientTimeZone = -(d.getTimezoneOffset() / 60);
var res = {
serverPosix:s.serverPosix,
serverTimeZone:s.serverTimeZone,
clientPosix:clientPosix,
clientTimeZone:clientTimeZone
}
Shiny.onInputChange("clientTime",res)
})
Put this code in a script tag or in a separate js file.
In a shiny session :
# Observe and print time from client and server
observe({
print(input$clientTime)
})
# Ask the client for current time and time zone (hours from UTC)
triggerClientTime()
It should output something like:
# output
$serverPosix
[1] 1449827815
$serverTimeZone
[1] 1
$clientPosix
[1] 1449827816
$clientTimeZone
[1] 1

- 607
- 8
- 16
One of the problems we had was that we use physiological data and want to synchronize this data with calendar data filled out by a user. The physiological data is always datetime stamped with UTC time (and can then later be timestamped based on your own local timezone) while typical calendar data is in local clock time.
For the local R session this did not result in any problems. The calendar clock time data is read in with the timezone (Sys.timezone()) from your local computer, and then a UTC datetime stamp is attached (which can then also be time stamped with your local timezone).
However, on Shiny server (shinyapps.io) this results in unwanted behavior. Shiny server uses UTC time while calendar clock time data was filled out in the users' timezone. This effectively means that there is an unkown offset (Shinyapps.io does not provide the user timezone) on the calendar clock time that we wanted to adjust for. To my knowledge Shinyapps.io does not have a method to detect the timezone of the user (but please correct me if I'm wrong).
Based on several answers on finding the user time zone I have created a small shiny app to fetch the user timezone based on the browser of the user. Maybe it could be of use to someone else as it took me some time to figure this out.
So to keep a long story short: Copy and paste the Shiny code into an Rscript to fetch the user unix time, offset and time zone based on their browser
library(shiny)
runApp(list(
ui = bootstrapPage(
tags$script('
$(function() {
var time_now = new Date()
$("input#client_time").val(time_now.getTime())
$("input#client_time_zone_offset").val(time_now.getTimezoneOffset())
$("input#client_time_zone_char").val(time_now.toTimeString())
$("input#client_time_zone_international").val(Intl.DateTimeFormat().resolvedOptions().timeZone)
});
'),
textInput("client_time", "Client Time", value = ""),
textInput("client_time_zone_offset", "Time zone offset", value = ""),
textInput("client_time_zone_char", "Time zone verbatim", value = ""),
textInput("client_time_zone_international", "Time zone international", value = "")
),
server = function(input, output) {
client_time <- reactive(as.numeric(input$client_time) / 1000) # in s
client_time_zone_offset <- reactive(as.numeric(input$client_time_zone_offset) * 60 ) # in s
client_time_zone_char <- reactive(input$client_time_zone_char)
client_time_zone_international <- reactive(input$client_time_zone_international)
observe({
paste(input$client_time, sep = "; ")
paste(input$client_time_zone_offset, sep = "; ")
paste(input$client_time_zone_char, sep = "; ")
paste(input$client_time_zone_international, sep = "; ")
# Capture timezone in vector
browser_tz <- paste(input$client_time_zone_international, sep = "; ")
})
}
))

- 89
- 8