Pico y Placa Bello

`; } }); function getTZ(root){ return (root.getAttribute('data-tz') || 'America/Bogota').trim() || 'America/Bogota'; } function nowPartsInTZ(tz){ const dtf = new Intl.DateTimeFormat('en-CA', { timeZone: tz, year:'numeric', month:'2-digit', day:'2-digit', hour:'2-digit', minute:'2-digit', second:'2-digit', hour12:false }); const parts = dtf.formatToParts(new Date()); const m = {}; for (const p of parts) if (p.type !== 'literal') m[p.type] = p.value; return { year:+m.year, month:+m.month, day:+m.day, hour:+m.hour, minute:+m.minute, second:+m.second }; } function ymdFromParts(p){ return `${p.year}-${pad2(p.month)}-${pad2(p.day)}`; } function minutesOfDayFromParts(p){ return p.hour*60 + p.minute; } function dateUTCNoonFromYMD(ymd){ const [y,m,d] = ymd.split('-').map(Number); return new Date(Date.UTC(y, m-1, d, 12, 0, 0)); } function addDaysYMD(ymd, delta){ const dt = dateUTCNoonFromYMD(ymd); dt.setUTCDate(dt.getUTCDate() + delta); return `${dt.getUTCFullYear()}-${pad2(dt.getUTCMonth()+1)}-${pad2(dt.getUTCDate())}`; } function fmtTimeNoSeconds(tz){ return new Intl.DateTimeFormat('es-CO', { timeZone: tz, hour:'numeric', minute:'2-digit', hour12:true }).format(new Date()); } function weekdayUpperES(tz, ymd){ const dt = dateUTCNoonFromYMD(ymd); const w = new Intl.DateTimeFormat('es-CO', { timeZone: tz, weekday:'long' }).format(dt); return String(w).toUpperCase(); } function prettyDateES(ymd){ const [y,m,d] = ymd.split('-').map(Number); const meses = ['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic']; return `${d} de ${meses[m-1]} ${y}`; } function isHHMM(s){ return /^([01]\d|2[0-3]):([0-5]\d)$/.test(String(s||'').trim()); } function toMinutes(hhmm){ if (!isHHMM(hhmm)) return null; const [h,m] = hhmm.split(':').map(Number); return h*60 + m; } function time24to12ES(hhmm){ if (!isHHMM(hhmm)) return String(hhmm||''); const [h,m] = hhmm.split(':').map(Number); const h12 = ((h + 11) % 12) + 1; const suf = h >= 12 ? 'p. m.' : 'a. m.'; return `${h12}:${pad2(m)} ${suf}`; } function scheduleLabel(schedule){ const slots = Array.isArray(schedule) ? schedule : []; if (slots.length === 1 && String(slots[0].start) === "00:00" && String(slots[0].end) === "23:59") return "Todo el día"; const parts = slots .filter(s => s && s.start && s.end) .map(s => `${time24to12ES(String(s.start))} a ${time24to12ES(String(s.end))}`); return parts.length ? parts.join(' · ') : 'Sin restricción'; } function getHorarioEstado(schedule, nowMin){ const slots = (Array.isArray(schedule) ? schedule : []) .map(s => ({ s: toMinutes(String(s.start||'')), e: toMinutes(String(s.end||'')) })) .filter(x => x.s !== null && x.e !== null) .sort((a,b) => a.s - b.s); if (!slots.length) return { kind:'none', endMin:null }; for (const slot of slots){ if (nowMin >= slot.s && nowMin < slot.e) return { kind:'active', endMin: slot.e }; } return { kind:'inactive', endMin:null }; } function countdownHM(endMin, nowMin){ if (endMin === null) return null; const rem = Math.max(0, endMin - nowMin); return { h: Math.floor(rem/60), m: rem % 60 }; } function safeUrl(u){ const s = String(u ?? '').trim(); return /^https?:\/\//i.test(s) ? s : ''; } function dayKeyFromYMD(ymd){ const dt = dateUTCNoonFromYMD(ymd); return ['sun','mon','tue','wed','thu','fri','sat'][dt.getUTCDay()]; } function iconSvg(key){ const common = `width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true"`; const car = ``; const taxi = ``; const truck = ``; const moto = ``; const k = String(key||'').toLowerCase(); if (k.includes('taxi')) return taxi; if (k.includes('carga')) return truck; if (k.includes('moto')) return moto; return car; } function resolveRestriction(city, cat, ymd){ const rule = cat.rule || {}; if (rule.type === "always_no_aplica"){ return { value:"NO APLICA", kind:"na", note:"", schedule: [] }; } if (rule.type === "month_map"){ const ym = ymd.slice(0,7); const bucket = rule.months && rule.months[ym] ? rule.months[ym] : null; if (!bucket) return { value:"SIN INFORMACIÓN", kind:"unknown", note:"No hay calendario cargado para esta fecha.", schedule: [] }; const noA = Array.isArray(bucket.no_aplica) ? bucket.no_aplica : []; if (noA.includes(ymd)) return { value:"NO APLICA", kind:"na", note:"No aplica.", schedule: [] }; const v = bucket.restricted && bucket.restricted[ymd] ? String(bucket.restricted[ymd]) : ""; if (!v) return { value:"SIN INFORMACIÓN", kind:"unknown", note:"No hay dato cargado para esta fecha.", schedule: [] }; return { value: v, kind:"digits", note:"", schedule: cat.schedule || [] }; } return { value:"SIN INFORMACIÓN", kind:"unknown", note:"", schedule: [] }; } function mount(root){ const tz = getTZ(root); const key = String(root.getAttribute("data-key") || "").trim(); const cfg = window.PZ_PYP_DATA && window.PZ_PYP_DATA[key] ? window.PZ_PYP_DATA[key] : null; if (!cfg) throw new Error(`No existe window.PZ_PYP_DATA["${key}"]. Revisa data-key.`); const city = cfg.city; const options = (city.switch && Array.isArray(city.switch.options)) ? city.switch.options : []; root.innerHTML = `
PICO Y PLACA
Hora: --:--
--
--
Si vas a viajar, revisa el pico y placa para la fecha de tu viaje.
`; const $ = (sel) => root.querySelector(sel); const elTitle = $('.pz-title'); const elTime = $('.pz-time'); const elCity = $('.pz-cityselect'); const elWeek = $('.pz-weekday'); const elDate = $('.pz-date'); const elDateInput = $('.pz-dateinput'); const elDateCenter = $('.pz-datecenter'); const elPrevDay = $('.pz-daybtn--left'); const elNextDay = $('.pz-daybtn--right'); const elGrid = $('.pz-grid'); const elFoot = $('.pz-foot'); const elPrevPage = $('.pz-page--prev'); const elNextPage = $('.pz-page--next'); elCity.innerHTML = options .slice() .sort((a,b) => String(a.name||'').localeCompare(String(b.name||''), 'es')) .map(o => ``) .join(''); elCity.value = city.id; let todayTZ = ymdFromParts(nowPartsInTZ(tz)); let selectedYMD = todayTZ; let pageIndex = 0; let pageSize = window.matchMedia('(min-width: 820px)').matches ? 4 : 2; let visibleNodes = new Map(); function getSortedCats(){ return (Array.isArray(city.categories) ? city.categories : []) .slice() .sort((a,b) => (Number(a.priority||99) - Number(b.priority||99)) || String(a.name||'').localeCompare(String(b.name||''), 'es')); } function updateHeader(){ elTitle.textContent = `PICO Y PLACA ${String(city.name || city.id).toUpperCase()}`.trim(); elTime.textContent = `Hora: ${fmtTimeNoSeconds(tz)}`; elWeek.textContent = weekdayUpperES(tz, selectedYMD); elDate.textContent = prettyDateES(selectedYMD); elDateInput.value = selectedYMD; } function updateFooter(){ const srcName = String(city.source && city.source.name ? city.source.name : '').trim(); const srcUrl = safeUrl(city.source && city.source.url ? city.source.url : ''); if (srcUrl) elFoot.innerHTML = `Fuente: ${srcName || 'Fuente oficial'}`; else elFoot.textContent = srcName ? `Fuente: ${srcName}` : ''; } function calcPageSize(){ return window.matchMedia('(min-width: 820px)').matches ? 4 : 2; } function renderPage(){ const cats = getSortedCats(); const newSize = calcPageSize(); if (newSize !== pageSize) { pageSize = newSize; pageIndex = 0; } const totalPages = Math.max(1, Math.ceil(cats.length / pageSize)); pageIndex = Math.min(pageIndex, totalPages - 1); const start = pageIndex * pageSize; const pageCats = cats.slice(start, start + pageSize); const showPager = cats.length > pageSize; elPrevPage.style.display = showPager ? 'flex' : 'none'; elNextPage.style.display = showPager ? 'flex' : 'none'; elGrid.innerHTML = pageCats.map(cat => `
${iconSvg(cat.icon || cat.id)}
${String(cat.name || cat.id).toUpperCase()}
--
Termina en: --
Horario: --
`).join(''); visibleNodes = new Map(); elGrid.querySelectorAll('.pz-card').forEach(card => { const catId = card.getAttribute('data-cat'); visibleNodes.set(catId, { label: card.querySelector('.pz-label'), value: card.querySelector('.pz-value'), cd: card.querySelector('.pz-countdown'), cdText: card.querySelector('.pz-counttext'), band: card.querySelector('.pz-band'), bandText: card.querySelector('.pz-bandtext'), note: card.querySelector('.pz-note') }); }); updateCardsDynamic(); } function updateCardsDynamic(){ const nowP = nowPartsInTZ(tz); todayTZ = ymdFromParts(nowP); const nowMin = minutesOfDayFromParts(nowP); const isTodaySelected = (selectedYMD === todayTZ); const cats = getSortedCats(); for (const cat of cats){ const refs = visibleNodes.get(String(cat.id)); if (!refs) continue; const r = resolveRestriction(city, cat, selectedYMD); const sched = Array.isArray(r.schedule) && r.schedule.length ? r.schedule : (Array.isArray(cat.schedule) ? cat.schedule : []); const schedLabel = scheduleLabel(sched); refs.value.classList.remove('pz-value--na'); const basis = String(cat.plate_basis || 'last'); const labelDigits = (basis === 'first') ? 'Placa inicia en:' : 'Placa termina en:'; if (r.kind === 'na'){ refs.label.textContent = 'Estado hoy:'; refs.value.textContent = 'NO APLICA'; refs.value.classList.add('pz-value--na'); } else if (r.kind === 'unknown'){ refs.label.textContent = 'Estado hoy:'; refs.value.textContent = 'SIN INFORMACIÓN'; } else { refs.label.textContent = labelDigits; refs.value.textContent = String(r.value); } if (r.kind === 'na' || r.kind === 'unknown'){ refs.band.classList.remove('pz-band--yellow'); refs.band.classList.add('pz-band--gray'); refs.bandText.textContent = 'Sin restricción'; } else { refs.band.classList.remove('pz-band--gray'); refs.band.classList.add('pz-band--yellow'); refs.bandText.textContent = `Horario: ${schedLabel}`; } const note = String(r.note || '').trim(); if (note){ refs.note.style.display = 'block'; refs.note.textContent = note; } else { refs.note.style.display = 'none'; refs.note.textContent = ''; } const canCount = isTodaySelected && r.kind !== 'na' && r.kind !== 'unknown' && Array.isArray(sched) && sched.length > 0; if (!canCount){ refs.cd.style.display = 'none'; refs.cdText.textContent = ''; continue; } const st = getHorarioEstado(sched, nowMin); if (st.kind !== 'active'){ refs.cd.style.display = 'none'; refs.cdText.textContent = ''; continue; } const hm = countdownHM(st.endMin, nowMin); refs.cd.style.display = 'flex'; refs.cdText.textContent = `Termina en: ${hm.h}h ${pad2(hm.m)}m`; } elTime.textContent = `Hora: ${fmtTimeNoSeconds(tz)}`; } // Redirección por ciudad elCity.addEventListener('change', () => { const nextId = elCity.value; const target = options.find(o => String(o.id) === String(nextId)); const url = target && target.url ? String(target.url).trim() : ''; if (safeUrl(url)) window.location.href = url; }); elPrevDay.addEventListener('click', () => { selectedYMD = addDaysYMD(selectedYMD, -1); pageIndex = 0; updateHeader(); renderPage(); }); elNextDay.addEventListener('click', () => { selectedYMD = addDaysYMD(selectedYMD, +1); pageIndex = 0; updateHeader(); renderPage(); }); function openPicker(){ if (typeof elDateInput.showPicker === 'function') elDateInput.showPicker(); else elDateInput.focus(); } elDateCenter.addEventListener('click', openPicker); elDateCenter.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' '){ e.preventDefault(); openPicker(); } }); elDateInput.addEventListener('change', () => { if (elDateInput.value){ selectedYMD = elDateInput.value; pageIndex = 0; updateHeader(); renderPage(); } }); elPrevPage.addEventListener('click', () => { const cats = getSortedCats(); const totalPages = Math.max(1, Math.ceil(cats.length / pageSize)); pageIndex = (pageIndex - 1 + totalPages) % totalPages; renderPage(); }); elNextPage.addEventListener('click', () => { const cats = getSortedCats(); const totalPages = Math.max(1, Math.ceil(cats.length / pageSize)); pageIndex = (pageIndex + 1) % totalPages; renderPage(); }); window.addEventListener('resize', renderPage); updateHeader(); updateFooter(); renderPage(); root._pzTimer && clearInterval(root._pzTimer); root._pzTimer = setInterval(() => { updateHeader(); updateCardsDynamic(); }, 30 * 1000); } })();
Redacción Seguros Bolívar

¡Hola! Somos el equipo de redacción. A través de nuestros artículos también queremos brindar tranquilidad y enriquecer la vida con integridad. Por eso, aquí ofrecemos contenidos educativos, recomendaciones, noticias y mucho más. Bienvenidos todos los lectores y las empresas que desean aprender y actualizarse con información de calidad.

Recent Posts

¿Cuánto es el aumento del arriendo en el 2026?

De acuerdo con la ley 820 de 2003, el aumento del arriendo lo determina la inflación y el IPC del…

9 January, 2026

Guía de prevención general para empresas en el 2026

Prepare su empresa para el 2026 con esta guía de prevención, así protegerá su negocio frente a riesgos y garantizará…

9 January, 2026

Seguros Bolívar destaca entre las aseguradoras líderes en sostenibilidad a nivel mundial

Según el CSA 2025, Seguros Bolívar se ubica entre los 12 mejores puntajes en sostenibilidad a nivel mundial en el…

8 January, 2026

Cómo el Seguro para copropiedades le acompaña en los retos del año nuevo

Descubra cómo el Seguro para Copropiedades le ayuda a enfrentar los retos del año nuevo con confianza y protección.

8 January, 2026

Evite el sedentarismo en vacaciones y priorice su salud

Consejos prácticos para evitar el sedentarismo y cuidar su bienestar físico y mental durante las vacaciones.

6 January, 2026

Exámenes médicos para iniciar el 2026

¡Comience el año cuidando su salud! Estos son algunos exámenes de rigor que se debe realizar. ¡Tome lápiz y papel!

6 January, 2026