Por qué un EPG muestra la hora equivocada: marcas de tiempo y desfases XMLTV

Una guía que va desplazada un número entero de horas casi nunca es un misterio. Es un sufijo que venía en el archivo y no se respetó.

<programme start="20260719150000 +0200" stop="20260719160000 +0200" channel="one.example.com">

Catorce dígitos, un espacio y luego cinco caracteres que deciden si esa fila empieza a las 15:00 o a las 13:00. Los catorce dígitos no son un instante. Son la lectura de un reloj de pared sin ningún lugar asociado, y una guía de programación correcta depende de que esos cinco últimos caracteres se lean, o de que su ausencia se interprete como quería el grabber que escribió el archivo.

Antes de tocar nada, mide el desplazamiento. Si todos los programas de todos los canales van desplazados el mismo número entero de horas, lo que falla es una sola cosa, y casi siempre es un desfase que venía en el archivo y no se respetó. Si unos canales están bien y otros mal, o si una fila está desplazada y las de arriba y abajo están bien, eso es otro fallo distinto y nada del trabajo con desfases que viene abajo lo va a tocar.

Nuestro reproductor analiza la guía en tu dispositivo, contra la dirección a la que lo apuntas. Nosotros curamos direcciones de guía, y el mismo analizador corre de nuestro lado sobre las curadas para trabajo de catálogo. Una dirección de guía que tú proporcionas se descarga y se lee en tu máquina, y nunca guardamos tus datos de guía.

Una guía entera desplazada y un solo programa mal son fallos distintos

Un desplazamiento uniforme tiene tres causas plausibles y se distinguen en un minuto.

La primera es un desfase que el archivo traía y el lector tiró. La segunda es un desfase que el archivo nunca trajo: el grabber escribió horas locales de reloj de pared sin sufijo y el lector no tenía forma de saberlo. La tercera es una corrección aplicada dos veces, una por la fuente y otra por ti, que es la primera a la que la gente echa mano y la que produce un desplazamiento exactamente del doble de lo que hayan puesto. Si tu guía pasó de ir una hora desplazada a ir tres después de que pusieras una corrección de dos horas, ese es el tercer caso, y la respuesta es devolver la corrección a cero antes de diagnosticar nada más.

Medirlo son dos comparaciones y un reloj. Elige un programa que esté en emisión ahora mismo y anota cuánto se aleja de la realidad la hora de inicio que declara; repite con un segundo canal de la misma fuente y luego con un canal de otra fuente distinta. El mismo error en los dos canales de una fuente y ningún error en la otra fuente lo acota al archivo de esa fuente. El mismo error en todas partes apunta más bien al reloj del dispositivo, que es una reparación completamente distinta.

Un desplazamiento no uniforme no es un problema de zona horaria en absoluto. La causa habitual es que la fila de guía está enganchada al canal equivocado, con lo que la programación correcta de otra emisora parece la programación equivocada de la tuya. Eso es un fallo de identidad, y su forma es el tema de otro artículo. Que haya un id en la lista de reproducción no es lo mismo que un id que case con tu guía: en la mayor de las dos listas que medimos, 527 de 1895 filas acababan sin ningún id utilizable. Las otras causas no uniformes son duraciones y no horas de inicio, y se tratan más abajo.

Un sufijo que empieza por un signo ya te ha dicho que es un número

Esta es la regla que aplica nuestro lector de marcas de tiempo, con el comentario que tiene encima, literal:

var suffix = value[14..].Trim();
if (suffix.Length > 0 && (suffix[0] == '+' || suffix[0] == '-'))
{
    // A suffix that looks like a numeric offset must read as one. Falling
    // through to the assumed timezone here is what used to shift a whole
    // feed by hours with nothing in the logs: the offset was present, said
    // +02:00, and was read as UTC.
    if (!TryParseOffset(suffix, out var offset))
    {
        return false;
    }

Ese comentario describe un fallo nuestro. Lo hicimos mal en una versión anterior de este lector, que trataba un desfase ilegible igual que trataba la ausencia total de desfase: seguir de largo, asumir UTC, continuar. El síntoma era una guía desplazada exactamente el tamaño del desfase que el archivo declaraba, en todos los canales, todos los días del feed, con un resumen de importación impecable y nada que mirar en el log. La causa fue un return temprano que faltaba. El precio fue que el fallo era indetectable desde dentro de la app: no se movía ningún contador, no se escribía ni una línea de log, y la guía seguía mal hasta que alguien la ponía al lado de un reloj.

Rechazar la fila es peor para ese programa concreto y mucho mejor para la guía. Un programa descartado deja un hueco que se ve. Un feed reinterpretado en silencio es una programación uniformemente equivocada y muy segura de sí misma, y por mucho que la mires no te lo va a decir.

Esa regla tiene un agujero, y conviene decirlo claro. La comprobación solo mira el primer carácter del sufijo. Un sufijo escrito como GMT+0200, con la etiqueta delante del signo en vez de detrás, no empieza por un signo, así que toma el camino silencioso. Pasado por el analizador que enviamos, devuelve 15:00 UTC para una hora local de 15:00; es decir, el desfase está ahí, en la cadena, y se ignora. Ningún test fija esa forma, y no tenemos corpus XMLTV propio, así que la ausencia de un caso testigo no es prueba de que sea raro.

Se leen tres formas de desfase y se rechazan siete

Después del signo, el lector toma todo hasta el primer espacio y mide la serie de dígitos. Solo tres longitudes significan algo: dos caracteres para un desfase de solo horas, cuatro para horas y minutos pegados, y cinco cuando el tercer carácter es un dos puntos. +02, +0200 y +02:00 se resuelven los tres a las mismas dos horas. Cualquier cosa de menos de tres caracteres en total se rechaza antes de llegar al switch, y cualquier otra longitud sale por una rama por defecto.

Las tres formas son ISO 8601, y por eso se leen las tres. +0200 es la forma básica, +02:00 la extendida y +02 la de solo horas, y el DTD de XMLTV escribe su propio ejemplo en la forma básica, como +0300. Bendecir una forma y dar las otras dos por UTC en silencio dejaría desplazado una hora o más a cualquier feed que hubiera elegido distinto.

Alrededor de eso hay dos tolerancias. El espacio delante del signo es opcional, porque el sufijo se define como todo lo que va del carácter quince en adelante, así que 20260719150000+0200 funciona igual. Y una etiqueta de zona detrás de un desfase real se descarta en vez de tratarse como daño: +0100 BST se corta en el espacio, lee +0100 y da 14:00 UTC para una hora local de 15:00. Las zonas de media hora salen gratis, porque los minutos se analizan como sus propios dos dígitos, así que +05:30 se resuelve bien.

Esa frontera del carácter quince tiene una consecuencia que no diseñó nadie. El núcleo de fecha se toma como exactamente los primeros catorce caracteres, así que una marca de tiempo con un decimoquinto dígito, 202607191500000, analiza sus primeros catorce sin problema y le pasa el 0 suelto al lector de sufijos, que ve un carácter que no es un signo y toma el camino sin desfase. Pasado por el analizador, ese valor devuelve 15:00 UTC y el dígito de más se descarta sin decir nada. Ese es el resultado inofensivo para una Z final, que la misma caída por defecto gestiona y que además resulta que significa UTC, y un truncamiento silencioso para cualquier otra cosa. El caso de la Z solo es inofensivo porque nada en la app que enviamos fija una zona horaria asumida, y eso tiene su propia sección más abajo.

Estas siete están fijadas por test como fallos, y cada una nombra una clase real de daño:

  • +2, una hora de un solo dígito, demasiado corta para llegar al switch
  • +02:0, una forma con dos puntos a la que le falta un dígito
  • +0X30, una letra dentro de la serie de dígitos
  • +2400, veinticuatro horas
  • +99:00, noventa y nueve horas
  • -0270, setenta minutos
  • +, un signo y nada más

Dos guardas producen la mayoría de esos rechazos. Los minutos por encima de 59 se rechazan de plano, y la magnitud total se limita a 14 horas, porque el tipo de fecha subyacente rechaza cualquier cosa que pase de ahí y, como dice el comentario del código, «a guide claiming one is corrupt rather than exotic» (una guía que declare uno de esos está corrupta, no es exótica). El tope incluye ese valor, así que +1400 se resuelve a una hora pasada la medianoche UTC y +1401 falla. La prueba de dígitos exige además dígitos ASCII en concreto y analiza sin ningún estilo numérico habilitado, así que no se cuela ningún signo delante, ningún separador de millares ni ningún dígito de ancho completo por un análisis permisivo sensible a la cultura.

Nuestro lector rechaza dos de las tres marcas de tiempo de ejemplo del DTD

El DTD no solo permite la forma de catorce dígitos. Dice que una fecha puede ser YYYYMMDDhhmmss o alguna subcadena inicial de esa forma, e imprime tres ejemplos: 200007281733 BST, 200209 y 19880523083000 +0300. Solo el tercero sobrevive a nuestro analizador, y se resuelve a 05:30 UTC. El segundo cae en el suelo de longitud, que rechaza cualquier cosa de menos de catorce caracteres antes de intentar analizarla. El primero pasa ese suelo y falla igualmente, porque el lector corta los primeros catorce caracteres como núcleo de fecha y 200007281733 B no es una fecha.

Ese estrechamiento es una decisión nuestra y, cuando salta, no es culpa del archivo. Una marca de tiempo con precisión de minuto no tiene segundos que cortar, una marca de tiempo de año y mes no es la hora de inicio de un programa en ningún sentido útil, y un lector que aceptara cualquiera de las dos se estaría inventando los campos que faltan. Rechazarlas es defendible. Presentarlas como daño no lo es, y la última fila del recorrido de abajo es XMLTV conforme que descartamos.

El primer ejemplo del DTD lleva la otra mitad de la asimetría de este artículo en un solo paréntesis. Ahí 200007281733 BST viene anotado como (BST == +0100.), o sea que el documento que define el formato resuelve justo la abreviatura que nuestro lector se niega a resolver.

Por qué se cree a +0100 BST y no a un BST a secas

Aquí hay una asimetría que parece un descuido y es una decisión. Un sufijo +0100 BST se resuelve a más una hora, porque el número está y la etiqueta se tira. Un sufijo BST a solas se resuelve a UTC, que es una hora de error en todas las fechas de verano británico en las que aparezca. Las dos cosas están fijadas por tests, o sea que las dos son a propósito.

Las zonas con nombre no se resuelven nunca, y el comentario da la razón: «the abbreviations are ambiguous across regions» (las abreviaturas son ambiguas entre regiones). BST es British Summer Time, y también se ha escrito para Bangladesh Standard Time, cinco horas de diferencia. CST es la colisión que sobrevive en la propia base de datos tz, y la llevan a la vez Chicago, La Habana y Shanghái. Resolver un nombre significa elegir una de ellas, es decir, adivinar, y una conjetura que acierta en un mercado y falla en otro es peor que una regla que se equivoca igual en todas partes.

Elegimos la respuesta que se equivoca de forma conocida por una regla fija antes que la conjetura, y eso cuesta una hora en las fechas de verano de cualquier feed que etiquete sus horas así en vez de numerarlas. Que el DTD anote su propio ejemplo lo hace más difícil de defender de lo que parecía antes de escribir este artículo: la documentación del propio formato resolvió una abreviatura, y el párrafo de arriba es todo el argumento que tenemos para seguir sin hacerlo.

Es una limitación real y no sabemos con qué frecuencia aparece esa forma, porque un nombre de zona a secas es exactamente la entrada que no produce ningún error, ningún contador y ninguna queja hasta que alguien compara la guía con un reloj.

La línea de diagnóstico cuenta descartes sin decir por qué

Una marca de tiempo que no se puede analizar no lanza excepción. El atributo no se asigna nunca, el inicio se queda a cero, la fila se rechaza al construirla y un contador se incrementa. Ese contador aflora en el diálogo de configuración de EPG de la fuente, bajo «Última obtención de guía», con este formato:

{0} channels · {1} programmes · {2} dropped · {3} ms

Es la única lectura que tienes, y es honesta con el total y muda con el motivo. Tres condiciones sin relación entre sí incrementan el mismo número: un programa sin atributo channel, un programa cuya marca de tiempo de inicio falló y un programa que cayó fuera de la ventana de retención.

La ventana es de donde suele salir un número grande, y no es una sola ventana. Siempre empieza 24 horas por detrás del instante de análisis. Termina ocho días por delante para una guía por fuente, cuatro días por delante cuando la descarga sin comprimir supera los 200 MB, y dos días por delante para el almacén de la guía del hogar, que guarda menos porque sostiene todas las fuentes a la vez. Una guía que publique tres semanas de programación va a informar por tanto de un recuento de descartes enorme en una importación perfectamente sana, y el mismo archivo informará de uno mucho mayor en cuanto se active el almacén de la guía del hogar. Un número alto es un motivo para mirar, no una prueba de que haya un problema de hora.

Lo incómodo es que nuestro modo de fallo más ruidoso es un solo entero en un diálogo que nadie abre a menos que algo ya se vea mal.

Un stop malo te cuesta tres horas, no un programa

Un desfase ilegible en la marca de tiempo de start descarta la fila. Un desfase ilegible en la de stop, no.

Cuando el start se analiza y el stop no, el stop se queda a cero, con lo que no pasa la prueba de «el stop es posterior al start», y a la fila se le da una duración por defecto de tres horas. Un recorte aparte limita cualquier programa a seis horas; aquí se queda inerte, porque tres es menos que seis, y solo muerde en filas cuyo stop sí se analiza y cae muy lejos. Ni el valor por defecto ni el recorte incrementan el contador de descartes. Así que un archivo con los atributos stop mal formados de una manera en que los start no lo están produce una guía con horas de inicio correctas, bloques de tres horas por todas partes, filas solapadas y un resumen de importación impecable. Esa es una forma habitual detrás de los informes de una guía en la que las horas parecen bien pero no cuadra nada.

Entran seis programas y salen cuatro

Este es un fragmento construido para ejercitar todos los caminos a la vez. Se ejecutó contra el analizador que enviamos, en vez de seguirlo a mano. Cada id de canal usa un dominio de ejemplo reservado y todos los títulos son inventados, y conviene que asumas que la ventana de retención cubre estas fechas; si no, la retención se lleva por delante el argumento antes de que a los desfases les toque el turno.

<?xml version="1.0" encoding="UTF-8"?>
<tv>
  <channel id="one.example.com"><display-name>Example One</display-name></channel>
  <programme start="20260719150000 +0200" stop="20260719160000 +0200" channel="one.example.com">
    <title>Clean offset</title>
  </programme>
  <programme start="20260719160000 +02:0" stop="20260719170000 +02:0" channel="one.example.com">
    <title>Broken on both ends</title>
  </programme>
  <programme start="20260719170000 +02:00" stop="20260719180000 +02:0" channel="one.example.com">
    <title>Broken on the stop only</title>
  </programme>
  <programme start="20260719180000 BST" stop="20260719190000 BST" channel="one.example.com">
    <title>Zone name, no number</title>
  </programme>
  <programme start="20260719190000 +0100 BST" stop="20260719200000 +0100 BST" channel="one.example.com">
    <title>Zone name after a number</title>
  </programme>
  <programme start="20260719" stop="20260720" channel="one.example.com">
    <title>Date only</title>
  </programme>
</tv>

La fila uno es el camino feliz: las 15:00 a más dos horas son las 13:00 UTC, y va hasta las 14:00 UTC.

La fila dos lleva +02:0 en los dos atributos. El sufijo empieza por un signo, así que tiene que leerse como desfase; la serie de dígitos son cuatro caracteres y los dos últimos no son ambos dígitos, así que falla. El start no llega a asignarse y la fila se rechaza, lo que deja el contador de descartes en uno.

La fila tres tiene un start limpio y el mismo stop roto. El start se resuelve a las 15:00 UTC. El stop no se resuelve, así que se aplica el valor por defecto de tres horas y la fila ocupa de 15:00 a 18:00 UTC en vez de una hora. No se cuenta nada. Esta fila es la razón por la que el contador de descartes no es una métrica de salud.

La fila cuatro es el caso de la hora en su forma más pura. El sufijo es BST, que no empieza por un signo, así que el lector toma el camino sin desfase y aplica la zona horaria asumida, que es UTC. El grabber quería decir las 17:00 UTC. La guía muestra las 18:00 UTC. No se mueve ningún contador.

La fila cinco lleva la misma etiqueta detrás de un número real, y se resuelve correctamente a las 18:00 UTC. Las filas cuatro y cinco empiezan por tanto las dos a las 18:00 UTC en un mismo canal y solo una de ellas quería hacerlo, que es el aspecto que tiene desde dentro un archivo con dos grabbers detrás.

La fila seis son ocho caracteres, por debajo del suelo de catorce, así que los dos atributos fallan y el contador de descartes sube a dos. Es además la fila que el DTD llamaría legal, una subcadena inicial de una marca de tiempo completa, así que la mitad del daño contado en este fragmento es nuestro estrechamiento y no el archivo.

Cuatro filas llegaron al almacén, y dos de las cuatro están mal de una forma que nada reporta: una empieza una hora tarde y otra dura tres veces lo que dura de verdad. El contador informa de las otras dos y no da el motivo de ninguna.

El desfase se resuelve por instante, no una vez por archivo

El núcleo de fecha se analiza sin ninguna bandera de suposición activada, lo que devuelve un valor cuyo kind es unspecified, y eso es deliberado. Después el lector lo empareja con un desfase de forma explícita. La alternativa, pasarle un valor unspecified a un constructor que rellena el hueco, hace que .NET aplique el desfase propio de la máquina anfitriona, con lo que el mismo archivo produciría una programación distinta en un dispositivo de París y en uno de Túnez, y el almacén dejaría de ser portable entre dos dispositivos de un mismo hogar.

En el camino sin desfase, el desfase de la zona asumida se consulta para ese instante concreto y no una sola vez para todo el archivo. A través de una transición de primavera en una zona de Europa occidental, dos marcas de tiempo separadas dos horas y media en el reloj local salen separadas noventa minutos en UTC, que es lo correcto y es justo en lo que un único desfase a nivel de archivo se equivocaría en todas las filas posteriores al cambio. Las dos horas locales que una transición vuelve inservibles, la hora que ocurre dos veces y la hora que no ocurre nunca, se resuelven las dos al desfase estándar, y volver a analizar devuelve el mismo valor, así que un archivo no puede pintarse como dos guías distintas en dos importaciones consecutivas.

Hay un hueco que conviene reconocer en toda esa maquinaria. El parámetro de zona horaria asumida existe, los dos caminos que ingieren una guía en el dispositivo lo pasan, y los dos pasan null. Nada en la app que enviamos lo fija nunca, y hay un test que lo deja fijado. Una guía que escribe horas locales de reloj de pared a secas, sin sufijo, se lee como UTC, que es el valor por defecto documentado del DTD, y no hay ningún control por fuente que cambie cómo se analiza. Todo lo del párrafo anterior sobre transiciones es maquinaria a la que hoy no llega ningún camino de código de los que enviamos.

La corrección horaria es en horas enteras, y hay dos sitios que la desactivan

Existe una corrección, y trabaja en otra capa. Cada fuente lleva un desfase horario en horas enteras, de menos 48 a más 48, editable en ese mismo diálogo de configuración de EPG bajo «Desfase horario (horas enteras)», con el campo etiquetado «Horas a añadir». Se aplica cuando la programación se lee del almacén, no cuando entra, así que cambiarla no obliga a volver a descargar nada y no reescribe lo que se guardó.

Hay dos cosas que a propósito no hace. Es solo en horas enteras, así que no puede corregir una zona de media hora, y con ella no se recupera una fuente de una región +05:30 que se haya leído como UTC. Y se fuerza a cero en dos casos. El primero es el almacén de la guía del hogar, que se normaliza a UTC al ingerir y no deja nada que una corrección pueda arreglar. El segundo es cualquier canal que pertenezca a una fuente agregada, donde el canal está respaldado por varios miembros a la vez y el desfase correcto depende de cuál lo esté sirviendo. Un solo número sería erróneo para todos menos uno, así que el control no se ofrece, en vez de ofrecerse y mentir.

Esa última decisión es la primera que revisaría yo si cambiara la evidencia. Es defendible, y a la vez significa que la vía de escape falta justo donde un hogar tiene más fuentes y más probabilidades de que una de ellas esté mal.

Nuestras apps de Windows y Xbox hacen todo este análisis en local, sobre una dirección de guía que ya tienes. La línea de diagnóstico y el control de corrección están en el mismo diálogo por una razón: el primer número te dice si el archivo se está leyendo siquiera, y el segundo es a lo que echas mano una vez que sabes que sí.

Si estás escribiendo tu propio lector, la regla que te salva es la que más nos costó aprender. Un sufijo que empieza por un signo ya te ha dicho que es un número. Léelo o haz fallar la fila, pero no caigas a un valor por defecto, porque un valor por defecto se aplica de forma uniforme y con total seguridad a todas las marcas de tiempo del archivo, y equivocarse de forma uniforme y segura es el único fallo que no reporta nadie.

Lo que midió este artículo28 afirmaciones, cada una con la evidencia detrás de ellas
Reclamarevidenciacontado
La definición de tipo de documento de XMLTV dice que una marca de tiempo que no lleva zona horaria explícita se lee como UTC.xmltv.dtd, date field documentation: you can also append a timezone to the end; if no explicit timezone is given, UTC is assumed.EspecificaciónNo aplicable
El DTD de XMLTV escribe su propio desfase de ejemplo en la forma básica de cuatro dígitos, como +0300.xmltv.dtd, date field documentation, example 19880523083000 +0300EspecificaciónNo aplicable
El DTD de XMLTV permite que una fecha sea YYYYMMDDhhmmss o alguna subcadena inicial de esa forma, e imprime 200007281733 BST, 200209 y 19880523083000 +0300 como sus tres ejemplos.xmltv.dtd, date field documentation, including the annotation (BST == +0100.) on the first exampleEspecificaciónNo aplicable
ISO 8601 escribe un desfase UTC en tres formas: básica (+0200), extendida (+02:00) y solo horas (+02).ISO 8601-1, time offset from UTCEspecificaciónNo aplicable
Un DateTimeOffset de .NET rechaza un desfase cuya magnitud supera las 14 horas, y acepta exactamente 14 horas..NET DateTimeOffset constructor, offset argument range -14:00 to +14:00 inclusiveEspecificaciónNo aplicable
Construir un DateTimeOffset a partir de un DateTime cuyo Kind es Unspecified aplica el desfase local de la máquina anfitriona..NET DateTimeOffset(DateTime) constructor remarks, which treat an Unspecified Kind as local timeEspecificaciónNo aplicable
Las abreviaturas de zona no son únicas: CST la llevan a la vez America/Chicago, America/Havana y Asia/Shanghai, y BST es British Summer Time y también se ha escrito para Bangladesh Standard Time, cinco horas de diferencia.IANA time zone database, theory.html on the ambiguity of zone abbreviations, plus the CST abbreviation on America/Chicago, America/Havana and Asia/ShanghaiEspecificaciónNo aplicable
Un sufijo de marca de tiempo que empieza por + o - tiene que analizarse como desfase numérico, o falla la marca de tiempo entera. Caer en la zona horaria asumida es el defecto que llegamos a publicar y que esta regla sustituyó.n = 222 ago 2026
Solo se aceptan series de dígitos de longitud 2, 4 o 5 con dos puntos en el índice 2, así que +02, +0200 y +02:00 se resuelven los tres; cualquier otra longitud sale por la rama por defecto.n = 322 ago 2026
Siete formas de desfase están fijadas por test como fallos de análisis: +2, +02:0, +0X30, +2400, +99:00, -0270 y un + suelto.n = 722 ago 2026
Los minutos por encima de 59 se rechazan y la magnitud total se limita a 14 horas inclusive, así que +1400 se resuelve y +1401 no; el lector de dos dígitos exige dígitos ASCII y analiza con NumberStyles.None.n = 222 ago 2026
Una etiqueta de zona detrás de un desfase real se descarta en el primer espacio, así que +0100 BST se resuelve a +01:00 y una hora local de 15:00 da 14:00 UTC.n = 122 ago 2026
Un nombre de zona alfabético a secas nunca llega al lector de desfases y toma el camino de la zona horaria asumida, así que 20260719150000 BST y 20260719150000 UTC se resuelven los dos a 15:00 UTC.n = 222 ago 2026
Nuestro lector rechaza dos de las tres marcas de tiempo de ejemplo que imprime el DTD de XMLTV: 200007281733 BST y 200209 fallan las dos, y solo 19880523083000 +0300 se analiza, a 05:30 UTC.n = 322 ago 2026
Una marca de tiempo de menos de 14 caracteres se rechaza antes de intentar ningún análisis, así que un valor de solo fecha falla.n = 122 ago 2026
El núcleo de fecha son exactamente los primeros 14 caracteres, así que un decimoquinto dígito suelto acaba en el sufijo, no pasa la prueba del signo y se descarta en silencio.n = 122 ago 2026
La regla del error tajante se fija en el primer carácter del sufijo, así que una forma con la etiqueta delante, como GMT+0200, toma el camino de la zona horaria asumida y se lee como UTC ignorando el desfase.n = 122 ago 2026
El mismo contador de descartes se incrementa por un atributo channel ausente, un start que no se puede analizar y un programa fuera de la ventana de retención.n = 322 ago 2026
La ventana de retención siempre empieza 24 horas por detrás del instante de análisis y termina ocho días por delante en el camino por fuente, cuatro días cuando la descarga sin comprimir supera los 200 MB y dos días en el almacén de la guía del hogar.n = 322 ago 2026
Un programa con un start válido y un stop que no se puede analizar se conserva con una duración por defecto de tres horas y no cuenta como descartado; el máximo aparte de seis horas no llega a morderlo.n = 122 ago 2026
La lectura de la última obtención se formatea como canales, programas, descartados y milisegundos, bajo el encabezado Última obtención de guía.n = 122 ago 2026
La corrección por fuente es en horas enteras, de -48 a +48, etiquetada Desfase horario (horas enteras) con el campo Horas a añadir, y se aplica al leer y no al ingerir.n = 122 ago 2026
La corrección se fuerza a cero cuando el almacén de la guía del hogar está activo y cuando el canal pertenece a una fuente agregada.n = 222 ago 2026
Los dos caminos de ingesta del dispositivo construyen la tubería de análisis con assumeTimezone en null, así que una marca de tiempo a secas se lee como UTC y la zona horaria del equipo nunca entra en juego.n = 222 ago 2026
En el camino de la zona horaria asumida el desfase se resuelve por instante, así que dos horas locales separadas dos horas y media a través de una transición de primavera salen separadas noventa minutos en UTC.n = 222 ago 2026
La hora local repetida y la hora local inexistente se resuelven las dos al desfase estándar, y volver a analizar devuelve el mismo valor.n = 322 ago 2026
El fragmento hecho a mano de este artículo da 1 canal, 4 filas almacenadas y 2 descartes; una fila almacenada empieza una hora tarde y otra dura tres horas en vez de una.n = 622 ago 2026
En la mayor de las dos listas de reproducción de nuestro corpus M3U, 527 de 1895 filas acaban sin ningún id de canal utilizable, así que una fila de guía no tiene nada fiable a lo que engancharse.n = 189522 ago 2026