Fokusierte Arbeitszeit
Fortgeschritten
Dies ist ein Personal Productivity-Bereich Automatisierungsworkflow mit 11 Nodes. Hauptsächlich werden If, Code, ItemLists, GoogleCalendar, ScheduleTrigger und andere Nodes verwendet. Automatisches Blockieren von Fokuszeit in Google Calendar während eines vollen Terminkalenders
Voraussetzungen
- •Keine besonderen Voraussetzungen, sofort nach Import nutzbar
Verwendete Nodes (11)
Kategorie
Workflow-Vorschau
Visualisierung der Node-Verbindungen, mit Zoom und Pan
Workflow exportieren
Kopieren Sie die folgende JSON-Konfiguration und importieren Sie sie in n8n
{
"id": "H1q8R1MfhEk8F0ni",
"meta": {
"instanceId": "bdc54da2c96840612a04bf3fd3a4cd97a7a7bd7c1152bbe41d5615f09311c097"
},
"name": "FocusTime",
"tags": [
{
"id": "SauVYJKjA9yiw2uI",
"name": "calendar-automation",
"createdAt": "2025-07-20T22:06:21.623Z",
"updatedAt": "2025-07-20T22:06:21.623Z"
}
],
"nodes": [
{
"id": "965166ee-bf7e-48e6-b559-624c4a5bb72f",
"name": "Zeitplan-Auslöser",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-880,
96
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * *"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "af8970e0-6d2c-48d4-907b-5e022ab8d5ac",
"name": "Wochentermine abrufen",
"type": "n8n-nodes-base.googleCalendar",
"position": [
-656,
96
],
"parameters": {
"options": {},
"calendar": {
"__rl": true,
"mode": "list",
"value": "primary",
"cachedResultName": "Primary"
},
"operation": "getAll"
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "Isqbn5j7Czj35HLS",
"name": "Google Calendar account"
}
},
"typeVersion": 1
},
{
"id": "76c503e8-926f-4254-be1b-f2c5b55938e8",
"name": "Wöchentliche Fokuszeitfenster berechnen",
"type": "n8n-nodes-base.code",
"position": [
-448,
96
],
"parameters": {
"jsCode": "const events = $input.all();\nconst today = new Date();\n\n// Get Sunday of current week (start of week)\nconst sunday = new Date(today);\nsunday.setDate(today.getDate() - today.getDay());\nsunday.setHours(0, 0, 0, 0);\n\n// Create array of all 7 days (Sunday-Saturday)\nconst allDays = [];\nfor (let i = 0; i < 7; i++) {\n const day = new Date(sunday);\n day.setDate(sunday.getDate() + i);\n allDays.push(day);\n}\n\nconst dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\nconsole.log('Analyzing full week:', allDays.map((d, i) => `${dayNames[i]} ${d.toDateString()}`));\n\nconst allFocusSlots = [];\n\n// Process each day of the week\nfor (let dayIndex = 0; dayIndex < allDays.length; dayIndex++) {\n const currentDay = allDays[dayIndex];\n const dayName = dayNames[dayIndex];\n \n const workStart = new Date(currentDay);\n workStart.setHours(9, 0, 0, 0);\n const workEnd = new Date(currentDay);\n workEnd.setHours(17, 0, 0, 0);\n \n // Filter events for this specific day\n const dayEvents = events\n .filter(event => {\n const eventStart = new Date(event.json.start.dateTime || event.json.start.date);\n return eventStart.toDateString() === currentDay.toDateString();\n })\n .sort((a, b) => {\n const aStart = new Date(a.json.start.dateTime || a.json.start.date);\n const bStart = new Date(b.json.start.dateTime || b.json.start.date);\n return aStart - bStart;\n });\n\n // Calculate total booked time for this day\n let totalBookedMinutes = 0;\n for (const event of dayEvents) {\n const startTime = new Date(event.json.start.dateTime || event.json.start.date);\n const endTime = new Date(event.json.end.dateTime || event.json.end.date);\n \n const effectiveStart = new Date(Math.max(startTime.getTime(), workStart.getTime()));\n const effectiveEnd = new Date(Math.min(endTime.getTime(), workEnd.getTime()));\n \n if (effectiveStart < effectiveEnd) {\n totalBookedMinutes += (effectiveEnd - effectiveStart) / (1000 * 60);\n }\n }\n\n const totalBookedHours = totalBookedMinutes / 60;\n console.log(`${dayName} ${currentDay.toDateString()}: ${totalBookedHours.toFixed(1)} hours booked`);\n\n // Only process days with 6+ hours booked\n if (totalBookedHours >= 6) {\n console.log(`Creating focus time for ${dayName} (${totalBookedHours.toFixed(1)} hours booked)`);\n \n const freeSlots = [];\n let currentTime = new Date(workStart);\n\n // Check time before first event\n if (dayEvents.length > 0) {\n const firstEventStart = new Date(dayEvents[0].json.start.dateTime || dayEvents[0].json.start.date);\n if (currentTime < firstEventStart) {\n const slotEnd = new Date(Math.min(firstEventStart.getTime(), workEnd.getTime()));\n if (currentTime < slotEnd) {\n freeSlots.push({\n start: new Date(currentTime),\n end: slotEnd\n });\n }\n }\n }\n\n // Check time between events\n for (let i = 0; i < dayEvents.length - 1; i++) {\n const currentEventEnd = new Date(dayEvents[i].json.end.dateTime || dayEvents[i].json.end.date);\n const nextEventStart = new Date(dayEvents[i + 1].json.start.dateTime || dayEvents[i + 1].json.start.date);\n \n const slotStart = new Date(Math.max(currentEventEnd.getTime(), workStart.getTime()));\n const slotEnd = new Date(Math.min(nextEventStart.getTime(), workEnd.getTime()));\n \n if (slotStart < slotEnd) {\n freeSlots.push({\n start: slotStart,\n end: slotEnd\n });\n }\n }\n\n // Check time after last event\n if (dayEvents.length > 0) {\n const lastEventEnd = new Date(dayEvents[dayEvents.length - 1].json.end.dateTime || dayEvents[dayEvents.length - 1].json.end.date);\n const slotStart = new Date(Math.max(lastEventEnd.getTime(), workStart.getTime()));\n \n if (slotStart < workEnd) {\n freeSlots.push({\n start: slotStart,\n end: new Date(workEnd)\n });\n }\n } else {\n // No events this day, but 6+ hours requirement met somehow (shouldn't happen, but handle it)\n console.log(`${dayName}: No events found but met 6+ hour criteria`);\n }\n\n // Filter slots that are at least 15 minutes long and add to all slots\n const validSlots = freeSlots.filter(slot => \n (slot.end - slot.start) >= 15 * 60 * 1000\n );\n\n validSlots.forEach(slot => {\n allFocusSlots.push({\n start: slot.start.toISOString(),\n end: slot.end.toISOString(),\n duration: Math.round((slot.end - slot.start) / (1000 * 60)),\n summary: \"Focus Time\",\n day: currentDay.toDateString(),\n dayName: dayName,\n bookedHours: totalBookedHours.toFixed(1)\n });\n });\n }\n}\n\nconsole.log(`Found ${allFocusSlots.length} focus time slots across the full week`);\n\nif (allFocusSlots.length === 0) {\n return [{\n json: {\n shouldCreateFocusTime: false,\n message: 'No days this week have 6+ hours booked. Focus time not needed.',\n weekAnalyzed: allDays.map((d, i) => `${dayNames[i]} ${d.toDateString()}`)\n }\n }];\n}\n\nreturn [{\n json: {\n shouldCreateFocusTime: true,\n totalSlotsFound: allFocusSlots.length,\n freeSlots: allFocusSlots,\n weekAnalyzed: allDays.map((d, i) => `${dayNames[i]} ${d.toDateString()}`)\n }\n}];"
},
"typeVersion": 2
},
{
"id": "a6d17dd6-3aea-4860-b3c1-cd95d8e6a78c",
"name": "Fokuszeit erstellen?",
"type": "n8n-nodes-base.if",
"position": [
-224,
96
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "condition-001",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.shouldCreateFocusTime }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "49a4675b-2a0f-4219-9500-aa1803fd794b",
"name": "Freie Fenster aufteilen",
"type": "n8n-nodes-base.itemLists",
"position": [
0,
0
],
"parameters": {
"options": {},
"fieldToSplitOut": "freeSlots"
},
"typeVersion": 3
},
{
"id": "a7191014-8661-41c2-b121-7f7f924c895e",
"name": "Fokuszeit-Termin erstellen",
"type": "n8n-nodes-base.googleCalendar",
"position": [
224,
0
],
"parameters": {
"end": "={{ $json.end }}",
"start": "={{ $json.start }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "primary",
"cachedResultName": "Primary"
},
"additionalFields": {}
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "Isqbn5j7Czj35HLS",
"name": "Google Calendar account"
}
},
"typeVersion": 1
},
{
"id": "019babfa-6ac8-4028-951c-0cb776ef24cd",
"name": "Ergebnisse protokollieren",
"type": "n8n-nodes-base.code",
"position": [
448,
0
],
"parameters": {
"jsCode": "const items = $input.all();\nconst summary = {\n message: 'Focus time blocks created successfully for the week',\n totalSlots: items.length,\n slots: items.map(item => ({\n start: item.json.start.dateTime,\n end: item.json.end.dateTime,\n summary: item.json.summary\n }))\n};\n\nconsole.log('Weekly Focus Time Creation Summary:', JSON.stringify(summary, null, 2));\n\nreturn [{\n json: summary\n}];"
},
"typeVersion": 2
},
{
"id": "7ecbdb56-9195-4d13-891b-e307d10417f5",
"name": "Keine Fokuszeit nötig protokollieren",
"type": "n8n-nodes-base.code",
"position": [
0,
208
],
"parameters": {
"jsCode": "const data = $input.first().json;\nconsole.log('Weekly Focus Time Analysis:', data.message);\n\nreturn [{\n json: {\n message: data.message,\n weekAnalyzed: data.weekAnalyzed,\n action: 'no_focus_time_needed'\n }\n}];"
},
"typeVersion": 2
},
{
"id": "5a76f16a-5931-45d8-8319-440b39491a65",
"name": "Notizzettel",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
-80
],
"parameters": {
"height": 400,
"content": "Set the schedule time the workflow would run (recommend to set at a time before user's work day starts). "
},
"typeVersion": 1
},
{
"id": "f9e74c3f-ab4e-4e70-bddc-08f4903dc6f5",
"name": "Notizzettel1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-688,
-80
],
"parameters": {
"width": 592,
"height": 400,
"content": "Workflow checks user's calendar from Sunday to Saturday of current week. Goal of this part is to determine if a day has 6 or more hours booked already\n\nNote: Update the credentials used in the \"Get Full Weeks Events\" node to use your Google credentials. "
},
"typeVersion": 1
},
{
"id": "8ac0657c-c682-414e-b56e-884f517bcda2",
"name": "Notizzettel2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
-176
],
"parameters": {
"width": 704,
"height": 544,
"content": "For days with 6 or more hours already booked, the workflow automatically blocks out the remaining hours for dedicated focus time. The workflows assumes an 8 hour work week. For example, if Monday has 6.5 booked already (for meetings, tasks etc.), the workflow will block the remaining 1.5 hours. The results are logged to help with any troubleshooting\n\nNote: Update the credentials used in the \"Create Focus Time Event\" node to use your Google credentials. "
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "9c49a780-08ab-4198-9a16-8cdb241b5425",
"connections": {
"965166ee-bf7e-48e6-b559-624c4a5bb72f": {
"main": [
[
{
"node": "af8970e0-6d2c-48d4-907b-5e022ab8d5ac",
"type": "main",
"index": 0
}
]
]
},
"49a4675b-2a0f-4219-9500-aa1803fd794b": {
"main": [
[
{
"node": "a7191014-8661-41c2-b121-7f7f924c895e",
"type": "main",
"index": 0
}
]
]
},
"af8970e0-6d2c-48d4-907b-5e022ab8d5ac": {
"main": [
[
{
"node": "76c503e8-926f-4254-be1b-f2c5b55938e8",
"type": "main",
"index": 0
}
]
]
},
"a7191014-8661-41c2-b121-7f7f924c895e": {
"main": [
[
{
"node": "019babfa-6ac8-4028-951c-0cb776ef24cd",
"type": "main",
"index": 0
}
]
]
},
"a6d17dd6-3aea-4860-b3c1-cd95d8e6a78c": {
"main": [
[
{
"node": "49a4675b-2a0f-4219-9500-aa1803fd794b",
"type": "main",
"index": 0
}
],
[
{
"node": "7ecbdb56-9195-4d13-891b-e307d10417f5",
"type": "main",
"index": 0
}
]
]
},
"76c503e8-926f-4254-be1b-f2c5b55938e8": {
"main": [
[
{
"node": "a6d17dd6-3aea-4860-b3c1-cd95d8e6a78c",
"type": "main",
"index": 0
}
]
]
}
}
}Häufig gestellte Fragen
Wie verwende ich diesen Workflow?
Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.
Für welche Szenarien ist dieser Workflow geeignet?
Fortgeschritten - Persönliche Produktivität
Ist es kostenpflichtig?
Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.
Verwandte Workflows
Telegram-Kalender-Bot
Täglicher Kalenderzusammenfassung von Google Kalender per Telegram senden
If
Code
Telegram
+
If
Code
Telegram
11 NodesYassin Zehar
Persönliche Produktivität
Globale Feiertagskonflikte erkennen und Meetings neu planen
Feiertagskonflikte mit Google Calendar und Slack erkennen und Meeting-Umplanungen vorschlagen
If
Set
Code
+
If
Set
Code
23 NodesTakuya Ojima
Persönliche Produktivität
Kostenloses Geschenk: Tägliche Erinnerungsvorlage
Tägliche Kalenderzusammenfassungen per SMS über Google Calendar, Twilio und Claude AI abrufen
If
Set
Code
+
If
Set
Code
13 NodesAnne Uy Gothong
Persönliche Produktivität
Personalisiertes Wetter-E-Mail mit Python und AI
OpenWeatherMap, Python und GPT-4.1-mini zum Generieren personalisierter Wetterberichte verwenden
Code
Gmail
Form Trigger
+
Code
Gmail
Form Trigger
11 NodesMoe Ahad
Persönliche Produktivität
AI Timesheet Generator with Gmail, Calendar & GitHub to Google Sheets
AI-Arbeitszeiterfassung - Integration von Gmail, Kalender und GitHub in Google Tabellen
If
Set
Code
+
If
Set
Code
31 NodesLuka Zivkovic
Persönliche Produktivität
Automatisierte Aufgaben-Erinnerungen für Studierende und Dozenten sowie Nachverfolgung von Abgabeterminen
Verwenden Sie Notion und E-Mail, um Lehrern und Schülern Erinnerungen an die Abgabetermine zu geben
If
Notion
Email Send
+
If
Notion
Email Send
7 NodesOneclick AI Squad
Persönliche Produktivität
Workflow-Informationen
Schwierigkeitsgrad
Fortgeschritten
Anzahl der Nodes11
Kategorie1
Node-Typen6
Autor
Moe Ahad
@moe-ahadExterne Links
Auf n8n.io ansehen →
Diesen Workflow teilen