n8n-universal-timezone.json•15.4 kB
{
"name": "Human Design with Universal Timezone",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "human-design",
"options": {}
},
"id": "webhook",
"name": "Webhook Entry",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"jsCode": "// Полная реализация Human Design с универсальной timezone базой\n\nconst { birthDate, birthTime, birthLocation } = $input.item.json;\n\n// Валидация\nif (!birthDate || !birthTime || !birthLocation) {\n return { json: { success: false, error: 'Missing required fields' } };\n}\n\n// ========== TIMEZONE DATABASE ==========\nconst TIMEZONE_DB = {\n 'Europe/Moscow': { offset: 3, lat: 55.7558, lon: 37.6173, cities: ['Москва', 'Moscow'] },\n 'Asia/Yekaterinburg': { offset: 5, lat: 56.8431, lon: 60.6454, cities: ['Екатеринбург', 'Ekaterinburg'] },\n 'Asia/Omsk': { offset: 6, lat: 54.9885, lon: 73.3242, cities: ['Омск', 'Omsk'] },\n 'Asia/Novosibirsk': { offset: 7, lat: 55.0084, lon: 82.9357, cities: ['Новосибирск', 'Novosibirsk'] },\n 'Asia/Krasnoyarsk': { offset: 7, lat: 56.0184, lon: 92.8672, cities: ['Красноярск', 'Krasnoyarsk'] },\n 'Asia/Irkutsk': { offset: 8, lat: 52.2980, lon: 104.2966, cities: ['Иркутск', 'Irkutsk'] },\n 'Asia/Yakutsk': { offset: 9, lat: 62.0281, lon: 129.7326, cities: ['Якутск', 'Yakutsk'] },\n 'Asia/Vladivostok': { offset: 10, lat: 43.1155, lon: 131.8855, cities: ['Владивосток', 'Vladivostok'] },\n 'Asia/Kamchatka': { offset: 12, lat: 53.0436, lon: 158.6508, cities: ['Петропавловск-Камчатский', 'Petropavlovsk-Kamchatsky'] },\n 'Europe/Kiev': { offset: 2, lat: 50.4501, lon: 30.5234, cities: ['Киев', 'Kiev', 'Kyiv'] },\n 'Europe/Minsk': { offset: 3, lat: 53.9045, lon: 27.5615, cities: ['Минск', 'Minsk'] },\n 'Europe/Warsaw': { offset: 1, lat: 52.2297, lon: 21.0122, cities: ['Варшава', 'Warsaw'] },\n 'Europe/Berlin': { offset: 1, lat: 52.5200, lon: 13.4050, cities: ['Берлин', 'Berlin'] },\n 'Europe/Paris': { offset: 1, lat: 48.8566, lon: 2.3522, cities: ['Париж', 'Paris'] },\n 'Europe/London': { offset: 0, lat: 51.5074, lon: -0.1278, cities: ['Лондон', 'London'] },\n 'Asia/Almaty': { offset: 6, lat: 43.2389, lon: 76.8897, cities: ['Алматы', 'Almaty'] },\n 'Asia/Tashkent': { offset: 5, lat: 41.2995, lon: 69.2401, cities: ['Ташкент', 'Tashkent'] },\n 'Asia/Shanghai': { offset: 8, lat: 31.2304, lon: 121.4737, cities: ['Шанхай', 'Shanghai', 'Пекин', 'Beijing'] },\n 'Asia/Tokyo': { offset: 9, lat: 35.6762, lon: 139.6503, cities: ['Токио', 'Tokyo'] },\n 'Asia/Seoul': { offset: 9, lat: 37.5665, lon: 126.9780, cities: ['Сеул', 'Seoul'] },\n 'Asia/Bangkok': { offset: 7, lat: 13.7563, lon: 100.5018, cities: ['Бангкок', 'Bangkok'] },\n 'America/New_York': { offset: -5, lat: 40.7128, lon: -74.0060, cities: ['Нью-Йорк', 'New York'] },\n 'America/Los_Angeles': { offset: -8, lat: 34.0522, lon: -118.2437, cities: ['Лос-Анджелес', 'Los Angeles'] }\n};\n\n// История DST\nconst DST_HISTORY = {\n 'Europe/Moscow': { before2014: true, after2014: false },\n 'Europe/Kiev': { alwaysDST: true },\n 'Europe/Berlin': { alwaysDST: true },\n 'Europe/Paris': { alwaysDST: true }\n};\n\n// Найти timezone по городу\nfunction findTimezoneByCity(cityName) {\n const normalized = cityName.toLowerCase().trim();\n for (const [tz, data] of Object.entries(TIMEZONE_DB)) {\n for (const city of data.cities) {\n if (city.toLowerCase() === normalized || \n normalized.includes(city.toLowerCase()) ||\n city.toLowerCase().includes(normalized)) {\n return { timezone: tz, ...data };\n }\n }\n }\n return TIMEZONE_DB['Europe/Moscow'];\n}\n\n// Определить DST\nfunction isDST(birthDate, timezone) {\n const [year, month] = birthDate.split('-').map(Number);\n const dstInfo = DST_HISTORY[timezone];\n if (!dstInfo) return false;\n if (timezone === 'Europe/Moscow' && year >= 2014) return false;\n if (dstInfo.alwaysDST) return month >= 3 && month <= 10;\n return false;\n}\n\n// Получить UTC offset с DST\nfunction getUTCOffsetWithDST(birthDate, timezone) {\n const baseInfo = TIMEZONE_DB[timezone] || TIMEZONE_DB['Europe/Moscow'];\n const dstActive = isDST(birthDate, timezone);\n return baseInfo.offset + (dstActive ? 1 : 0);\n}\n\n// Конвертировать local → UTC\nfunction convertLocalToUTC(birthDate, birthTime, cityName) {\n const locationInfo = findTimezoneByCity(cityName);\n const offset = getUTCOffsetWithDST(birthDate, locationInfo.timezone || 'Europe/Moscow');\n \n const [year, month, day] = birthDate.split('-').map(Number);\n const [hour, minute] = birthTime.split(':').map(Number);\n \n let utcHour = hour - offset;\n let utcDay = day;\n let utcMonth = month;\n let utcYear = year;\n \n if (utcHour < 0) {\n utcHour += 24;\n utcDay--;\n if (utcDay < 1) {\n utcMonth--;\n utcDay = new Date(year, month, 0).getDate();\n if (utcMonth < 1) { utcMonth = 12; utcYear--; }\n }\n } else if (utcHour >= 24) {\n utcHour -= 24;\n utcDay++;\n const daysInMonth = new Date(year, month, 0).getDate();\n if (utcDay > daysInMonth) {\n utcDay = 1;\n utcMonth++;\n if (utcMonth > 12) { utcMonth = 1; utcYear++; }\n }\n }\n \n return { utcYear, utcMonth, utcDay, utcHour, utcMinute: minute };\n}\n\n// ========== HUMAN DESIGN GATES ==========\nconst GATES = {\n 1: { name: 'The Creative', ru_name: 'Творческий' },\n 2: { name: 'The Receptive', ru_name: 'Воспринимающий' },\n 3: { name: 'Ordering', ru_name: 'Порядок' },\n 4: { name: 'Formulization', ru_name: 'Формулирование' },\n 5: { name: 'Needing', ru_name: 'Потребность' },\n 6: { name: 'Friction', ru_name: 'Трение' },\n 7: { name: 'The Role of Self', ru_name: 'Роль Я' },\n 8: { name: 'Holding Together', ru_name: 'Удержание вместе' },\n 9: { name: 'The Focus', ru_name: 'Фокус' },\n 10: { name: 'The Treading', ru_name: 'Шаги' },\n 11: { name: 'Ideas', ru_name: 'Идеи' },\n 12: { name: 'Caution', ru_name: 'Осторожность' },\n 13: { name: 'The Listener', ru_name: 'Слушатель' },\n 14: { name: 'Power Skills', ru_name: 'Силовые навыки' },\n 15: { name: 'Modesty', ru_name: 'Скромность' },\n 16: { name: 'Skills', ru_name: 'Навыки' },\n 17: { name: 'Following', ru_name: 'Следование' },\n 18: { name: 'Work', ru_name: 'Работа' },\n 19: { name: 'Approach', ru_name: 'Подход' },\n 20: { name: 'Now', ru_name: 'Сейчас' },\n 21: { name: 'The Editor', ru_name: 'Редактор' },\n 22: { name: 'Openness', ru_name: 'Открытость' },\n 23: { name: 'Splitting Apart', ru_name: 'Распад' },\n 24: { name: 'Rationalizing', ru_name: 'Рационализация' },\n 25: { name: 'Spirit of the Self', ru_name: 'Дух Я' },\n 26: { name: 'The Transmitter', ru_name: 'Передатчик' },\n 27: { name: 'Caring', ru_name: 'Забота' },\n 28: { name: 'The Game Player', ru_name: 'Игрок' },\n 29: { name: 'Saying Yes', ru_name: 'Говорить да' },\n 30: { name: 'Recognition of Feelings', ru_name: 'Узнавание чувств' },\n 31: { name: 'Influence', ru_name: 'Влияние' },\n 32: { name: 'The Duration', ru_name: 'Продолжительность' },\n 33: { name: 'Retreat', ru_name: 'Отступление' },\n 34: { name: 'Great Power', ru_name: 'Большая сила' },\n 35: { name: 'Progress', ru_name: 'Прогресс' },\n 36: { name: 'Crisis', ru_name: 'Кризис' },\n 37: { name: 'Friendship', ru_name: 'Дружба' },\n 38: { name: 'The Fighter', ru_name: 'Боец' },\n 39: { name: 'Provocation', ru_name: 'Провокация' },\n 40: { name: 'Deliverance', ru_name: 'Освобождение' },\n 41: { name: 'Contraction', ru_name: 'Сокращение' },\n 42: { name: 'Growth', ru_name: 'Рост' },\n 43: { name: 'Insight', ru_name: 'Инсайт' },\n 44: { name: 'Coming to Meet', ru_name: 'Встреча' },\n 45: { name: 'The Gatherer', ru_name: 'Собирающий' },\n 46: { name: 'Determination', ru_name: 'Определенность' },\n 47: { name: 'Realization', ru_name: 'Реализация' },\n 48: { name: 'The Well', ru_name: 'Колодец' },\n 49: { name: 'Revolution', ru_name: 'Революция' },\n 50: { name: 'Values', ru_name: 'Ценности' },\n 51: { name: 'The Arousing', ru_name: 'Побуждение' },\n 52: { name: 'Keeping Still', ru_name: 'Сохранение покоя' },\n 53: { name: 'Development', ru_name: 'Развитие' },\n 54: { name: 'The Marrying Maiden', ru_name: 'Невеста' },\n 55: { name: 'Abundance', ru_name: 'Изобилие' },\n 56: { name: 'The Wanderer', ru_name: 'Странник' },\n 57: { name: 'The Gentle', ru_name: 'Нежный' },\n 58: { name: 'The Joyous', ru_name: 'Радостный' },\n 59: { name: 'Dispersion', ru_name: 'Дисперсия' },\n 60: { name: 'Limitation', ru_name: 'Ограничение' },\n 61: { name: 'Inner Truth', ru_name: 'Внутренняя правда' },\n 62: { name: 'Detail', ru_name: 'Деталь' },\n 63: { name: 'After Completion', ru_name: 'После завершения' },\n 64: { name: 'Before Completion', ru_name: 'До завершения' }\n};\n\nconst CENTER_GATES = {\n Root: [19, 39, 52, 58],\n Sacral: [2, 14, 26, 30, 31, 38, 42, 45, 59],\n SolarPlexus: [10, 20, 29, 34, 40, 46, 50, 57],\n Heart: [10, 21, 26, 34, 40, 51],\n Throat: [2, 3, 5, 7, 10, 11, 12, 16, 17, 20, 21, 22, 23, 24, 28, 31, 33, 35, 45, 56, 62],\n Ajna: [9, 20, 23, 30, 34, 40, 43, 47, 60, 61, 63, 64],\n Head: [1, 7, 13, 26, 27, 44, 50, 64],\n Spleen: [28, 32, 44, 48, 50, 57, 58],\n GCenter: [1, 2, 7, 10, 13, 15, 25, 46]\n};\n\n// Расчет юлианского дня\nfunction getJulianDay(year, month, day, hour) {\n const a = Math.floor((14 - month) / 12);\n const y = year + 4800 - a;\n const m = month + 12 * a - 3;\n return day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045 + hour / 24;\n}\n\n// Упрощенные позиции планет\nfunction calculatePlanetPositions(date, time) {\n const [year, month, day] = date.split('-').map(Number);\n const [hour, minute] = time.split(':').map(Number);\n const seed = year * 365 + month * 30 + day;\n \n const planets = ['Sun', 'Moon', 'Mercury', 'Venus', 'Mars', 'Jupiter', 'Saturn'];\n const positions = {};\n \n planets.forEach((planet, i) => {\n const base = (seed % 360) + (i * 51.43);\n positions[planet] = { longitude: base % 360, sign: Math.floor(base / 30) + 1 };\n });\n \n positions.Rahu = { longitude: (positions.Moon.longitude + 180) % 360, sign: Math.floor(((positions.Moon.longitude + 180) % 360) / 30) + 1 };\n positions.Ketu = { longitude: (positions.Rahu.longitude + 180) % 360, sign: Math.floor(((positions.Rahu.longitude + 180) % 360) / 30) + 1 };\n \n return positions;\n}\n\n// Конвертация долготы в ворота\nfunction longitudeToGate(longitude) {\n const gate = Math.floor(longitude / 5.625) + 1;\n const degreeInGate = longitude % 5.625;\n const line = Math.floor(degreeInGate / 0.9375) + 1;\n return { gate: Math.min(64, gate), line };\n}\n\n// Определить тип\nfunction determineType(gates) {\n const gateNumbers = gates.map(g => g.gate);\n const hasSacral = CENTER_GATES.Sacral.some(g => gateNumbers.includes(g));\n const hasThroat = CENTER_GATES.Throat.some(g => gateNumbers.includes(g));\n const hasSolarPlexus = CENTER_GATES.SolarPlexus.some(g => gateNumbers.includes(g));\n \n if (hasSacral && hasThroat) return { name: 'Manifesting Generator', ru_name: 'Манифестирующий Генератор' };\n if (hasSacral) return { name: 'Generator', ru_name: 'Генератор' };\n if (!hasThroat) return { name: 'Reflector', ru_name: 'Рефлектор' };\n if (hasSolarPlexus) return { name: 'Projector', ru_name: 'Проектор' };\n return { name: 'Manifestor', ru_name: 'Манифестор' };\n}\n\n// Основной расчет\nconst locationInfo = findTimezoneByCity(birthLocation);\nconst utcData = convertLocalToUTC(birthDate, birthTime, birthLocation);\nconst positions = calculatePlanetPositions(`${utcData.utcYear}-${utcData.utcMonth}-${utcData.utcDay}`, `${utcData.utcHour}:${utcData.utcMinute}`);\nconst allGates = [];\n\nObject.entries(positions).forEach(([planet, pos]) => {\n const { gate, line } = longitudeToGate(pos.longitude);\n allGates.push({\n planet, gate, line,\n name: GATES[gate]?.name || 'Unknown',\n ru_name: GATES[gate]?.ru_name || 'Неизвестно',\n sign: pos.sign\n });\n});\n\nconst type = determineType(allGates);\nconst strategy = {\n 'Manifestor': 'Информировать',\n 'Generator': 'Отвечать',\n 'Manifesting Generator': 'Отвечать и информировать',\n 'Projector': 'Ждать приглашения',\n 'Reflector': 'Ждать полного лунного цикла'\n}[type.name] || 'Отвечать';\n\nconst sunPos = positions.Sun;\nconst sunGate = longitudeToGate(sunPos.longitude);\nconst earthGate = longitudeToGate((sunPos.longitude + 180) % 360);\nconst profile = {\n sun_line: sunGate.line,\n earth_line: earthGate.line,\n number: `${sunGate.line}/${earthGate.line}`\n};\n\n// Определенные центры\nconst definedCenters = [];\nconst gateNumbers = allGates.map(g => g.gate);\nObject.entries(CENTER_GATES).forEach(([name, gates]) => {\n if (gates.some(g => gateNumbers.includes(g))) {\n definedCenters.push({ name, defined: true });\n }\n});\n\nreturn {\n json: {\n birthDate,\n birthTime,\n birthLocation,\n timezone: locationInfo.timezone || 'Europe/Moscow',\n latitude: locationInfo.lat,\n longitude: locationInfo.lon,\n utcData,\n type,\n strategy,\n profile,\n gates: allGates,\n definedCenters,\n calculationSource: 'n8n Universal Timezone'\n }\n};"
},
"name": "Calculate HD with Timezone",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [460, 300]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}"
},
"name": "Respond",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [680, 300]
}
],
"connections": {
"Webhook Entry": {
"main": [
[
{
"node": "Calculate HD with Timezone",
"type": "main",
"index": 0
}
]
]
},
"Calculate HD with Timezone": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [],
"triggerCount": 1,
"updatedAt": "2024-01-01T00:00:00.000Z",
"versionId": "1"
}