This question already has answers here:
concatenate date and time in google spreadsheet
(3 answers)
Closed 1 year ago.
I have my working hours in a Sheets document that I want to use to make Events in Calendar.
Following the tutorial:
https://cloud.google.com/blog/products/g-suite/g-suite-pro-tip-how-to-automatically-add-a-schedule-from-google-sheets-into-calendar
I have this script:
function scheduleShifts() {
/**
Task 1) Open the event calendar
**/
var spreadsheet = SpreadsheetApp.getActiveSheet();
var calendarId = spreadsheet.getRange("D1").getValue();
var eventCal = CalendarApp.getCalendarById(calendarId);
/** Task 2) Pull each shift information into the code, in a form that the code can understand
**/
var signups = spreadsheet.getRange("E2:F100").getValues();
/**
Create the calender entry
**/
for (x=0; x<signups.length; x++) {
var shift = signups[x];
eventName = "Work hours";
var startTime = shift[0];
var endTime = shift[1];
eventCal.createEvent(eventName, startTime, endTime); }
}
But, I get the error:
Exception: The parameters (String,String,String) don't match the method signature for CalendarApp.Calendar.createEvent.
scheduleShifts # Code.gs:24
Because I do not work everyday, there are blank cells in the data range from Sheets, could this be the issue?
And how can I ask the script to ignore those cells within that data range that are blank and NOT to create an event for them?
My work hours are provided with times and dates in seperate columns, so I used this Sheet formula to convert the data to DateTime format, and placed into new cells in columns E and F:
=IF(C2 <> "",concatenate(text(A2,"dd/mm/yyyy")&" "&text(C2,"hh:mm:ss")),"")
=IF(D2 <> "",concatenate(text(A2,"dd/mm/yyyy")&" "&text(D2,"hh:mm:ss")),"")
A
B
C
D
E
F
29/11/2021
man
13:30
22:30
29/11/2021 13:30:00
29/11/2021 22:30:00
30/11/2021
tir
01/12/2021
ons
02/12/2021
tor
09:30
16:42
02/12/2021 09:30:00
02/12/2021 16:42:00
03/12/2021
fre
09:30
16:42
03/12/2021 09:30:00
03/12/2021 16:42:00
04/12/2021
lør
05/12/2021
søn
06/12/2021
man
09:30
16:30
06/12/2021 09:30:00
06/12/2021 16:30:00
07/12/2021
tir
09:30
18:30
07/12/2021 09:30:00
07/12/2021 18:30:00
My understanding is using .getValues ignores the formula and only delivers the value of the cell, so I don't believe this to be the issue, but I thought I had better mention it for full disclosure.
The method is createEvent(String,Date,Date)
You are sending createEvent(String,String,String)
You need to parse your sting into a date.
// Creates an event for the moon landing and logs the ID.
var event = CalendarApp.getDefaultCalendar().createEvent('Apollo 11 Landing',
new Date('July 20, 1969 20:00:00 UTC'),
new Date('July 21, 1969 21:00:00 UTC'));
Logger.log('Event ID: ' + event.getId());
Related
Background Info
I have a maximum of 15 hours available for work Monday – Friday.
Each day, from Monday – Thursday, I will work a random amount of
hours between 0 – 8.
I can work 0 hours on Monday - Thursday.
On Friday, I will work whatever hours are left from the maximum of 15
hours available.
I must work at least 1 hour on Friday.
Formulas Used
(Cell: C4) Monday: RANDBETWEEN(0-8)
(Cell: D4) Tuesday: RANDBETWEEN(0-8)
(Cell: E4) Wednesday: RANDBETWEEN(0-8)
(Cell: F4) Thursday: RANDBETWEEN(0-8)
(Cell: G4) Friday: 15 – SUM(C4:F4)
Total Hours: SUM(C4:G4)
Issues
The Friday cell will occasionally receive a negative number of hours
worked.
Example Output of Issue
Output
Current Workaround
Update the values generated by RANDBETWEEN by pressing ‘DEL’ on an
empty cell. This forces all the values to change.
Repeat until a positive value is received in the cell for Friday
Google Sheet Settings
Goal
Have the cells update themselves automatically IF a negative value is received in the cell for Friday
Possible Solution/Thoughts
Is there a way to force RANDBETWEEN numbers to update via a formula?
If yes, is there a way to setup a WHILE loop that will update the
RANDBETWEEN values UNTIL the cell for Friday has a positive number?
Is there a way to have a script run on specific cells? The intent is to simulate data for variations on a work schedule.
I did try to accomplish this via a script but wasn’t able to get the cells to update correctly and other times it would not update at all.
function randomTotal()
{
var Monday = SpreadsheetApp.getActiveSheet().getRange('C4');
var Tuesday = SpreadsheetApp.getActiveSheet().getRange('D4');
var Wednesday = SpreadsheetApp.getActiveSheet().getRange('E4');
var Thursday = SpreadsheetApp.getActiveSheet().getRange('F4');
var Friday = SpreadsheetApp.getActiveSheet().getRange('G4');
var FridayValue = SpreadsheetApp.getActiveSheet().getRange('G4').getValue();
while(FridayValue < 0)
{
newTotal(Monday,Tuesday,Wednesday,Thursday,Friday);
FridayValue = SpreadsheetApp.getActiveSheet().getRange('G4').getValue();
}
}
function newTotal(Monday,Tuesday,Wednesday,Thursday,Friday)
{
Monday.setFormula('=RANDBETWEEN(0,8)');
Tuesday.setFormula('=RANDBETWEEN(0,8)');
Wednesday.setFormula('=RANDBETWEEN(0,8)');
Thursday.setFormula('=RANDBETWEEN(0,8)');
Friday.setFormula('=15-SUM(C4:F4)');
}
This can actually be accomplished without Google Apps Script. I would suggest the following formulas for cell D4
=RANDBETWEEN(0,IF(SUM($C4:C4)<=6,8,14-SUM($C4:C4)))
You can then copy/paste this from D4 into E4 and F4 (the formula references will work), and keep C4 and G4 as is. That should do the trick!
You absolutely can accomplish this programmatically, but in general, if it's possible to do without, that's usually the simpler approach.
For a quick explanation of why this works: if the cells to the left sum to <=6, then you can always add up to 8 hours, because it leaves you in the range of <= 14 total. But, if that's not the case, you want to subtract however many hours you already have from 14, as 14 is the max you can have on Mon - Thurs, and get the remaining of at least 1 on Friday.
While majorly overcomplicated given the other answer provided, I did go in and create a script for this.
Here is the code:
function setSame() {
console.log('Start check');
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetMaster = ss.getSheetByName("Sheet2");
var sortRange = sheetMaster.getRange('B3:E3');
var forms = ['=RANDBETWEEN(0,8)','=RANDBETWEEN(0,8)','=RANDBETWEEN(0,8)','=RANDBETWEEN(0,8)'];
sortRange.setValues([forms]);
var mon = sheetMaster.getRange('B3').getValue();
sortRange.getCell(1,1).setValue(mon);
var tues = sheetMaster.getRange('C3').getValue();
sortRange.getCell(1,2).setValue(tues);
var wed = sheetMaster.getRange('D3').getValue();
sortRange.getCell(1,3).setValue(wed);
var thurs = sheetMaster.getRange('E3').getValue();
sortRange.getCell(1,4).setValue(thurs);
var fri = sheetMaster.getRange('F3').getValue();
console.log('Monday: '+mon);
console.log('Tuesday: '+tues);
console.log('Wednesday: '+wed);
console.log('Thursday: '+thurs);
console.log('Friday: '+fri);
if(fri < 1) {
console.log("less");
setSame();
}
}
Sheet
The setSame() function is set up with an onChange trigger (Triggers > Add Trigger). The console.log() lines are there for debugging purposes, and are not necessary.
I am sure there are better ways to go about this with a script, but this was the quickest way I could think to solve this.
Context
I have an RESTful API built with Google App Script on a Google Sheet. One of the doGet() requests will retrieve data from one of the sheet tabs stored in a traditional column/row (database-like) fashion (structure described later). Simply, the doGet() will evoke another function to get the data, then it will encode that data into JSON response for the client.
The Data in the Sheet
This is what the data looks like on the sheet.
DATE
LOCATION
SHIFT
NAME
START
END
4-1-2021
WP
KANTOOR I
Danny
9:00
17:00
4-1-2021
BK
BAKKERIJ I
Naomi
9:00
17:00
4-1-2021
CK
KOK I
Fidel
7:00
16:00
...
...
...
...
...
...
The Google App Script Function
The function iterates over the table above and gets the the row that matches the name passed into the function against the name in the NAME column.
function getContactSchedule(name) {
var payload = { schedule: [] };
var rows = scheduleSheet // schedule sheet is the .getSheetByName() for the above sheet
.getRange(2, 1, scheduleSheet.getLastRow(), scheduleSheet.getLastColumn())
.getValues();
for (var i = 0, l = rows.length; i < l; i++) {
var shift = { date: null, location: null, shift: null, name: null, start: null, end: null };
const scheduleItem = rows[i];
if (name != scheduleItem[3]) continue;
shift.date = scheduleItem[0];
shift.location = scheduleItem[1];
shift.shift = scheduleItem[2];
shift.name = scheduleItem[3];
shift.start = scheduleItem[4];
shift.end = scheduleItem[5];
shift.index = i;
// add to payload.
payload.schedule.push(shift);
}
return payload;
}
Problem
When I get the data in the table and convert it to the Object, I see different timestamps than store (other the timezone or epoch difference).
Here is some driver code:
function testGetContactSchedule() {
var data = getContactSchedule('Danny')['schedule'];
console.log(data[0]);
}
Output:
{ date: Sun Jan 03 2021 16:00:00 GMT-0700 (Mountain Standard Time),
location: 'WP',
shift: 'KANTOOR I',
name: 'Danny',
start: Sat Dec 30 1899 01:40:28 GMT-0700 (Mountain Standard Time),
end: Sat Dec 30 1899 09:40:28 GMT-0700 (Mountain Standard Time),
canUpdate: true,
index: 0 }
The first row of the table is the same data here, just converted into the JS Object. But the time difference is unusual.
DATE
LOCATION
SHIFT
NAME
START
END
4-1-2021
WP
KANTOOR I
Danny
9:00
17:00
Question
Why is there this unusual difference in time? As if it adds about 40 minutes to the time stamp rather than the 00:00 that I think I'm expecting?
The reason you are receiving the date Sat Dec 30 1899 01:40:28 GMT-0700 is because getValues returns an object of type date. However, this object is adapted from Sheets - 12/30/1899 0:00:00 representing the zero mark of time for it.
Therefore, a solution for this is to use getDisplayValues instead of getValues. This will end up returning the actual values displayed in Sheets.
Reference
Apps Script Class Range - getDisplayValues().
dates are always a bit complex in JS.
You can try this script, it worked for me. You can change the format of the date and also the time zone.
const sheet = SpreadsheetApp.openById("ZZZZZZZ");
const data = sheet.getSheetByName("XXX").getDataRange().getValues();
function getData(){
data.forEach(dates => {
var date = Utilities.formatDate(new Date(dates), "GMT+2", "MM/dd/yyyy");
console.log(date);
})
}
Sheet:
Output:
I am trying to write a small Google Script which takes data from some cells of Google Sheet and Paste it in the GMAIL.
However, while pasting the 'Date Values' it always displays it in the following manner:-
Mon Apr 15 2019 00:00:00 GMT+0530 (IST)
Fri Apr 26 2019 00:00:00 GMT+0530 (IST)
But I need the dates in an appropriate way i.e.
"Mon Apr 15 2019" or
"Fri 04/26/2019"
I gone through these possible options i.e. Utilities.formatDate & .Split but somehow I am not able to write these codes appropriately. Can you please help me with this matter. Below I have mentioned the entire issue in detail.
My Code
function temp2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheetByName('Sheet1');
var templateSheet = ss.getSheetByName('Sheet2');
var emailTemplate2 = templateSheet.getRange("G1").getValue();
var rec = templateSheet.getRange("C1").getValue();
var sub = templateSheet.getRange("D1").getValue();
var date = templateSheet.getRange("E1").getValue();
// Logger.log(rec);
MailApp.sendEmail(rec, sub, emailTemplate2);
}
here var date = templateSheet.getRange("E1").getValue(); is the part of code which picks value of date.
Do let me know if you need more details in this regard
Regards,
Alok
Requirement:
Format date value from cell in Google Apps Script.
Solution:
Pass value to date constructor new Date() then format using Utilities.formatDate().
// pass date to date constructor
var date = new Date(templateSheet.getRange("E1").getValue());
// "Mon Apr 15 2019" example
var formattedDate = Utilities.formatDate(date, "GMT+0", 'E MMM dd yyyy');
// "Fri 04/26/2019" example
var formattedDate = Utilities.formatDate(date, "GMT+0", 'E MM/dd/yyyy');
Note: I've set this to timezone "GMT+0" by default, you can change this to whichever time zone you need.
References:
new Date() for date constructor.
Utilities.formatDate() for formatting dates in Google Apps Script.
SimpleDateFormat for date format strings.
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
I'm trying to write a script which is supposed to send out an email and create two calender entries when submitting a form. To be honest, this is my first script and I am very happy that the email is send out and the calender entries are working as well. The thing which gives me a headache is to subtract 5 days (actually x days) from a defined date.
First I thought I could simply do something like
var liveday = e.values[2];
var newday = liveday-5;
well, this didn't work :-)
I tried more:
var newtime = new Date(liveday);
var yr = newtime.getYear();
var dt = newtime.getDay();
var mt = newtime.getMonth();
var dtnew = dtnew.setDate(mt, dt-5, yr);
But here I received 1418256000000 whereas liveday = 12/01/2014. Not sure why days were added, rather than subtracted.
I am quite confused here and the answer can't be that hard.
I just want to subtract 5 days from 12/01/2014 to receive 11/27/2014.
Thanks for having a look
the comment sends you to a rather complicated serie of codes... there is a far more simple way to get that, here is the code :
function test() {
Logger.log('today= '+new Date()+' and 5 days ago is '+subDaysFromDate(new Date(),5));
}
function subDaysFromDate(date,d){
// d = number of day ro substract and date = start date
var result = new Date(date.getTime()-d*(24*3600*1000));
return result
}
Logger result :
[13-11-18 23:39:50:364 CET] today= Mon Nov 18 2013 23:39:50 GMT+0100 (CET) and 5 days ago is Wed Nov 13 2013 23:39:50 GMT+0100 (CET)
if you want to get the date in the form dd/mm/yyyy use Utilities.formatDate(date, timeZone, 'dd/MM/yyyy), see doc here