Marcas de tiempo Unix en sistemas embebidos, API y bases de datos
Diseña marcas de tiempo de sensores con RTC, NTP, relojes monótonos, JSON y SQL, con un ejemplo de sincronización ESP32.
Una medición útil combina valor, referencia temporal e incertidumbre. Unix facilita la interoperabilidad sin garantizar exactitud ni orden. Inspecciona registros con Convertidor Unix Timestamp / Epoch y consulta las bases en Comprender las marcas de tiempo Unix y Epoch.
RTC y reloj del sistema
Un RTC conserva calendario o contador durante el reposo de la CPU, a menudo con alimentación de respaldo. No está necesariamente en UTC ni sincronizado. El reloj del sistema relaciona una base de hardware con una época. Valida el RTC después de una pérdida de alimentación: su fecha predeterminada no es una medida.
STM32, ESP32 y Linux embebido
En STM32, registros de subsegundos, dominio de respaldo y funciones RTC dependen de la familia; consulta su manual y ST AN4759. No existe un registro Unix universal. ESP-IDF combina temporizadores RTC y de alta resolución según la configuración. Linux ofrece CLOCK_REALTIME y relojes monótonos. Comprueba libc y ABI además de la arquitectura de CPU.
Sincronización NTP y SNTP
NTP estima desplazamiento y retardo de red; SNTP simplifica el cliente. La asimetría de los paquetes sigue siendo una fuente de error. La época y las eras de NTP no son segundos Unix: deja la traducción a la pila. Conserva estado, antigüedad e incertidumbre de sincronización. Un salto cambia la hora de golpe; un ajuste gradual modifica temporalmente la velocidad del reloj.
Reloj civil frente a reloj monótono
El reloj civil indica una fecha UTC y puede saltar al corregirse. El monótono mide duraciones desde un origen arbitrario, no una fecha UTC; puede reiniciarse al arrancar y su comportamiento durante suspensión depende del reloj. Úsalo para plazos y reintentos, y añade una referencia UTC para correlacionar dispositivos.
Horodatación de sensores
Captura la hora cerca de la muestra ADC o de la interrupción que define la medición. El envío incluye colas, radio y retransmisiones; conserva aparte la recepción del servidor. Para bloques, registra origen, período y secuencia considerando la deriva. La guía de muestreo complementa este diseño.
Registros y telemetría
Incluye identidad de dispositivo, arranque y secuencia. Una corrección hacia atrás puede repetir marcas UTC sin repetir el evento. Distingue la hora medida de la reconstruida. Ordenar solo por UTC no garantiza causalidad entre dispositivos cuyas incertidumbres se solapan.
Elegir unidades y presupuesto de error
| Unidad de la marca | 1 s | 1700000000 s |
|---|---|---|
| Segundos (s) | 1 | 1700000000 |
| Milisegundos (ms) | 1000 | 1700000000000 |
| Microsegundos (µs) | 1000000 | 1700000000000000 |
| Nanosegundos (ns) | 1000000000 | 1700000000000000000 |
Los segundos sirven para planificación gruesa, milisegundos para mucha telemetría, microsegundos para adquisición adecuada y nanosegundos para hardware que los soporte. Resolución, repetibilidad y exactitud son propiedades distintas. Un error libre de 20 ppm acumula unos 1,728 s en 24 horas nominales; temperatura y envejecimiento pueden variarlo.
API REST y JSON
{
"timestamp_ns": "1700000000123456789",
"captured_at": "2023-11-14T22:13:20.123456789Z",
"time_quality": "synced",
"uncertainty_ms": 20,
"boot_id": "device-session-42",
"sequence": 17
}
Documenta época, unidad, signo y rango. Usa cadenas decimales para valores grandes si los clientes emplean binary64. JSON.stringify no acepta BigInt directamente. timestamp_ns evita deducir la unidad. Una hora desconocida debe ser null con metadatos de calidad, en vez de una fecha ficticia de 1970.
ISO 8601 y RFC 3339
Incluye Z o desplazamiento numérico y una precisión fraccionaria acordada. 2023-11-14T22:13:20Z y 2023-11-14T23:13:20+01:00 son el mismo instante. Una fecha sin sufijo no determina UTC. El desplazamiento no conserva las reglas futuras de Europe/Paris.
Almacenamiento SQL
CREATE TABLE sensor_measurement (
device_id text NOT NULL,
boot_id text NOT NULL,
sequence bigint NOT NULL,
captured_at timestamptz,
monotonic_us bigint NOT NULL,
time_quality text NOT NULL,
temperature_c double precision NOT NULL,
PRIMARY KEY (device_id, boot_id, sequence)
);
INSERT INTO sensor_measurement VALUES ('sensor-1', 'boot-42', 17,
TIMESTAMPTZ '2023-11-14T22:13:20.123456Z', 9812370, 'synced', 23.625);
Este ejemplo usa PostgreSQL. timestamptz guarda un instante y lo presenta según la zona de la sesión, sin conservar el identificador IANA original. Guárdalo aparte si hace falta. La precisión es de microsegundos; los nanosegundos exactos requieren otro campo entero o decimal. Otros motores SQL tienen reglas distintas. El índice temporal y la identidad dispositivo/arranque/secuencia cumplen funciones diferentes.
UTC y horarios locales
Almacena eventos en UTC. Una regla diaria a las 08:00 en París necesita hora local y zona IANA porque su UTC cambia con el horario de verano. Define qué ocurre cuando la hora se omite o se repite. Añadir 86400 segundos Unix no garantiza la misma hora local al día siguiente.
Límites de time_t
No deduzcas time_t de sizeof(void*). Un campo de segundos de 32 bits con signo llega a 2038 incluso si otra parte del equipo es de 64 bits. ESP-IDF usa time_t de 64 bits con signo desde v5.0; firmware y protocolos antiguos pueden seguir limitados. Revisa formatos printf, bases de datos, cargadores, controladores RTC y migraciones OTA.
Ejemplo ESP32 con NTP y datos de sensor
Este código para ESP-IDF 5.x/6.x se llama una vez después de inicializar esp-netif y conectar Wi-Fi o Ethernet. El controlador de la placa entrega a log_sensor una temperatura finita. Espera hasta 15 segundos por la sincronización y emite un registro JSON por adquisición.
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "esp_netif_sntp.h"
#include "esp_timer.h"
#include "esp_random.h"
static bool clock_synced;
static int64_t last_sync_us;
static uint32_t boot_id;
static uint64_t sequence;
void ntp_after_network_ready(void) {
boot_id = esp_random();
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
esp_netif_sntp_init(&config);
clock_synced = esp_netif_sntp_sync_wait(pdMS_TO_TICKS(15000)) == ESP_OK;
if (clock_synced) last_sync_us = esp_timer_get_time();
}
void log_sensor(double temperature_c) {
int64_t monotonic_us = esp_timer_get_time();
struct timeval tv;
bool valid = clock_synced && monotonic_us - last_sync_us < INT64_C(3600000000)
&& gettimeofday(&tv, NULL) == 0;
printf("{\"boot_id\":\"%08" PRIx32 "\",\"sequence\":%" PRIu64
",\"monotonic_us\":\"%" PRId64 "\",\"timestamp_us\":",
boot_id, sequence++, monotonic_us);
if (valid) {
int64_t utc_us = (int64_t)tv.tv_sec * INT64_C(1000000) + tv.tv_usec;
printf("\"%" PRId64 "\"", utc_us);
} else printf("null");
printf(",\"time_quality\":\"%s\",\"temperature_c\":%.3f}\n",
valid ? "synced" : "unsynced", temperature_c);
}
timestamp_us y monotonic_us son cadenas decimales. Sin sincronización, UTC es null y se conserva el orden. La ventana de una hora es una política ilustrativa, no una garantía de exactitud. El ejemplo no renueva la confianza tras sincronizaciones automáticas: en producción actualiza last_sync_us mediante notificación, protege el estado compartido y gestiona reconexiones e incertidumbre. El identificador aleatorio de arranque de 32 bits es ilustrativo; usa un contador persistente o un identificador robusto si las colisiones importan.
Reinicios, deriva y pérdida de sincronización
Un reinicio crea una nueva línea monótona. Conserva su identidad y no unas contadores de arranques distintos sin validación. Durante desconexiones aumenta la incertidumbre según el oscilador y la última referencia válida. Un RTC respaldado ayuda, pero necesita calidad explícita. Haz visibles las correcciones grandes sin reescribir silenciosamente medidas históricas.
Buenas prácticas y pruebas
- Definir época, unidad y signo en cada interfaz.
- UTC para eventos y reloj monótono para plazos.
- Conservar secuencia, identidad de arranque y calidad temporal.
- Probar arranque sin red, batería RTC agotada, saltos hacia atrás, cambios de hora y límites enteros.
- Actualizar datos de zona para calendarios futuros.
Preguntas técnicas
¿NTP garantiza microsegundos de exactitud?
No. Persisten asimetría de red, planificación y latencia de adquisición. Mide la cadena completa y declara una incertidumbre adecuada.
¿Basta un contador monótono para obtener UTC?
Necesita una correspondencia con UTC, modelo de deriva, antigüedad e incertidumbre. No es válida automáticamente tras reiniciar.
¿Conviene guardar todo en hora local?
Guarda instantes en UTC y una zona separada para horarios civiles o contexto original. Convierte al presentar.
Herramientas y referencias
Convertidor Unix Timestamp / Epoch · Comprender las marcas de tiempo Unix y Epoch · Tolerancia de osciladores.
- IETF · RFC 3339
- IETF · RFC 5905 (NTP)
- IETF · RFC 8259 (JSON)
- Python · PEP 418
- Espressif · ESP-IDF
- STMicroelectronics · AN4759
- PostgreSQL · SQL
Herramientas y guías relacionadas
Calculadora de condensadores de carga de cristal · Leer la guía de diseño completa