The main issue that you might struggle with is probably due to the relative slowness of the calendar service.
Even if Mogsdad code is well written and probably as efficient as possible it won't be able to copy a big amount of event in one batch because of the 5' time limit.
I've been dealing with calendars for a long time and that has always been a real concern...
So my idea was to handle the process in 2 times, a "backup" that writes all the events into a spreadsheet for storage, that's fairly simple and straightforward... and a "restore" function that reads the spreadsheet and copies the events in a calendar.
The nice trick is that you can copy these calendar data to another calendar and that's where it becomes interesting for your use case ! you can indeed restore all the events in any other domain calendar as long as you have write rights on it.
This script has been used on very large sets of data (more than 3000 events in a one year period) and worked pretty well. I use it to duplicate calendars so I have 'test copies' where I can do all sort of other experiments without touching the 'real ones'.
The script is very long and is not well documented (I didn't write it for this post ;-) but feel free to give it a try by adding it to a spreadsheet. The UI is in french (another bad idea for this forum, sorry about that) but any translator will help you to customize it your way if necessary (if ever you decide to use it). Anyway it uses very simple words and I'm sure anyone would understand it without effort.
Here it is :
(please note that you can select more than one calendar in the backup process)
var FUS1=new Date().toString().substr(25,6)+":00";
var tz = SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone();
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [
{name: "Backup des agendas", functionName: "backup"},
{name: "Restauration d'un agenda", functionName: "restore"},
];
ss.addMenu("Fonction Tech.", menuEntries);
}
function backup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle("Sauvegarde des agendas en feuilles Google");
app.setHeight(325).setWidth(420);
// Create a grid with 3 text boxes and corresponding labels
var grid = app.createGrid(4, 2);
var wait = app.createImage('https://dl.dropboxusercontent.com/u/211279/loading3.gif').setVisible(false);
grid.setWidget(0, 0, app.createLabel("Nom des agendas à sauvegarder :"));
var list = app.createListBox(true).setVisibleItemCount(5);
list.setName('calendar');
grid.setWidget(0, 1, list);
var calendars = CalendarApp.getAllCalendars();
for (var i = 0; i < calendars .length; i++) {
list.a
list.addItem(calendars[i].getName());
}
grid.setWidget(1, 0, app.createLabel('Date début :'))
.setWidget(2, 0, app.createDateBox().setId("start").setValue(new Date('2013/09/01')))
.setWidget(1, 1, app.createLabel('Date fin :'))
.setWidget(2, 1, app.createDateBox().setId("end").setValue(new Date('2014/07/30')))
var button = app.createButton('Confirmer');
var handler = app.createServerClickHandler('bkpToSheet');
handler.addCallbackElement(grid);
var cHandler = app.createClientHandler().forTargets(wait).setVisible(true);
button.addClickHandler(handler).addClickHandler(cHandler);
grid.setWidget(3, 0,button).setWidget(3, 1, wait);
app.add(grid);
doc.show(app);
}
function bkpToSheet(e){
var app = UiApp.getActiveApplication();
var calNames = e.parameter.calendar.split(',');
var name = 'BACKUP-AGENDAS-DU-'+Utilities.formatDate(new Date(), FUS1, 'dd-MM-yyyy@HH/mm').replace('/','h')+'-'+calNames.join('&');
var ss = SpreadsheetApp.create(name)
ss.setSpreadsheetTimeZone(tz);
var ssId = ss.getId();
try{var bkpFolder = DocsList.getFolder('Backup agendas')}
catch(err){var bkpFolder = DocsList.createFolder('Backup agendas')}
DocsList.getFileById(ssId).addToFolder(bkpFolder);
DocsList.getFileById(ssId).removeFromFolder(DocsList.getRootFolder());
for(n=0;n<calNames.length;++n){
var sh = ss.insertSheet(calNames[n]);
//Logger.log(calNames[n])
var eventArray = [];
var startDate = new Date(e.parameter.start);
var endDate = new Date(e.parameter.end);
var Calendar = CalendarApp.getCalendarsByName(calNames[n]);
var events = Calendar[0].getEvents(startDate , endDate);
if (events[0]){
var line = new Array();
for (i = 0; i < events.length; i++) {
line = new Array();
var guestList = events[i].getGuestList(false);
var guests = [];
var guestsName = []
for(g=0;g<guestList.length;++g){
guests.push(guestList[g].getEmail());
guestsName.push(guestList[g].getName());
}
FUS1=events[i].getStartTime().toString().substr(25,6)+":00";
var title = events[i].getTitle()
line.push(title);
line.push(Utilities.formatDate(events[i].getStartTime(), FUS1, 'yyyy/MM/dd HH:mm:ss'));
line.push(Utilities.formatDate(events[i].getEndTime(), FUS1, 'yyyy/MM/dd HH:mm:ss'));
line.push(events[i].getLocation());
line.push(events[i].getCreators());
line.push(guests.join(','))
line.push(guestsName.join(','))
line.push((events[i].getEndTime() - events[i].getStartTime()) / 3600000);
line.push(events[i].getDescription())
eventArray.push(line);
}
}
var titre = ["Backup de l'Agenda de "+calNames[n],'Début ','Fin','Lieu/ressources','Créateur','invités (lien)','invités (nom)','durée','description'];
eventArray.unshift(titre);
sh.getRange(1,1,eventArray.length,eventArray[0].length).setValues(eventArray);
}
ss.setActiveSheet(ss.getSheets()[0]);
var delSheet = ss.deleteActiveSheet(); // delete first empty sheet
var app = UiApp.getActiveApplication();
app.close();
return app;
}
function restore(){
ScriptProperties.setProperty('restorePointers',[0,0].join('@'))
var app = UiApp.createApplication().setTitle("Restauration d'agenda à partir des BACKUPS Google Spreadsheets");
app.setHeight(225).setWidth(780);
var doc = SpreadsheetApp.getActiveSpreadsheet();
var waitR = app.createImage('https://dl.dropboxusercontent.com/u/211279/loading3T.gif').setId('waitR').setVisible(false);
var wait = app.createImage('https://dl.dropboxusercontent.com/u/211279/loading3.gif').setId('wait').setVisible(false);
var handlerContinueRestore = app.createServerHandler('continueRestore');
var handlerCancelRestore = app.createServerHandler('cancelRestore');
var cliHandlerContinue = app.createClientHandler().forEventSource().setEnabled(false).setHTML('Merci, reprise de la restauration').forTargets(waitR).setVisible(true);
var cont = app.createButton('continuer la restauration',handlerContinueRestore).setId('continue')
.setStyleAttributes({'fontSize':'12px', padding:'5px', borderRadius:'4px 4px 4px 4px',borderColor:'#ff0000',borderWidth:'2px'}).addClickHandler(cliHandlerContinue);
var cancel = app.createButton("Annuler la restauration.", handlerCancelRestore).setId('cancel')
.setStyleAttributes({'fontSize':'12px', padding:'5px', borderRadius:'4px 4px 4px 4px',borderColor:'#ff0000',borderWidth:'2px'});
var msgHTML = app.createHTML().setId('msgHTML').setStyleAttributes({'fontSize':'12px', 'padding':'25px', 'borderRadius':'4px 4px 4px 4px','borderColor':'#ff0000','borderWidth':'2px'});
var popPanel = app.createVerticalPanel().setPixelSize(587,137).setId('popPanel').setStyleAttributes({background:'#ffffcc',padding:'25px', borderRadius:'12px 12px 12px 12px',borderColor:'#ff0000',borderWidth:'1px'}).setVisible(false);
var popGrid = app.createGrid(2,3).setWidth('500');
popPanel.add(msgHTML).add(popGrid);
popGrid.setWidget(0,0,cont).setWidget(0,1,cancel).setWidget(0, 2, waitR);
var cHandler = app.createClientHandler().forTargets(wait).setVisible(true);
var wHandler = app.createClientHandler();
var grid = app.createGrid(5, 2).setId('grid').addClickHandler(wHandler);
var dateHandler = app.createServerHandler('restoreDate').addCallbackElement(grid);
var chkGrid = app.createGrid(1, 7);
chkGrid.setText(0, 0, 'ressources/invités à restaurer :')
.setWidget(0, 1, app.createCheckBox('@salles').setName('salles'))
.setWidget(0, 2, app.createCheckBox('#cours').setName('cours'))
.setWidget(0, 3, app.createCheckBox('profs').setName('profs'))
.setWidget(0, 4, app.createCheckBox('Dates partielles').setName('dates').addClickHandler(dateHandler).addClickHandler(cHandler));
var list = app.createListBox().setName('bkpname').addItem('- - -');
var listS = app.createListBox().setName('sourceCal').addItem('- - -');
var listD = app.createListBox().setName('targetCal').addItem('- - -');
grid.setText(0, 0, "Backup à utiliser :");
grid.setWidget(0, 1, list);
grid.setText(1, 0, "Agenda de la feuille (source) :");
grid.setWidget(1, 1, listS);
grid.setText(2, 0, "Agenda cible(destination) :");
grid.setWidget(2, 1, listD);
var bkps = DocsList.find('BACKUP-AGENDAS-DU-');
var bkpList = [];
for(n=0;n<bkps.length;++n){
//Logger.log(bkps[n].getName()+' '+bkps[n].getId())
if(bkps[n].getName().indexOf('BACKUP-AGENDAS-DU-')>-1){
list.addItem(bkps[n].getName(),bkps[n].getId())
}
}
var calendars = CalendarApp.getAllCalendars();
for (var i = 0; i < calendars .length; i++) {
listS.addItem(calendars[i].getName(),calendars[i].getId());
listD.addItem(calendars[i].getName(),calendars[i].getId());
}
var dateDeb = app.createListBox().setId('dateDeb').setName('dateDeb').setVisible(false).addChangeHandler(dateHandler).addItem('première date disponible','xxxxxxxxxx');
var dateFin = app.createListBox().setId('dateFin').setName('dateFin').setVisible(false).addChangeHandler(dateHandler).addItem('dernière date disponible','xxxxxxxxxx');
var button = app.createButton('Confirmer').setId('button');
var msg = app.createButton("cette opération peut être longue... veuillez patienter et attendre la disparition de cette fenêtre<BR>Vous pouvez voir la progression dans le bas de l'écran (date et nombre / total) "
+"<BR>ou interrompre la restauration en cliquant ici.",handlerCancelRestore).setVisible(false).setId('msg').setStyleAttributes({'fontSize':'12px', padding:'25px',background:'#ffffff',borderWidth:'0px'});
var handler = app.createServerClickHandler('restoreCal');
handler.addCallbackElement(grid);
var cHandler = app.createClientHandler().forEventSource().setVisible(false).forTargets(wait,msg).setVisible(true).forTargets(dateDeb,dateFin).setEnabled(false);
// var msgHandler = app.createClientHandler().forTargets(msg).setVisible(true).forTargets(dateDeb,dateFin).setEnabled(false);
button.addClickHandler(handler).addClickHandler(cHandler).setEnabled(false);
grid.setWidget(3, 0,button).setWidget(3, 1, chkGrid);
grid.setWidget(4, 0,dateDeb).setWidget(4, 1, dateFin);
var warning = app.createLabel("Veuillez d'abord sélectionner un document et les noms des agendas").setId('warning');
wHandler.validateNotMatches(list, '- - -').validateNotMatches(listS, '- - -').validateNotMatches(listD, '- - -')
.forTargets(button).setEnabled(true).forTargets(warning).setVisible(false);
app.add(grid).add(warning).add(msg).add(popPanel).add(wait);
cHandler.forTargets(grid).setVisible(false);
doc.show(app);
}
function continueRestore(e){
var app = UiApp.getActiveApplication();
var popAlert = app.getElementById('popPanel');
var grid = app.getElementById('grid');
var msg = app.getElementById('msg').setVisible(false);
ScriptProperties.setProperty('startrestore',new Date().getTime().toString());
// recover pointers to continue restore
var restoreData = ScriptProperties.getProperty('restoreData');
e = Utilities.jsonParse(restoreData);
return restoreCal(e)
}
function cancelRestore(e){
var app = UiApp.getActiveApplication();
ScriptProperties.setProperty('restoreData','')
ScriptProperties.setProperty('restorePointers','canceled');
SpreadsheetApp.getActiveSpreadsheet().toast(' ','restauration annulée');
app.close();
return app;
}
function restoreDate(e){
var app = UiApp.getActiveApplication();
var wait = app.getElementById('wait');
var sourceCalId = e.parameter.sourceCal;
var sourceCal = CalendarApp.getCalendarById(sourceCalId);
var sourceCalName = sourceCal.getName();
var ssId = e.parameter.bkpname;
if(!SpreadsheetApp.openById(ssId).getSheetByName(sourceCalName)){Browser.msgBox('pas de backup correspondant à cet agenda dans ce document');return app}
var data = SpreadsheetApp.openById(ssId).getSheetByName(sourceCalName).getDataRange().getValues();
var deb = [];
var fin = [];
for(n=1;n<data.length;++n){
deb.push([Utilities.formatDate(new Date(data[n][1]),tz,'dd-MM-yyyy'),n-1]);
fin.push([Utilities.formatDate(new Date(data[n][2]),tz,'dd-MM-yyyy'),n-1]);
}
//Logger.log(deb)
var dateDeb = [];
var dateFin = [];
for(n=deb.length-1;n>0;n--){if(deb[n][0]!=deb[n-1][0]){dateDeb.push(deb[n])}};
for(n=fin.length-1;n>0;n--){if(fin[n][0]!=fin[n-1][0]){dateFin.push(fin[n])}};
var debList = app.getElementById('dateDeb');
debList.setVisible(true);
var finList = app.getElementById('dateFin');
finList.setVisible(true);
if(e.parameter.dates=='false'){debList.setVisible(false);finList.setVisible(false)}
dateDeb.push(['première date disponible','xxxxxxxxxx']);
dateDeb.reverse();
dateFin.unshift(['dernière date disponible','xxxxxxxxxx']);
if(e.parameter.dateDeb=='xxxxxxxxxx'){
debList.clear();
for(n=0;n<dateDeb.length;++n){debList.addItem(dateDeb[n][0],dateDeb[n][1])}
}
if(e.parameter.dateFin=='xxxxxxxxxx'){
finList.clear();
for(n=0;n<dateFin.length;++n){finList.addItem(dateFin[n][0],dateFin[n][1])}
}
wait.setVisible(false);
var cHandler = app.createClientHandler().forTargets(wait).setVisible(true);
app.getElementById('button').addClickHandler(cHandler);
return app;
}
function restoreCal(e){
var lock = LockService.getPublicLock();
var success = lock.tryLock(5000);
if (!success) {
Logger.log('tryLock failed to get the lock');
return
}
ScriptProperties.setProperty('startrestore',new Date().getTime().toString())
if(ScriptProperties.getProperty('restoreData')==''||ScriptProperties.getProperties().toString().indexOf('restoreData')==-1)
{ScriptProperties.setProperty('restoreData',Utilities.jsonStringify(e))
}
var app = UiApp.getActiveApplication();
var alert = app.getElementById('alert')
var ssId = e.parameter.bkpname;
var targetCalId = e.parameter.targetCal;
var targetCal = CalendarApp.getCalendarById(targetCalId);
var targetCalName = targetCal.getName();
var sourceCalId = e.parameter.sourceCal;
var sourceCal = CalendarApp.getCalendarById(sourceCalId);
var sourceCalName = sourceCal.getName();
var salles = e.parameter.salles =='true';
var cours = e.parameter.cours == 'true';
var profs = e.parameter.profs == 'true';
var partiel = e.parameter.dates =='true';
//Logger.log(SpreadsheetApp.openById(ssId).getNumSheets()+' '+sourceCalName + salles+cours+profs)
if(!SpreadsheetApp.openById(ssId).getSheetByName(sourceCalName)){Browser.msgBox('pas de backup correspondant à cet agenda dans ce document');lock.releaseLock(); return app}
var data = SpreadsheetApp.openById(ssId).getSheetByName(sourceCalName).getDataRange().getValues();
var headers = data.shift();
//Logger.log(headers)
//Logger.log(ssId+' '+targetCal)
// [Agendas de BaAC1, Début , Fin, Lieu/ressources, Créateur, invités(liens),invités(nom), durée, description]
// date format = 23/09/2013 12:45:00
var pointers = ScriptProperties.getProperty('restorePointers');
if(pointers=='0@0'){
if(partiel){
//Logger.log(partiel+' '+e.parameter.dateDeb+' '+e.parameter.dateFin)
if(e.parameter.dateDeb.length < 5){var dStart = Number(e.parameter.dateDeb)}else{dStart=0};
if(e.parameter.dateFin.length < 5){var dEnd = Number(e.parameter.dateFin)}else{dEnd=data.length};
}else{
var dStart=0;dEnd=data.length;
}
}else{
dStart = Number(pointers.split('@')[0]);
dEnd = Number(pointers.split('@')[1]);
}
if(dStart>dEnd){dStart=dEnd}
//Logger.log(partiel+' de '+dStart+' à '+dEnd)
// main loop ------------------------
for(var ee=dStart;ee<dEnd;++ee){
var ccc = ScriptProperties.getProperty('restorePointers');
if(ccc=='canceled'){ app.close() ; return app };
if(new Date().getTime()-Number(ScriptProperties.getProperty('startrestore'))>260000){ ;// normal = 260000 mS
ScriptProperties.setProperty('restorePointers',[ee,dEnd].join('@'));
var popPanel = app.getElementById('popPanel').setVisible(true);
var msgHTML = app.getElementById('msgHTML').setHTML("la restauration n'est pas terminée...( encore "+(dEnd-ee)
+" éléments à restaurer sur "+dEnd+" )<BR> veuillez cliquer ici et le processus reprendra là où il s'était arrêté");
var msg = app.getElementById('msg').setVisible(false);
var wait = app.getElementById('wait').setVisible(false);
var waitR = app.getElementById('waitR').setVisible(false);
var cont = app.getElementById('continue').setEnabled(true).setHTML('continuer la restauration');
var grid = app.getElementById('grid').setVisible(false);
lock.releaseLock();
return app
}
var guests = '';
var types = data[ee][6].split(',');
var typesLink = data[ee][5].split(',');
for(t=0;t<types.length;++t){
if(types[t].indexOf('@')>-1 && salles){guests+=typesLink[t]+','; continue}
if(types[t].indexOf('#')>-1 && cours){guests+=typesLink[t]+','; continue}
if(profs){guests+=typesLink[t]+','}
}
if(guests.length>0){guests = guests.substring(0,guests.length-1)}
//Logger.log(targetCal.getName()+' '+ee+' '+ guests)
var options = {'guests':guests,'location':data[ee][3],'description':data[ee][8]}
try{
targetCal.createEvent(data[ee][0], new Date(data[ee][1]), new Date(data[ee][2]), options);
Utilities.sleep(30);
}catch(error){
app.add(app.createLabel('erreur du serveur :'+Utilities.jsonStringify(error)+ ' le processus devrait néanmoins continuer sans intervention de vore part'));
}
//Logger.log(ee+' '+data[ee][0]+' '+new Date(data[ee][1])+' '+ new Date(data[ee][2])+' '+guests)
if((ee%10==0)&&ee>0){SpreadsheetApp.getActiveSpreadsheet().toast(ee+' événements crées sur '+dEnd,Utilities.formatDate(new Date(data[ee][1]),tz,'dd-MMM-yyyy'))}
}
// end of main loop-----------------
ScriptProperties.setProperty('restoreData','')
ScriptProperties.setProperty('restorePointers',0+'@'+0);
SpreadsheetApp.getActiveSpreadsheet().toast(dEnd+' événements crées sur '+dEnd,'restauration terminée');
app.close();
lock.releaseLock();
return app;
}