Someone in the "Europe/London" (UTC +0) Timezone created a Spreadsheet. They input the date "March 22 2019" into one of the fields. This represents the date 3/22/2019 0:00 UTC+O.
I'm in the "America/Los_Angeles" (UTC -7) Timezone. When I run a Google Apps Script and try to get the value, it's evaluated as:
Thu Mar 21 17:00:00 GMT-07:00 2019
This is accurate since 3/22/2019 0:00 UTC+O == 3/21/2019 17:00 UTC-7.
The problem is when I try to get the date programmatically, I'll get it as 21 instead of 22.
For example, if I try to run:
cellRange.getValue().getDate() // returns 21 even though the sheet shows the date as 22
This is because getDate() returns values "according to local time." The local script time is UTC-7, hence it's returning 21.
However, this causes a dissonance:
Spreadsheet date: 22 (i.e. the value I see in the sheet)
Programmatic date: 21 (i.e. the one returned by getDate() above)
This is problematic when I'm trying to use a function such as joinDateAndTime_() with "March 22 2019" as the date and 6am as the time, for example. This causes it to produce a date "March 21 2019 6:00 UTC-7" instead of "March 22 2019 6:00 UTC-7".
What is the best solution here?
Not a complete solution (I'll update soon)
It seems like this is what is happening:
The value is hard-coded as "March 22" (text).
When a user opens the sheet, no matter what timezone they are in, it'll assume it represents March 22 in the sheet's timezone. 3/22/2019 0:00 UTC+0
Once you read the value into a JavaScript Date, all date functions assume you want it in your current (aka the script's) timezone. 3/21/2019 17:00 UTC-7
Solution A: Just add the hours
Forget about the timezones. Instead of hardcoding the hours in a Date, just offset the date by the hours you want.
The only downside is you need to be certain that the date started at 0:00 according to whatever timezone it was in. (E.g. if they decided to write "March 22 2019 5:00", then you'll be offsetting the hours incorrectly.)
Solution B: Do some math
I'll update this soon, but eventually you might want a function sheetTimezoneOffset() that could be used like this:
function getDate(cellRange) {
var date = cellRange.getValue().getDate();
var extraneousHours = formatDate(date, "h", sheetTimezoneOffset());
date = date.addHours(-extraneousHours);
var offsetHours = 6; // e.g. for 6am
date.addHours(offsetHours);
return date;
}
I have two inputs first input is for getting the date and the second input is for getting the time of the day.
For example,
User selects date: 20 January 2019 and time: 12:30 pm.
When I convert the date input to Unix timestamp I get the timestamp for 00:00 hours on 20 January 2019.
startingDate = moment(date.startsOn).unix();
So I want to add hours that I'm getting from the user into the date timestamp.
When I try to convert hours into Unix timestamp I get a timestamp for the present day along with the hours entered by the user i.e. I get timestamp for 12:00 pm on 11 January 2019.
startingTime = moment(date.startingTime).unix();
Any suggestion how I can achieve this?
I managed to do this in this way:
As I had my starting date and time in unix format
startingDate = moment(date.startsOn).unix();
startingTime = moment(date.startingTime).unix();
I had to convert them into moment format
const date = moment.unix(this.startingDate).format('YYYY-MM-DD h:mm a');
const hours = moment.unix(this.startingTime).format('HH');
Then I added hours to my date constant
var finalTime = date.add(hours, 'hours');
Then I posted this finalTime to my API.
I have to maintain an ASPX page that increments the date/time by passing a value in the querystring in this format:
636529536000000000 in reference to 31 January 2018
636530400000000000 in reference to 01 February 2018
The url format is: /reservas.aspx?t=636530400000000000
What is this date/time format?
It is the number of ticks where a tick is one hundred nanoseconds or one ten-millionth of a second. The number of ticks is measured since the epoch DateTime.MinValue (12:00:00 midnight, January 1, 0001). For example:
new DateTime(636529536000000000).ToString("F", CultureInfo.InvariantCulture)
outputs:
Wednesday, 31 January 2018 00:00:00
Could be a number of days from certain date, similar to julian date calculation:
https://en.wikipedia.org/wiki/Julian_day#Julian_date_calculation
Potentially incorporating the time as well?
Without details of the code I cant really advise from a provided value.
I have a starting time in "HH:MM:SS" format. In my spreadsheet, the user enters it in this format, like "09:00:00" for 9AM. When I get this cell's value in my script, I get this weirdo :
"Sat Dec 30 09:00:00 GMT+00:09 1899"
It seems like I have that random date of Sat Dec 30 1899, which I don't really care about, but also the "GMT+00:09", that bothers me a lot more. My spreadsheet and script are "GMT+01:00 Paris", so when I insert this data elsewhere, I get 09:50 GMT+01:00... Not even 51 minutes off, as I would have expected.
Do you have any idea how and why it happens ?
The fix I use right now is to display the time in my "HH:MM:SS" format, or "HH:MM", but set the value to, say "05/01/2018 09:00:00", so it is considered a full dateTime in my timezone. I would really like to be able to only specify the time here.
Thanks for your answers,
How about this answer? This answer supposes the following condition.
Format of cell "A1" is HH:MM:SS for time.
Value of cell "A1" is 09:00:00.
In your 1st case :
When the value of "A1" is retrieved by getValue(), the value is Sat Dec 30 09:00:00 GMT+09:00 1899. (I'm sorry. "GMT+09:00" is due to the time zone. My time zone is Asia/Tokyo.) Because Spreadsheet uses Serial Number for Date/Time. The start of serial number is 12/30/1899 00:00:00. In this case, because there are no date information, Sat Dec 30 09:00:00 GMT+09:00 1899 is retrieved as the value which elapsed for 09:00:00 from the start.
If you want to retrieve 09:00:00 from cell "A1", please use getDisplayValue() instead of getValue(). By this, you can retrieve 09:00:00.
In your 2nd case :
I think that this is better usage. 05/01/2018 09:00:00 is imported to the cell with the format of HH:MM:SS. By this, the value has the information of both date and time. So the values of cell retrieved by getValue() and getDisplayValue() are Fri Jan 05 09:00:00 GMT+09:00 2018 and 09:00:00, respectively.
Sample :
In the case using getValue()
SpreadsheetApp.getActiveSheet().getRange("A1").getValue();
In the case using getDisplayValue()
SpreadsheetApp.getActiveSheet().getRange("A1").getDisplayValue();
References :
getValue()
getDisplayValue()
Date/Time serial numbers
If I misunderstand your question, I'm sorry.
I have time series data from 1974-2013 with a column for datetimeUTC (YYYY-MM-DD hh:mm +0000), and a column for the timezones in Olson format (e.g., Canada/Pacific, Canada/Eastern). I can convert the whole UTCdatetime column to a common timezone like this:
dataset$datetimeEST <- strptime(
dataset$datetimeUTC, format="%Y-%m-%d %H:%M:%S%z", tz="Canada/Eastern"
)
How do I convert datetimeUTC to datetimeLOCAL, given the corresponding timezone in each row?
Let me back up a bit. I have data from across the country (6 timezones) formatted in ISO8601 representation for 1974-2013. The timestamps are in local standard time throughout the year (i.e. DST is disregarded even if civilian time in the region observes DST). I need to do datetime calculations which are probably safest to do in UTC time, so that's easy. But, I also need to pull data for specific civil time periods, taking into account DST, and do calculations and plots (e.g., all the data for rush hour at locations across all 6 timezones) for that subsetted data.
The datetimeCLOCKTIME that I calculated below appears to be doing what I want for plotting, but gives the wrong answer when doing datetime calculations because it stored the datetime in the timezone of my local machine without having actually converted the time. The solution offered by #thelatemail is what I'm looking for, but I haven't been able to get it to work in Windows on the test dataset for 2012 (see below). Also, I was using strptime which converts to POXITlt, and his solution is in POXITct. I'm new to R, so any help would be infinitely appreciated.
Test dataset:
dataset <- data.frame (timestampISO8601 = c("2012-04-25T22:00:00-08:00","2012-04-25T22:15:00-08:00","2012-04-25T22:30:00-08:00","2012-04-25T22:45:00-08:00","2012-04-25T23:00:00-08:00","2012-04-25T23:15:00-08:00","2012-04-25T23:30:00-08:00","2012-04-25T23:45:00-08:00","2012-04-26T00:00:00-08:00","2012-04-26T00:15:00-08:00","2012-04-26T00:30:00-08:00","2012-04-26T00:45:00-08:00","2012-04-26T01:00:00-08:00","2012-04-26T01:15:00-08:00","2012-04-26T01:30:00-08:00","2012-04-26T01:45:00-08:00","2012-04-26T02:00:00-08:00","2012-04-25T22:00:00-03:30","2012-04-25T22:15:00-03:30","2012-04-25T22:30:00-03:30","2012-04-25T22:45:00-03:30","2012-04-25T23:00:00-03:30","2012-04-25T23:15:00-03:30","2012-04-25T23:30:00-03:30","2012-04-25T23:45:00-03:30","2012-04-26T00:00:00-03:30","2012-04-26T00:15:00-03:30","2012-04-26T00:30:00-03:30","2012-04-26T00:45:00-03:30","2012-04-26T01:00:00-03:30","2012-04-26T01:15:00-03:30","2012-04-26T01:30:00-03:30","2012-04-26T01:45:00-03:30","2012-04-26T02:00:00-03:30"), olson = c("Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland"), value = c(0,0,1,2,5,11,17,19,20,19,17,11,5,2,1,0,0,-3,-3,-2,-1,2,8,14,16,17,16,14,8,2,-1,-2,-3,-3), stringsAsFactors=FALSE)
Remove the ":" from the UTC offset. (R is expecting the format nnnn for the UTC offset):
dataset$timestampR<- paste(substr(dataset$timestampISO8601,1,22),substr(dataset$timestampISO8601,24,25),sep="")
When converting to UTC time, R defaults to -ve for the UTC offset, making -ve offsets in the timestamps positive:
dataset$datetimeUTC <- strptime(dataset$timestampR, format="%Y-%m-%dT%H:%M:%S%z", tz="UTC")
When converting to MACHINE time like this, R reads the input time and converts it to the time in the timezone of the local machine - in my case, this is Canada/Eastern:
dataset$datetimeMACHINE <- strptime(dataset$timestampR, format="%Y-%m-%dT%H:%M:%S%z")
When converting to CLOCKTIME time like this, R reads the input time and assigns the time zone of the local machine (currently EDT on my machine) without doing any time conversions:
dataset$datetimeCLOCKTIME <- strptime(dataset$timestampR,format="%Y-%m-%dT%H:%M:%S")
See the structure of the dataset:
str(dataset)
Plotting behaviours are different
library(ggplot2)
qplot(data=dataset,x=datetimeUTC,y=value)
qplot(data=dataset,x=datetimeMACHINE,y=value)
qplot(data=dataset,x=datetimeCLOCKTIME,y=value)
Calculation results differ. Incorrect calculation result for datetimeCLOCKTIME:
range (dataset$datetimeUTC)
range (dataset$datetimeMACHINE)
range (dataset$datetimeCLOCKTIME)
dataset$datetimeUTC[34] - dataset$datetimeUTC[1]
dataset$datetimeMACHINE[34] - dataset$datetimeMACHINE[1]
dataset$datetimeCLOCKTIME[34] - dataset$datetimeCLOCKTIME[1]
You could format back and forth a bit to get a local time representation in a character format. E.g.:
dataset <- data.frame(
datetimeUTC=c("2014-01-01 00:00 +0000","2014-01-01 00:00 +0000"),
olson=c("Canada/Eastern", "Canada/Pacific"),
stringsAsFactors=FALSE
)
# datetimeUTC olson
#1 2014-01-01 00:00 +0000 Canada/Eastern
#2 2014-01-01 00:00 +0000 Canada/Pacific
dataset$localtime <- with(dataset,
mapply(function(dt,ol) format(
as.POSIXct(dt,"%Y-%m-%d %H:%M %z",tz=ol),
"%Y-%m-%d %H:%M %z"),
datetimeUTC, olson
)
)
# datetimeUTC olson localtime
#1 2014-01-01 00:00 +0000 Canada/Eastern 2013-12-31 19:00 -0500
#2 2014-01-01 00:00 +0000 Canada/Pacific 2013-12-31 16:00 -0800
If you have only two time zones to convert to and know the difference in time between UTC and those two. Using #thelatemail's dataset
transform(dataset,
localtime=as.POSIXct(datetimeUTC, "%Y-%m-%d %H:%M %z")-
c(5*3600,8*3600)[as.numeric(factor(olson))])
# datetimeUTC olson localtime
#1 2014-01-01 00:00 +0000 Canada/Eastern 2013-12-31 19:00:00
#2 2014-01-01 00:00 +0000 Canada/Pacific 2013-12-31 16:00:00