Utilities.formatDate Date not set correct - google-apps-script

I have a date stored as follows:
existingDate = Wed Apr 30 2014 00:00:00 GMT+0100 (BST)
When I use Utilities.formatDate to format the date the date is changed to the day before.
var formattedDate = Utilities.formatDate(new Date(existingDate), "GMT", "dd/MM/yyyy");
the formatted date is then set to 29/04/2014 and not 30/04/2014.
Has anyone else seen this behavior.

Utilities.formatDate seems to be working fine.
You have Apr 30 midnight in GMT-1 but then you tell it to format this date in a different timezone GMT, or more explicity GMT-0. The expected result is indeed Apr 29 23h.
The second parameter in Utilities.formatDate must be the timezone you desire.

There are some other issues with this google script.
If I want the timezone AEST but only have the date in the form of 1/27/2017, then Utilities.formatDate("1/27/2017","AEST","yyyy-MM-dd") will return a value of 2017-01-26, a day before it should be! However if I have a time with it such as "1/27/2017 12:00:00" then it returns the correct day. However if I use "GMT+11" as the timezone even without a time on the end if returns the correct day.
Example -
Logger.log('Example 1='+Utilities.formatDate(new Date("1/27/2017"),"AEST","yyyy-MM-dd"));
Logger.log('Example 2='+Utilities.formatDate(new Date("1/27/2017 12:00:00"),"AEST","yyyy-MM-dd"));
Logger.log('Example 3='+Utilities.formatDate(new Date("1/27/2017"),"GMT+11","yyyy-MM-dd"));
Output -
Example 1=2017-01-26
Example 2=2017-01-27
Example 3=2017-01-27
A workaround when reading a date from a spreadsheet cell that does not have a time is to add a time and when using a timezone like "AEST" or similar, something like this -
var displayDate = sheet.getRange(a1Notation).getDisplayValue(); // Not .getValue();
Logger.log(Utilities.formatDate(new Date(displayDate + " 12:00:00"), "AEST", "yyyy-MM-dd"));
However "GMT+11" would be easier because you don't need to add a time.

Related

Date changes when setValues() is called

I have written a script for a client in a Spreadsheet whose time is GMT-5 while my TimeZone is GMT+5. The column H on the spreadsheet's tab has a value as date without any time factor e.g. 01/25/2019.
On the start of script function I am setting the format of column like under the following .setNumberFormat("MM/dd/yyyy"). Also note that I am working with .getDisplayValues() which returns me test for the Date column.
There is nowhere in the script I am explicitly updating DateValue its value. After manipulating some other values on the other column I happen to update the row by calling the .setValues([row]).
Then the date changes to 01/24/2019 and when I change the format to include time factor then it is like 01/24/2020 19:00:00.
Interesting point is it does not occur on my end where my timeZone is GMT+5. Even though I changed the Spreadsheet's Timezone to GMT-5 and on my system as well but still it doesn't occur on my end but on the client machine.
The runtime version of the script is:
"runtimeVersion": "V8"
This can happen when the script time zone and spreadsheet time zone are different and you format the date object
I cannot reproduce your exact situation from the information you provided, but I invite you to do the following test:
Set your spreadsheet timezone to any timezone that is ahead of your script time zone
Set cell A1 of your active sheet to =today()
Run the following code:
function myFunction(){
var displayDate = SpreadsheetApp.getActiveSheet().getRange("A1").getDisplayValue();
Logger.log("displayDate: " + displayDate);
var date = SpreadsheetApp.getActiveSheet().getRange("A1").getValue();
Logger.log("actual date retrieved by Apps Script: " + date);
var timeZone = Session.getScriptTimeZone();
Logger.log("ScriptTimeZone: " + timeZone);
var timezone2 = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
Logger.log("SpreadsheetTimeZone: " + timezone2);
var newDate = Utilities.formatDate(date, timeZone, "MM/dd/yyyy");
Logger.log("formatted date that will be set back to the spreadsheet: " + newDate);
SpreadsheetApp.getActiveSheet().getRange("A1").setValue(newDate);
}
function updatePatientTransactions(transactionSheetValues, patientNam, insuranceName) {
var tempRow = [];
for(var i= start; i<= end-2; i++) {
tempRow = transactionSheetValues[i];
tempRow[0] = patientName;
tempRow[3] = insuranceName;
transactionSheet.getRange(i+2,1,1,transactionSheet.getLastColumn()).setValues([tempRow]);
}
}
Observe the logs and the output
Sample logs:
Stackdriver logs
Jun 8, 2020, 1:03:00 PM Info displayDate: 6/8/2020
Jun 8, 2020, 1:03:01 PM Info actual date retrieved by Apps Script: Sun Jun 07 2020 23:00:00 GMT+0200 (Central European Summer Time)
Jun 8, 2020, 1:03:01 PM Info ScriptTimeZone: Europe/Paris
Jun 8, 2020, 1:03:01 PM Info SpreadsheetTimeZone: Europe/Athens
Jun 8, 2020, 1:03:01 PM Info formatted date that will be set back to the spreadsheet: 06/07/2020
so the date will be set back to yesterday.
Why?
When you retrieve a value that is formatted as Date and not Date Time, that is if the time is not set - Apps Script automatically sets it to midnight.
When it is the 8th of June midnight in Athens, it is the 7th of June 23:00 o'clock in Paris
This is why the conversion from a spreadsheet timezone to a script timezone lying behind will lead to a date change
Now, if you format the date value as a date string or process it otherwise, the informaiton about the original timezone might get lost and when you set the datestring back to the spreadsheet, you will set back the Apps Script date - different from the spreadsheet date - so be careful!

How to get google sheet's cell values as is using google script

I'm about to use google sheet as my database for my android app small project. I'm using Google Script to handle the request from my app.
In my google sheet, I store;
A2:A = date as dd/mm/yyyy e.g 21/12/2019 but
the display format is dd-MMM e.g 21-Dec
C2:D = time as hh:mm:ss e.g 21:00:00 but
the display format is hh:mm e.g 21:00
Yes, I need a different format for the display and input.
My google sheet:
When I use google script to get a value of the cell, it seems that it is reformatted
the date looks like this: Sat Jan 01 2019 00:00:00 GMT+0700 (ICT)
the time the other hand, change in value a bit. 20:00:00 to 19:52:48
Is there any function to get cell real values as text without being reformatted?
The only thing that I can think of is instead of using getValues(), I can use getDisplayValues(). The values will not be reformatted, but it is not a solution for me, as it will take the display format.
Snippet of my code:
function updateData(e, sheet) {
var tgl = e.parameter.tgl;
var dtg = e.parameter.dtg;
var plg = e.parameter.plg;
var lbr = e.parameter.lbr;
var rangeHead = sheet.getRange("A2:A");
var valuesHead = rangeHead.getValues();
var rangeFirst = sheet.getRange("C2:D")
var valuesFirst = rangeFirst.getValues();
var rangeSecond = sheet.getRange("G2:G")
var valuesSecond = rangeSecond.getValues();
for (var i = 0; i < valuesHead.length; i++) {
if (valuesHead[i][0] === tgl) {
if(dtg!="null") { valuesFirst[i][0] = dtg; }
if(plg!="null") { valuesFirst[i][1] = plg; }
if(lbr!="null") { valuesSecond[i][0] = lbr; }
break;
}
}
rangeFirst.setValues(valuesFirst);
rangeSecond.setValues(valuesSecond);
}
The code won't work as I will comparing 21/12/2019 with Sat Jan 01 2019 00:00:00 GMT+0700 (GMT).
[UPDATE 1]:
Thank you P-Burke for the enlightenment. Now, I have an idea to solve the date problem. I know that the script pulls the date as date object, but I am unaware that it also saves as a date object. (hehe my bad) I don't realize it as there is no autocomplete when I call values[0][0]. of course, as it recognizes the object type at the run time.
So, my workaround will be; I will call getDate, getMonth+1, and getYear. After that, I will compare with my parameter freely.
Though, the time cell still a bit confusing for me. the time offset is 18 minutes 12 seconds. I don't think it's because of timezone different and my computer clock. the timezone different is too big and I 've made sure that the script, spreadsheet, and local timezone all the same. My computer clock is also only a minute less behind.
[UPDATE 2]:
Alright, enough with the confusion. It seemed that the script converts the time to Date object respect to my local timezone. I got this answer from another thread. So, actually, my local timezone changes many times and some of them have offset smaller than hours unit (one of the timezones used in my area is UTC +7:07:12h). The only source documenting those changes I could find is from https://www.timeanddate.com/time/zone/indonesia/jakarta. Finally, I gave up. For my goodness sake, I will just use getDisplayValue and ignore the seconds. Unless you guys have any other workaround, I will be so grateful.
Thank you once again to the community.
Firstly, and I don't know if this is related to your issue, but the spreadsheet and the script each have their own timezone setting:
Spreadsheet: File >> Spreadsheet Settings >> Time Zone.
Script: File >> Project Properties >> Time Zone.
And if these are different that can lead to confusion. One answer, if all your users are in the same timezone, is to set them to the same. Alternatively these can be determined from within your script as described here, and logic included to handle any differences. I don't understand the few minutes time difference, perhaps your PC clock is inaccurate?
The other point, which I think is more relevant to your question is that you effectively have multiple date/time formats in play. The picture below shows that in the spreadsheet times are edited in one format (02/01/2019 09:00:00), but displayed in whatever format is defined for the cell using the format menu. Yet when the cell values are pulled into a script using getValues() and displayed they appear as follows: Values: [[Thu Jan 31 09:00:00 GMT+00:00 2019, Wed Jan 02 09:00:00 GMT+00:00 2019]].
Yet in the code below, values[0][0] and values[0][1] are actually JavaScript Date() objects and can be compared in the usual way, alternatively they can be reformatted into whatever string format you require as illustrated in the code below:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var ws = ss.getActiveSheet();
var input_range = ws.getRange("A1:B1");
var values = [];
values = input_range.getValues(); // Returns a multi-dimensional array, hence [0][0] to access.
Logger.log("Values: %s", values);
// As Date() objects the usual methods are available.
Logger.log("Date().getMonth(): %s",values[0][0].getMonth());
Logger.log("Date().getYear(): %s",values[0][1].getYear());
// This formats the date as Greenwich Mean Time in the format
// year-month-dateThour-minute-second.
var formattedDate = Utilities.formatDate(values[0][0], "GMT", "yyyy-MM-dd'T'HH:mm:ss'Z'");
Logger.log(formattedDate);
formattedDate = Utilities.formatDate(values[0][1], "GMT", "yyyy-MM-dd'T'HH:mm:ss'Z'");
Logger.log(formattedDate);
}
Logger.log output:
[19-01-31 11:43:17:635 GMT] Values: [[Thu Jan 31 09:00:00 GMT+00:00 2019, Wed Jan 02 09:00:00 GMT+00:00 2019]]
[19-01-31 11:43:17:636 GMT] Date().getMonth(): 0.0
[19-01-31 11:43:17:637 GMT] Date().getYear(): 2019.0
[19-01-31 11:43:17:638 GMT] 2019-01-31T09:00:00Z
[19-01-31 11:43:17:638 GMT] 2019-01-02T09:00:00Z

Apps Script - Formatting the current date for timestamp

I wish to format the current date as "yyyy/MM/dd HH:mm". formatDate allows me to format the date but I need to specify a timezone, per the following:
Utilities.formatDate(new Date(), "GMT", "yyyy/MM/dd HH:mm")
This is almost what I want, but I want the result to be BST or GMT, as appropriate to the calendar. What timezone should I specify to get the answer without further manipulation of the text date? (I do have a clumsy workaround). The problem caught me out with a timed batched process that runs at midnight upon our recent BST clock change where timestamps of 23:00 the previous day were applied.
In your script properties, make sure you've selected the correct time zone. Then, in your script, instead of using "GMT", use Session.getScriptTimeZone().
function test() {
var date1 = new Date("March 10, 2018 10:00");
var date2 = new Date("March 11, 2018 10:00");
Logger.log(date1); // Sat Mar 10 10:00:00 GMT-05:00 2018
Logger.log(Utilities.formatDate(date1, Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm")); // 2018/03/10 10:00
Logger.log(date2); // Sun Mar 11 10:00:00 GMT-04:00 2018
Logger.log(Utilities.formatDate(date2, Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm")); // 2018/03/11 10:00
}
In the script editor, go to File > Project properties and set your time zone. (I used Eastern time for mine.)

Utilities.formatDate returning wrong week number

In Google Script I have the following code:
var myDate = new Date(sheet.getRange(3,1).getValue());
var year = Utilities.formatDate(myDate, "Europe/Amsterdam", 'dd-MM-yyyy');
var weekyear = Utilities.formatDate(myDate, "Europe/Amsterdam", 'dd-MM-YYYY');
var week = Utilities.formatDate(myDate, "Europe/Amsterdam", 'w');
When I insert 30-12-2015 as date, the result will be.
// year: 30-12-2015
// weekyear: 30-12-201**6**
// week: 1
In my local timezone, it should be week number 53. Not 1.
If I calculate the week in ISO 8601, the result is 52.
Strange, isn't it?
Edited:
New attempt, with this code
var cursus_datum = sheet.getRange(3,1).getValue();
Logger.log('type of data: ' + typeof cursus_datum);
Logger.log(cursus_datum);
Logger.log(Utilities.formatDate(cursus_datum, SpreadsheetApp.getActive().getSpreadsheetTimeZone(), "d-MM-y HH:mm"));
Logger.log(Utilities.formatDate(cursus_datum, SpreadsheetApp.getActive().getSpreadsheetTimeZone(), "w"));
This results in
// type of data: object
// Wed Dec 30 09:00:00 GMT+01:00 2015
// 30-12-2015 00:00 which is perfect
// 1 which is **not** correct.
The wrong week is the bug.
The Utilities.formatDate documentation states that it uses Java SimpleDateFormat - I have a feeling this might be the cause of the problem as they are Locale sensitive and I would take a guess it will be using the default US locale (I don't think passing in the timezone changes the locale). The problem is the US locale calendar has getFirstDayOfWeek() = 1 (SUNDAY) and getMinimalDaysInFirstWeek() = 1. And for ISO 8601 you need the settings 2 and 4 respectively. I think you're better off sticking to the Javascript code you linked to if you want to work with week years.
new Date() will accept a few different parameter configurations, but you still need to make sure that the parameters are correct. You can't just plug anything into new Date() If the variable is already a date type, then there is no point using new Date(). You can test for the data type with typeof.
var dateFromSheet = sheet.getRange(3,1).getValue();
Logger.log('type of data: ' + typeof dateFromSheet);
If the data type is a string, it must be in a valid date string format. There are a few different formats. But, again, you need to use a valid format.
ISO 8601 syntax "YYYY-MM-DD" or "YYYY-MM" or "YYYY" or "YYYY-MM-DDTHH:MM:SS"
Long Date syntax - Year, month and day can be in any order: "Mar 7 2015" or "2015 Mar 7", and Month can be written in full: "2015 March 7"
Short dates - "/" or "-" can be used. "MM/DD/YYYY" or "YYYY/MM/DD" NOTE: You can not use "DD/MM/YYYY"
Full Date Format - "Wed Mar DD YYYY HH:MM:SS GMT+0100 (W. Europe Standard Time)"
This is what I did:
function getCurrentCalendarWeek(){
let date = new Date();
let weekNum = Utilities.formatDate(date, "Europe/Berlin", "w") - 1;
if (weekNum === 0){
weekNum = 1
}
return weekNum
}

Google SpreadSheet Custom Date Format

I'm looking for a easy formula to generate this type of Date Format:
10:35 PM August 12th 2013
hh:mm AM/PM Month dd yyyy
It's for the MarketMeSuite CSV scheduling utility that only excepts that format when uploading scheduled tweets.
Yes this format is possible using the Utilities.formatDate() utility. Please see Oracles Class SimpleDateFormat documentation for java as this uses the same formats. You should be able to get your desired format using the below formatting.
h:mm a MMMMM d yyyy
The only issues would be with the th or nd or rd or st after the date. But you could use some if statements to format that depending on the number, I'll let you work on that :)
The final string of the above would be -
9:16 PM April 15 2013
So the final date object creation would be.
Utilities.formatDate(new Date(), "GMT", "h:mm a MMMMM d yyyy")
EDIT
I've just realised you might not be talking about getting this format in a script but actually just calling it in a cell. If so you still need to create a custom function, so add the below code to a new script.
function getDate() {
var date = Utilities.formatDate(new Date(), "GMT", "h:mm a MMMMM d yyyy")
return date;
}
Then you can call it back in a cell with =getDate()