Tiempo de concentración

Intermedio

Este es unPersonal Productivityflujo de automatización del dominio deautomatización que contiene 11 nodos.Utiliza principalmente nodos como If, Code, ItemLists, GoogleCalendar, ScheduleTrigger. Bloquear automáticamente tiempo de concentración en Google Calendar en agendas ocupadas

Requisitos previos
  • No hay requisitos previos especiales, puede importar y usarlo directamente
Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "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": "Disparador Programado",
      "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": "Obtener Eventos de la Semana Completa",
      "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": "Calcular Espacios de Tiempo de Concentración de la Semana Completa",
      "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": "¿Debe Crear Tiempo de Concentración?",
      "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": "Dividir Espacios Libres",
      "type": "n8n-nodes-base.itemLists",
      "position": [
        0,
        0
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "freeSlots"
      },
      "typeVersion": 3
    },
    {
      "id": "a7191014-8661-41c2-b121-7f7f924c895e",
      "name": "Crear Evento de Tiempo de Concentración",
      "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": "Registrar Resultados",
      "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": "Registrar que no se Necesita Tiempo de Concentración",
      "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": "Nota Adhesiva",
      "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": "Nota Adhesiva1",
      "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": "Nota Adhesiva2",
      "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
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿Cómo usar este flujo de trabajo?

Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.

¿En qué escenarios es adecuado este flujo de trabajo?

Intermedio - Productividad personal

¿Es de pago?

Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.

Información del flujo de trabajo
Nivel de dificultad
Intermedio
Número de nodos11
Categoría1
Tipos de nodos6
Descripción de la dificultad

Adecuado para usuarios con experiencia intermedia, flujos de trabajo de complejidad media con 6-15 nodos

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34