Google Sheet -> Calendar -- Create Events with CalID - google-sheets

I have a giant spreadsheet to create student schedules. I've summarized all of the event information in one tab (see screenshot). The current Script I'm using creates a NEW calendar with the events. I just want it to add the events to an already pre-created calendar.
enter image description here
/**
* Creates a Google Calendar with events for each conference session in the
* spreadsheet, then writes the event IDs to the spreadsheet for future use.
* #param {Array<string[]>} values Cell values for the spreadsheet range.
* #param {Range} range A spreadsheet range that contains conference data.
*/
function setUpCalendar_(values, range) {
let cal = CalendarApp.createCalendar('Conference Calendar 2');
// Start at 1 to skip the header row.
for (let i = 1; i < values.length; i++) {
let session = values[i];
let title = session[0];
let start = joinDateAndTime_(session[1], session[3]);
let end = joinDateAndTime_(session[1], session[4]);
let options = {location: session[5], sendInvites: true};
let event = cal.createEvent(title, start, end, options)
.setGuestsCanSeeGuests(false);
session[6] = event.getId();
}
range.setValues(values);
// Stores the ID for the Calendar, which is needed to retrieve events by ID.
let scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty('calId', cal.getId());
}
/**
* Creates a single Date object from separate date and time cells.
*
* #param {Date} date A Date object from which to extract the date.
* #param {Date} time A Date object from which to extract the time.
* #return {Date} A Date object representing the combined date and time.
*/
function joinDateAndTime_(date, time) {
date = new Date(date);
date.setHours(time.getHours());
date.setMinutes(time.getMinutes());
return date;
}

Try replacing the CalendarApp.createCalendar() call with CalendarApp.getCalendarById().

Related

How do I conditionally highlight dates within a start and end date range based on individual date rows?

so I have this workbook that I am trying to figure out how to manage in a more automated way.
I have 2 main sheets. In 'Sheet2' there are 4 columns (Item, Sub-Item, Start, End). In 'Sheet1' there is similar data just formatted differently. Each valid permutation of Item and Sub-Item is already listed and the dates are expanded. Under each permutation of item/subitem I want to be able to enter 'True' if the date is affected and have it highlight any matching affected rows in 'Sheet2'. To be a match it needs to match the Item and Sub-Item and have a highlighted date that falls within the date range (exclusive of the End date) in 'Sheet2'. It doesn't have to be done in google sheets, it could also be done in excel if that makes it any easier or different.
I've linked a sample sheet below. Hopefully that helps clear up any questions.
https://docs.google.com/spreadsheets/d/1Smsxr5_qsj0hLhc5oIJHsX-ISpB9p66vc1z4wOd3CNk/edit
Try this:
Here I created an onEdit Trigger that will execute a function whenever an edit in Sheet was made and used its property to determine the item, sub-item, and date. Then compare it to each row in Sheet2. I added comment to each line of code to explain the process.
Code:
function isInBetween(t, s, e){
let target = new Date(t); //convert target date to date format
let start = new Date(s); //convert start date to date format
let end = new Date(e); //convert end date to date format
if(target.getTime() >= start.getTime() && target.getTime() < end.getTime()){ // check if target date is in between of start and end -1
return true;
}else{
return false;
}
}
function onEdit(e) {
let spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
let range = e.range; //get the range of edited cell
let sheet = range.getSheet() //get the sheet of edited cell
let row = range.getRow(); //get the row of edited cell
let column = range.getColumn(); //get the column of edited cell
if(row > 5 && column > 1 && column < 7 && sheet.getName() == 'Sheet1' && e.value == 'TRUE'){ //check whether the edited cell is in the editable range in sheet1
let sheetItem = sheet.getRange(1, column).getDisplayValue(); //get the corresponding item of the edited cell
let sheetSubItem = sheet.getRange(4, column).getDisplayValue(); //get the corresponding sub item of the edited cell
let dateToCheck = sheet.getRange(row, 1).getDisplayValue(); //get the date of edited cell
let sheet2 = spreadsheet.getSheetByName('Sheet2');
let data = sheet2.getRange(2, 1, sheet2.getLastRow()-1, 4).getDisplayValues(); //get all values in sheet2
data.forEach(function(row, i) { //iterate each values in sheet2
let sheet2Item = row[0]; //get the item in sheet2
let sheet2SubItem = row[1]; //get the sub item in sheet2
let start = row[2].replace(new RegExp('-', 'g'), '/'); //replace the '-' of start date with '/'
let end = row[3].replace(new RegExp('-', 'g'), '/'); //replace the '-' of end date with '/'
if(sheetItem == sheet2Item && sheetSubItem == sheet2SubItem && isInBetween(dateToCheck, start, end)){ // this will check if the item, subitem of sheet1 matches in sheet2, this will also check if the date is in between
sheet2.getRange(i+2, 1, 1, 4).setBackground("#b7e1cd"); //change the color of affected row in sheet2 to green
}
})
}
}
Demo:
References:
Simple Trigger
Google Apps Script
Event Object
Class Range
Class Sheet
Class Spreadsheet

Using GSheets Script to increment value of duplicate by 1

I want to check a row for duplicates and if match increment these by 1.
The data I want to manipulate this way is LAT LONG Coordinates.
They originate from an aggregated data acquisition, where users can only insert country and city. Via an Add-On these will get GEO coded.
Problem is, that I need to slightly change the values of duplicate entries, in order to display them on a map. Easiest way (I think) is to increment a LAT or LONG coordinate by 1 if there is already an entry with the same value.
Data sample & results of script
Any idea how to do this via Script?
My code, originally intended to delete duplicate rows:
function overwriteDuplicates() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName("Formularantworten 2");
var vA=sh.getDataRange().getValues();
var hA=vA[0];
var hObj={};
hA.forEach(function(e,i){hObj[e]=i;});//header title to index
var uA=[];
var d=0;
for(var i=0;i<vA.length;i++) {
if(uA.indexOf(vA[i][hObj['Latitude']])==-1) {
uA.push(vA[i][hObj['Latitude']]);
}else{
function increment() {
SpreadsheetApp.getActiveSheet().getRange('K').setValue(SpreadsheetApp.getActiveSheet().getRange('K').getValue() + 1);
}
}}}
You want to modify the latitude whenever duplicate coordinates (latitude and longitude is found).
In this case, you can do the following:
Get all the values in the sheet, and retrieve the indexes where Latitude and Longitude are, based on the headers.
Loop through all rows (excluding headers), and for each row, check whether a previous row contains these coordinates.
If that's the case (isDuplicate), increment the last number in the latitude (after the last .), or decrement it if it's close to 999 (I assume there's always 3 digits).
Store the new latitude in an array after modification.
Use setValues to write the modified latitudes to the sheet.
Below is a possible code snippet to do this (see inline comments for details).
Code snippet:
function overwriteDuplicates() {
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName("Formularantworten 2");
const values = sheet.getDataRange().getValues();
const headers = values.shift(); // Retrieve first row (headers)
const latColumn = headers.indexOf("Latitude"); // Latitude column index
const longColumn = headers.indexOf("Longitude"); // Longitude column index
let outputLocations = [];
for (let i = 0; i < values.length; i++) { // Loop through rows
const newLocation = { // Store object with current location
"latitude": values[i][latColumn],
"longitude": values[i][longColumn]
}
let isDuplicate;
do { // Check if location is duplicate, and increment if necessary
isDuplicate = outputLocations.some(location => {
const sameLatitude = location["latitude"] === newLocation["latitude"];
const sameLongitude = location["longitude"] === newLocation["longitude"];
return sameLatitude && sameLongitude;
});
if (isDuplicate) newLocation["latitude"] = modifyCoord(newLocation["latitude"]);
} while (isDuplicate);
outputLocations.push(newLocation); // Store new location in array
}
let outputLatitudes = outputLocations.map(location => [location["latitude"]]); // Retrieve latitudes from array
sheet.getRange(2, latColumn+1, sheet.getLastRow()-1).setValues(outputLatitudes); // Write updated latitudes to sheet
}
function modifyCoord(coordinates) {
let coordArray = coordinates.split(".");
let lastCoord = coordArray.pop();
if (lastCoord > 990) lastCoord--;
else lastCoord++;
coordArray.push(lastCoord);
return coordArray.join(".");
}
Output:

Google docs to google sheets script

I’m using Google Sheets to conduct some text analysis. I would like to automate the process by linking a spreadsheet to a Google doc file on my GDrive to extract text directly. It doesn’t have to structured/formatted. It just has to be a plain text. Does it take a comprehensive scripting or the task of copying text is simple?
I searched the web but couldn’t find one.
To help you start, here is an SO thread.
Same scenario: Get data from the Google Sheets and copy it to the Google Docs.
A reference from Open Source Hacker: Script for generating Google documents from Google spreadsheet data source.
Here is the code provided in the article. You can modify it by yourself depending on your use.
/**
* Generate Google Docs based on a template document and data incoming from a Google Spreadsheet
*
* License: MIT
*
* Copyright 2013 Mikko Ohtamaa, http://opensourcehacker.com
*/
// Row number from where to fill in the data (starts as 1 = first row)
var CUSTOMER_ID = 1;
// Google Doc id from the document template
// (Get ids from the URL)
var SOURCE_TEMPLATE = "xxx";
// In which spreadsheet we have all the customer data
var CUSTOMER_SPREADSHEET = "yyy";
// In which Google Drive we toss the target documents
var TARGET_FOLDER = "zzz";
/**
* Return spreadsheet row content as JS array.
*
* Note: We assume the row ends when we encounter
* the first empty cell. This might not be
* sometimes the desired behavior.
*
* Rows start at 1, not zero based!!! 🙁
*
*/
function getRowAsArray(sheet, row) {
var dataRange = sheet.getRange(row, 1, 1, 99);
var data = dataRange.getValues();
var columns = [];
for (i in data) {
var row = data[i];
Logger.log("Got row", row);
for(var l=0; l<99; l++) {
var col = row[l];
// First empty column interrupts
if(!col) {
break;
}
columns.push(col);
}
}
return columns;
}
/**
* Duplicates a Google Apps doc
*
* #return a new document with a given name from the orignal
*/
function createDuplicateDocument(sourceId, name) {
var source = DocsList.getFileById(sourceId);
var newFile = source.makeCopy(name);
var targetFolder = DocsList.getFolderById(TARGET_FOLDER);
newFile.addToFolder(targetFolder);
return DocumentApp.openById(newFile.getId());
}
/**
* Search a paragraph in the document and replaces it with the generated text
*/
function replaceParagraph(doc, keyword, newText) {
var ps = doc.getParagraphs();
for(var i=0; i<ps.length; i++) {
var p = ps[i];
var text = p.getText();
if(text.indexOf(keyword) >= 0) {
p.setText(newText);
p.setBold(false);
}
}
}
/**
* Script entry point
*/
function generateCustomerContract() {
var data = SpreadsheetApp.openById(CUSTOMER_SPREADSHEET);
// XXX: Cannot be accessed when run in the script editor?
// WHYYYYYYYYY? Asking one number, too complex?
//var CUSTOMER_ID = Browser.inputBox("Enter customer number in the spreadsheet", Browser.Buttons.OK_CANCEL);
if(!CUSTOMER_ID) {
return;
}
// Fetch variable names
// they are column names in the spreadsheet
var sheet = data.getSheets()[0];
var columns = getRowAsArray(sheet, 1);
Logger.log("Processing columns:" + columns);
var customerData = getRowAsArray(sheet, CUSTOMER_ID);
Logger.log("Processing data:" + customerData);
// Assume first column holds the name of the customer
var customerName = customerData[0];
var target = createDuplicateDocument(SOURCE_TEMPLATE, customerName + " agreement");
Logger.log("Created new document:" + target.getId());
for(var i=0; i<columns.length; i++) {
var key = columns[i] + ":";
// We don't replace the whole text, but leave the template text as a label
var text = customerData[i] || ""; // No Javascript undefined
var value = key + " " + text;
replaceParagraph(target, key, value);
}
}

starttime changes on CalendarRule when I insert it into work hours in CRM

When I submit a CalendarRule to CRM's work hours, the StartTime changes just before it is submitted to the database. I submit the CalendarRule through the code below. The submitted StartTime differ by -2 hours. I suspect this has something to do with the fact that I live in +1 GMT timezone and our clocks are set to dayligt time savings.
var calendarFrequenceRule = new CalendarRule
{
Duration = 24 * 60, //24 hours
ExtentCode = 1,
StartTime = start.Date,
Pattern =
new CalendarRulePattern
{
ByDay = new List<DayOfWeek> {start.DayOfWeek},
Interval = 1,
Frequency = CalendarRulePattern.FrequencyEnum.WEEKLY
}.ToString(),
Rank = 0,
TimeZoneCode = userSettings.TimeZoneCode,
InnerCalendarId = new EntityReference(Calendar.EntityLogicalName, innerCalendarId),
};
calendarRules.Clear();
calendarRules.Add(calendarFrequenceRule);
userCalendarEntity.CalendarRules = calendarRules;
OrganizationService.Update(userCalendarEntity);
var calendarTimeRule = new CalendarRule
{
//Name = name,
//Description = name,
Duration = (int)(end - start).TotalMinutes,
Effort = 1.0,
IsSimple = true,
Offset = (int)(start - start.Date).TotalMinutes,
Rank = 0,
TimeCode = (int)TimeCode.Available,
SubCode = (int)SubCode.Schedulable,
TimeZoneCode = -1,
CalendarId = new EntityReference(Calendar.EntityLogicalName, innerCalendarId),
};
calendarRules.Add(calendarTimeRule);
newInnerCalendar.CalendarRules = new List<CalendarRule> {calendarTimeRule};
OrganizationService.Update(newInnerCalendar);
When I retrieve the time again through the code below the time is off by 4 hours. I've checked that all users have their time zone settings set to the same time zone - but to no avail. When I look at the database I can see that the time zone submitted through code is the same as the calendar rules I've insert through the GUI.
Code to retrieve the CalendarRule:
var user = OrganizationService.Retrieve<SystemUser>(userId);
var expandCalendarRequest = new ExpandCalendarRequest
{
CalendarId = user.CalendarId.Id,
Start = start,
End = end,
};
var response = OrganizationService.Execute<ExpandCalendarResponse>(expandCalendarRequest);
return response.result;
Anytime you insert a DateTime into CRM using the SDK or the Odata endpoint, it assumes that it's UTC. If you update a field via javascript, it will assume it's in the time of the current users. I'm not sure what case you're currently working with, but always work with UTC unless you're editing fields in the actual form.
See this answer: https://stackoverflow.com/a/22787954/227436 for an overview of working with Time in CRM.
This answer has a function that maybe useful in your case as well:
https://stackoverflow.com/a/11367508/227436

Not able to read the time from native calendar event

I have created a appoitment for particular date and time in Blackberry calendar,i am trying to read date and time using the following code,but its showing the error.
private void getEvents() {
try {
EventList eventList = (EventList)PIM.getInstance().openPIMList(PIM.EVENT_LIST, PIM.READ_ONLY);
Enumeration events = eventList.items();
while (events.hasMoreElements()) {
Event event = (Event)events.nextElement();
if(eventList.isSupportedField(Event.ALARM) && event.countValues(Event.ALARM) > 0) {
long alarm = event.getDate(Event.ALARM, 0);
System.out.println(alarm);
}
}
}
i am not sure what is wrong in if loop
The field Event.ALARM contains:
Field specifying a relative time for an Alarm for this Event. Data for
this field is expressed with an INT data type. The alarm is expressed
in seconds and derived by subtracting the alarm value from every
date/time occurrence of this Event. For example, if this field has a
value of 600, then the alarm first occurs 600 seconds before the
date/time value specified by Event.START. For re-occurrences of the
event, the alarm is calculated by subtracting the stored value from
the date/time of the specific event occurrence.
So you need to get the value from the field Event.START for the Date/Time of the Event start. You can then subtract the value of Event.ALARM (as seconds) from the start Date/Time to get the time for any requested reminder.
long start = event.getDate(Event.START);
int alarm = event.getDate(Event.ALARM);
if (alarm > 0) {
long reminderTime = start - (long)alarm * 1000L;
...
}
SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy HH:mm");
String dateString = sdf.formatLocal(start);

Resources