Satura rādītājs
Vajadzīga palīdzība ar Google Workspace?

Pastāstiet, kas nedarbojas, mēs atbildēsim tajā pašā dienā.

Darbo grafikas gyvena Google skaičiuoklėje. Komanda gyvena Google kalendoriuje. Kažkas jau dvejus metus kiekvieną penktadienį perrašo vieną į kitą, ir tą vieną savaitę, kai jis buvo atostogose, dvi pamainos liko nepadengtos. Mūsų r/GoogleAppsScript analizėje tai vienas iš dviejų dažniausiai užduodamų automatizavimo klausimų (imtyje apie 250 diskusijų), ir maždaug trečdalis šių diskusijų taip ir nesulaukė veikiančio atsakymo. Priežastis ne ta, kad tai sudėtinga. Priežastis ta, kad nepavyksta keturi atskiri dalykai, o kiekviena instrukcija aprašo tik vieną iš jų.

Toliau: skriptas, kurį galima saugiai paleisti pakartotinai, laiko juostų problema, dėl kurios įvykiai atsiduria dieną per anksti, kaip atsiranda dublikatai ir kaip daugumos jų išvengti, ir kada to apskritai nereikėtų daryti skriptu. Patikrinta pagal Google kalendoriaus ir Apps Script dokumentaciją 2026 m. rugsėjo 9 d. Išbandykite tai lentelės kopijoje ir testiniame kalendoriuje, prieš nukreipdami į tikrus.

Ką reiškia „teisingai”

Skriptas iš lentelės į kalendorių naudingas tik tada, jei jį galima paleisti dar kartą. Tai reiškia, kad jis negali sukurti to paties įvykio du kartus, turi atnaujinti įvykį, kai eilutė pasikeičia, negali tyliai pastumti laikų ir turi sustoti su aiškia klaida, o ne pusiaukelėje. Dauguma iš forumų nukopijuotų skriptų neatitinka visų keturių kriterijų. Veikiantis sprendimas paprastas: vienas lentelės stulpelis saugo kalendoriaus įvykio ID, kuris įrašomas įvykio sukūrimo momentu, o ne pabaigoje. Nėra ID – sukuria; yra ID – atnaujina. Užraktas neleidžia dviem vykdymams persidengti, o būsenos stulpelis apdoroja atšaukimus.

Lentelės išdėstymas

A: Pavadinimas B: Pradžia C: Pabaiga D: Aprašymas E: Įvykio ID F: Būsena
Rytinė pamaina, Anna 2026-09-14 08:00 2026-09-14 16:00 Registratūra užpildo skriptas
Pristatymas, klientas X 2026-09-15 10:30 2026-09-15 11:30 Užsakymas 4471 užpildo skriptas Cancelled

Pradžia ir Pabaiga turi būti tikros datos ir laiko reikšmės, o ne tekstas, panašus į datą. Stulpelio formatavimas kaip „Data ir laikas” esamo teksto nepaverčia, todėl patikrinkite langelį su =ISDATE(B2): jis turi grąžinti TRUE. Pavyzdyje naudojama metai-mėnuo-diena tvarka, kokia yra Lietuvos lokalėje (daugumoje kitų Europos lokalių – diena.mėnuo.metai); jei jūsų skaičiuoklės lokalė yra JAV, rašykite 09/14/2026 08:00. Toliau pateiktas skriptas praleidžia eilutes, kurių datos nėra tikros datos, ir apie jas praneša, o ne tyliai sužlunga.

Skriptas

Atidarykite Extensions, Apps Script. Jei projekte jau yra kodo, jo neperrašykite: pridėkite naują skripto failą (pliuso ženklas prie Files) ir įklijuokite ten toliau pateiktą kodą. Užpildykite tris konstantas viršuje: skaičiuoklės ID (iš lentelės URL), lapo (skirtuko) pavadinimą ir komandos kalendoriaus ID (Calendar settings, Integrate calendar). Skriptas savo lentelę ir kalendorių nurodo tiesiogiai, o ne „tą, kuri aktyvi”, nes planuotam vykdymui aktyvios lentelės nėra.

const SPREADSHEET_ID = 'ikelkite-id-is-lenteles-url';
const SHEET_NAME     = 'Roster';
const CALENDAR_ID    = 'team@yourdomain.com';

function syncSheetToCalendar() {
  const lock = LockService.getScriptLock();
  if (!lock.tryLock(30000)) { Logger.log('Kitas vykdymas dar tesiasi; praleidziame.'); return; }
  try {
    const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(SHEET_NAME);
    const cal   = CalendarApp.getCalendarById(CALENDAR_ID);
    if (!sheet) throw new Error('Lapas "' + SHEET_NAME + '" nerastas');
    if (!cal)   throw new Error('Kalendorius nerastas arba nera prieigos: ' + CALENDAR_ID);

    const lastRow = sheet.getLastRow();
    if (lastRow < 2) return;                                  // tik antraste
    const rows = sheet.getRange(2, 1, lastRow - 1, 6).getValues(); // A:F, vienas nuskaitymas
    const problems = [];

    rows.forEach((row, i) => {
      const r = i + 2;                                          // eilutes numeris lenteleje
      const [title, start, end, desc, id, status] = row;

      if (String(status).trim().toLowerCase() === 'cancelled') {
        if (id) {
          try { const ev = cal.getEventById(id); if (ev) ev.deleteEvent(); }
          catch (e) { problems.push('Eilute ' + r + ': nepavyko istrinti: ' + e.message); return; }
          sheet.getRange(r, 5).setValue('');                    // isvalo ID, eilute lieka atsaukta
        }
        return;
      }
      if (!title) return;                                       // tuscia eilute
      if (!(start instanceof Date) || !(end instanceof Date) || end <= start) {
        problems.push('Eilute ' + r + ': pradzia/pabaiga nera tinkamas datu intervalas'); return;
      }
      try {
        let ev = id ? cal.getEventById(id) : null;
        if (ev) {
          ev.setTitle(title); ev.setTime(start, end); ev.setDescription(desc || '');
        } else {
          ev = cal.createEvent(title, start, end, { description: desc || '' });
          sheet.getRange(r, 5).setValue(ev.getId());            // iraso ID nedelsiant
        }
      } catch (e) {
        problems.push('Eilute ' + r + ': ' + e.message);
      }
    });

    if (problems.length) {
      Logger.log(problems.join('\n'));
      // Pasirinktinai: MailApp.sendEmail('it@yourdomain.com', 'Grafiko sinchronizavimo problemos', problems.join('\n'));
    }
  } finally {
    lock.releaseLock();
  }
}

Pirmiausia paleiskite jį vieną kartą iš redaktoriaus (paleidimo mygtukas prie syncSheetToCalendar) lentelės kopijoje ir testiniame kalendoriuje. Google paprašys suteikti prieigą prie skaičiuoklių ir kalendoriaus. Kadangi paleidžiate skriptą, kurį ką tik patys įklijavote į savo projektą, šis autorizavimas skirtas jūsų pačių kodui; vis dėlto perskaitykite prašomų leidimų sąrašą, o jei kada nors pamatysite įspėjimą „unverified app” skriptui, kurio nerašėte, sustokite ir išsiaiškinkite, kam jis priklauso. Patikrinkite kalendorių, tada patikrinkite, ar E stulpelis užsipildė ID. Paleiskite dar kartą: niekas neturi dubliuotis. Tada išbandykite klaidos kelią: įrašykite Pradžios langelyje tekstą ir įsitikinkite, kad vykdymas baigiasi, įrašo problemos eilutę į žurnalą ir kitų įvykių neliečia.

Kodėl ID įrašomas kiekvienai eilutei atskirai

Daug forumų skriptų surenka ID į masyvą ir įrašo juos visus pabaigoje. Jei vykdymas nutrūksta pusiaukelėje (kvota, leidimų klaida, 6 minučių limitas), iki tol sukurti įvykiai kalendoriuje egzistuoja, bet jų ID į lentelę nepatenka, ir kitas vykdymas sukuria juos dar kartą. Kiekvieno ID įrašymas tuoj pat po createEvent kainuoja vieną papildomą iškvietimą kiekvienai naujai eilutei ir uždaro didžiąją šio lango dalį. Tai nepaverčia skaičiuoklių ir kalendoriaus viena transakcija; klaida tarp createEvent ir setValue vis dar galima, tik reta. Jei dublikatas kada nors vis tiek atsiranda, ID stulpelis pasako, kurį įvykį lentelė pažįsta, o kitas yra našlaitis.

Laiko juostų klaida: įvykiai pasislinkę per dieną ar valandą

Tai ta dalis, kuri žmonėms kainuoja visą popietę. Dalyvauja trys laiko juostos nustatymai, ir jei nežinote, ką kiekvienas daro, jie nesutaps:

1. SkaičiuoklėFile, Settings, Time zonelangelis „2026-09-14 08:00” skaitomas kaipEurope/Vilnius2. Apps Script projektasProject Settings, appsscript.json„timeZone” formatuoja ir pastumia datasEurope/Vilnius3. KalendoriusCalendar settings, Time zoneįvykis saugomas ir rodomas čiaEurope/VilniusJei trys nesutampa:tekstinės datos išanalizuotos ne toje juostoje arba reikšmė be laikosukurta kaip įvykis su laiku: „įvykiai diena per anksti”Lentelė ir skriptas įmonės juostoje:laikai atsiduria taip, kaip įrašyti; žiūrovai kitose šalyse matotą patį momentą savo juostoje, ir tai teisinga

  1. Skaičiuoklės laiko juosta. File, Settings, Time zone. Langeliuose įrašytos datos interpretuojamos čia.
  2. Skripto projekto laiko juosta. Apps Script redaktoriuje Project Settings, pažymėkite Show appsscript.json; laukas timeZone. Naujiems projektams numatytoji reikšmė kartais būna America/New_York, nepriklausomai nuo to, kur esate.
  3. Kalendoriaus laiko juosta. Konkretaus kalendoriaus nustatymuose.

Datos ir laiko langelis skaičiuoklėje saugomas kaip momentas laike, interpretuojamas skaičiuoklės juostoje. „2026-09-14 08:00” Europe/Vilnius lentelėje yra 05:00 UTC. Kalendorius saugo tą patį momentą ir rodo jį kiekvieno žiūrovo juostoje, todėl kolega Niujorke teisingai mato 01:00; tai ne klaida. Klaidos atsiranda, kai skriptas tekstą paverčia datomis naudodamas skripto juostą, kai reikšmė be laiko (vidurnaktis lentelės juostoje) sukuriama kaip įvykis su laiku ir kitoje juostoje rodoma kaip ankstesnis vakaras, arba kai paties kalendoriaus juosta skiriasi ir visos dienos įvykiai pasislenka per dieną. Praktiškai: nustatykite skaičiuoklei ir skripto projektui įmonės namų juostą, laikykite lentelėje datas kaip tikras datos reikšmes ir, prieš pasitikėdami, išbandykite vieną įvykį abipus vasaros/žiemos laiko ribos.

Visos dienos įvykiams (data be laiko) naudokite cal.createAllDayEvent(title, date), o ne createEvent. Jis ima reikšmės kalendorinę datą, todėl įsitikinkite, kad lentelės juostoje reikšmė iš tikrųjų yra ši data. Vėlesniam visos dienos įvykio atnaujinimui reikia setAllDayDate, o ne setTime; aukščiau pateiktas skriptas apdoroja tik įvykius su laiku.

Automatinis paleidimas

Redaktoriuje spustelėkite Triggers (laikrodžio piktograma), Add trigger, pasirinkite syncSheetToCalendar, įvykio šaltinis Time-driven, pavyzdžiui, kas valandą arba dienos langas, tarkime, nuo 6:00 iki 7:00 (Google planuoja valandos ribose, o ne minutės tikslumu). Nenaudokite tam paprasto onEdit aktyviklio (trigger): paprasti aktyvikliai negali pasiekti kalendoriaus, nes veikia be autorizacijos. Įdiegiamas „on edit” aktyviklis veikia, bet pagal laiką planuojamas sinchronizavimas yra ramesnis ir lengviau derinamas, o skripto užraktas persidengiančius vykdymus padaro nekenksmingus.

Dvi tvarkos taisyklės. Kurkite aktyviklį iš paskyros, kuri egzistuos ir kitais metais, idealiu atveju iš atskiro IT valdomo automatizavimo naudotojo, nes įdiegiami aktyvikliai sustoja, kai jų savininko paskyra sustabdoma, ir niekas kitas jų nemato. Ir nustatykite aktyviklio klaidų pranešimus į „immediately” adresu, kurį žmonės skaito, kad apie sugedusį sinchronizavimą sužinotumėte anksčiau nei komanda.

Įvykių šalinimas ir perkėlimas

Jei eilutė iš lentelės tiesiog ištrinama, įvykis kalendoriuje lieka ir niekas apie jį nebežino, todėl eilučių netrinkite: vietoj to F stulpelyje nustatykite Cancelled. Skriptas tada įvykį ištrina, išvalo ID ir toliau praleidžia šią eilutę kituose vykdymuose. Norėdami perkelti įvykį į kitą kalendorių, pažymėkite jį kaip atšauktą, leiskite vykdymui jį pašalinti, tada grąžinkite eilutę atgal ir nukreipkite skriptą į naują kalendorių (arba išplėskite skriptą kalendoriaus stulpeliu, jei sinchronizuojate kelis).

Kada to nereikėtų daryti skriptu

  • Klientų rezervacijos. Naudokite Google kalendoriaus integruotus rezervacijų puslapius; klientas pasirenka laiką, ir lentelės nereikia.
  • Pamainų planavimas, kur žmonės keičiasi, prašo ir tvirtina. Grafikų įrankiai su pamainų mainais, patvirtinimais ir pranešimais egzistuoja ne veltui. Lentelė plius skriptas tampa tuo, ką visi kaltina.
  • Bet kas, kur kalendorius yra tiesos šaltinis. Aukščiau pateiktas skriptas yra vienpusis. Jei žmonės redaguoja įvykius kalendoriuje ir tikisi, kad lentelė seks, reikia ir atvirkštinio sinchronizavimo, ir dabar turite sinchronizavimo problemą, o tai jau tikra problema.

Dažniausiai užduodami klausimai

Kodėl mano Google kalendoriaus įvykiai iš Google skaičiuoklių sukuriami diena per anksti?

Paprastai reikšmė be laiko (vidurnaktis skaičiuoklės juostoje) sukurta kaip įvykis su laiku ir rodoma kitoje juostoje, arba tekstinės datos išanalizuotos skripto projekto juostoje. Nustatykite skaičiuoklei ir skriptui įmonės juostą, laikykite lentelėje tikras datos reikšmes, o eilutėms be laiko naudokite createAllDayEvent.

Kaip pasiekti, kad skriptas kiekvieno vykdymo metu nekurtų dubliuotų įvykių?

Saugokite įvykio ID stulpelyje tuoj pat po kiekvieno įvykio sukūrimo, kituose vykdymuose atnaujinkite esamus įvykius, o ne kurkite naujus, ir naudokite užraktą, kad du vykdymai negalėtų persidengti. Aukščiau pateiktas skriptas daro visus tris dalykus. Jis negali padaryti dublikatų neįmanomų kiekvienos klaidos atveju, bet padaro juos retus ir lengvai atpažįstamus.

Ar skriptas gali pasileisti automatiškai, kai lentelė pasikeičia?

Taip, su įdiegiamu „on edit” aktyvikliu, bet pagal laiką planuojamas aktyviklis (kas valandą ar kasdien) yra nuspėjamesnis. Paprasti onEdit aktyvikliai kalendoriaus pasiekti negali.

Susiję straipsniai

Jei norėtumėte, kad tai nustatytų ir prižiūrėtų kas nors kitas, paprastas vieno kalendoriaus sinchronizavimas, kaip aprašyta aukščiau, mums yra trumpas darbas, o jo priežiūra yra valdomų IT paslaugų dalis.

Automatizavimas sugedo, ir niekas už jį neatsako? Mes įvertiname darbo eigą, jos aktyviklius ir vykdymo paskyras, tada nustatome remonto apimtį ir priežiūros planą su konkrečiu atsakingu asmeniu. Užsiregistruokite nemokamam 30 minučių auditui arba skambinkite +371 22 30 50 90.

Įvertinti automatizavimą

FreeIT SIA · Google Cloud partneris Baltijā kopš 2012. gada

Pirmais Google Cloud partneris Baltijā. Dibinātāja Google Cloud sertifikāts Nr. 860 ir viens no pirmajiem 1000 pasaulē. 15 gadu pieredze Google Workspace ieviešanā, migrācijās un atbalstā Baltijas uzņēmumiem.

Sazinieties · +371 22 30 50 90

Google Workspace zināšanu bāze

Saistītie raksti