2013-11-03 17 views
5

Come:Leap secondo la manipolazione nel database

The Unix time number is zero at the Unix epoch, and increases by exactly 86400 
per day since the epoch. So it cannot represent leap seconds. The OS will slow 
down the clock to accomodate for this. 

Quindi, se io sono la memorizzazione di epoca Unix (ad esempio ts) nel DB (precisione milli-secondo), come gestire il caso seguente?

  1. Come assicurarsi che il valore di t sia sempre crescente e senza arretramenti?
  2. Come selezionare esattamente l'intervallo di 100s da db che prendono il conto nel secondo intercalare?

ad es.

SELECT * FROM events WHERE ts >= T1 and ts < T1 + 100 

È possibile che SQL eventi che accadono a T1 tornare, T1 + 1, T1 + 2, ..up a T1 + 99, ma dal momento che a causa di saltare secondi, il risultato potrebbe essere sbagliato includendo il salto tempo di 1s, come tenerne conto?

risposta

4

Inizierò dicendo che non mi sono mai trovato di fronte a un problema del genere nella realtà, quindi suppongo solo che sarà un'ipotesi plausibile. Secondo http://en.wikipedia.org/wiki/Unix_time#Encoding_time_as_a_number quando viene inserito un secondo intercalare il problema è 2 volte (ad esempio 1998-12-31T23: 59: 60.00 e 1999-01-01T00: 00: 00.00) hanno lo stesso tempo Unix (915.148.800.000). Quando viene eliminato un secondo intercalare, non dovrebbero esserci problemi.

In base alla nota n. 2 sulla stessa pagina di Wikipedia i secondi non sono prevedibili, il che lascia 2 scelte: una soluzione generica che (assumendo che la tabella indicizzata da questi timestamp) possa sempre inserire voci e il momento in cui l'inserimento avviene prima dell'ultima voce inserita (probabilmente entro un secondo intercalare) è possibile iniziare un processo di "smear" che aggiunge sostanzialmente alcuni millisecondi alla voce per assicurarsi che cada fuori dal range del secondo intercalare. Il processo può interrompersi nel momento in cui la voce inserita avrà di nuovo un valore maggiore rispetto alla voce precedentemente inserita. Io chiamo questo "striscio" perché è in qualche modo ispirato alla tecnica "Leap Smear" di Google (sebbene non del tutto uguale): http://googleblog.blogspot.in/2011/09/time-technology-and-leaping-seconds.html Il modo in cui lo vedo, però, può mettere a dura prova il database e quella query di inserimento sarebbe quasi una delle query più complesse che ho visto (se è addirittura possibile solo in SQL).

Un'altra soluzione può essere (presumo che tu stia utilizzando Java) che controlli manualmente se il timestamp rientra in un secondo intercalare o meno. Se lo fa, basta bloccare qualsiasi accesso al database e inserire le voci in una coda. Quando il secondo intercalare è finito basta inserire la coda in modo FIFO nel database per garantire l'ordine di cui si preoccupi (simile alla soluzione di cui sopra ma interamente in Java, quindi prima ancora che tocchi il livello DB). Puoi ottimizzarlo un po 'eliminando la coda e inserendo direttamente nel DB - solo "sporcando" le voci per un secondo come sopra.

Ovviamente c'è il rovescio della medaglia che si sacrifica un po 'di precisione in quel balzo secondo (non un grande sacrificio considerando i secondi bisestili sono così rari) ma il vantaggio è che è semplice e il tuo ordine è garantito.

Se tu o chiunque altro trova soluzioni migliori si prega di condividere qui, questo argomento è piuttosto interessante :)

Aggiornamento: ho scritto il pseudocodice per un 3 ° soluzione di (interamente nella query SQL), che fa affidamento su un controllo hardcoded per un secondo intercalare (più veloce di una soluzione generica).Probabilmente può essere ottimizzata molto, ma solo per dimostrare il mio punto:

if (newTime is in a leap second){ 
    read smearCount from db; 
    if (smearCount <= 0) { 
     smearCount = 1000; // making sure we land outside the leap second 
     update smearCount in db; 
    } 
    newTime += smearCount; 
    insert newTime into db; 
} else { // gradually reducing smearCount by 1 millisecond over the following 1000 insertions 
    read smearCount from db; 
    if (smearCount > 0){ 
     smearCount -= 1; 
     update smearCount in db; 
     newTime += smearCount; 
    } 
    insert newTime into db; 
} 
+1

+1 ma l'implementazione di questo sullo strato db può sembrare più semplice di quanto non sia (pensando al famoso ORA-04091: la tabella XXXX sta mutando, trigger/funzione potrebbe non vederlo) –

+0

Vieni a pensarci forse è davvero è più semplice di quanto pensassi. Il controllo per il secondo intercalare può essere anche codificato nel codice di inserimento SQL. L'unico problema (che non dovrebbe essere affatto un problema) sarebbe quello di leggere (e incrementare nel database stesso) un conteggio "smear" (il numero di millisecondi che aggiungi artificialmente). – Sandman

+0

@ HAL9000: l'errore "trigger si sta mutando" di solito si verifica quando le persone non capiscono che Oracle ha trigger a livello di riga che non richiedono alcun DML sulla tabella attivata.E il codice sopra potrebbe cambiare il tempo per una singola riga senza problemi (anche se non userei un trigger per questo - una procedura che gestisca tutto sarebbe una scelta migliore) –

3

Dal Joda Time FAQ:

Are bisestili secondi supportati?

Joda-Time non supporta i secondi bisestili. I secondi di salto possono essere supportati scrivendo una nuova cronologia specializzata, o apportando alcuni miglioramenti alla classe ZonedChronology esistente. In entrambi i casi, le versioni future di Joda-Time non abiliteranno automaticamente i secondi bisestili. La maggior parte delle applicazioni non ne ha bisogno e potrebbe avere costi di prestazioni aggiuntivi.

Da IANA/Olson TZDB file on leap seconds:

Anche se la definizione include anche la possibilità di far cadere secondi ("negativi" bisestili secondi), questo non è mai stato fatto ed è improbabile che sia necessaria nel prossimo futuro.

La tua prima domanda:

Come per assicurarsi che il TS è sempre in aumento e non all'indietro?

Uno negativo secondo intercalare lascerebbe voi allo stesso timestamp (un valore per due secondi trascorsi), quindi non si può davvero andare indietro senza due secondo salto negativo. Dal momento che non sembra probabile che ci saranno mai secondi bisestili negativi, direi che questo è un problema che non incontrerai mai.

Aggiornamento: L'unico modo in cui posso prevedere il timestamp all'indietro è se si utilizza la precisione in millisecondi e si verifica il comportamento n. 3 di seguito.

tua seconda domanda:

come selezionare esattamente l'intervallo 100s da db che tengono conto nel secondo intercalare?

Poiché i tempi di registrazione sono in UTC, i valori sono già comprensivi di secondi bisestili. So che può sembrare contro-intuitivo, dal momento che come hai descritto ci sono esattamente 86400 secondi (86400000 ms) in un giorno da questa scala. Ma sono davvero lì dentro. Se non lo fossero, allora verremmo sincronizzati con TAI, non con UTC. Quindi, come può essere? Beh, ci sono un paio di cose diverse che possono accadere quando si verifica un secondo intercalare:

  1. Se secondo salto sono supportati sia dal sistema operativo e il codice dell'applicazione, allora potrebbe mostrare davvero uno spettacolo secondi come :60 o :61. Ma non ci sono quasi reali implementazioni di questo perché i linguaggi di programmazione di solito consentono solo i secondi che vanno a :59.

  2. Il sistema operativo potrebbe "bloccarsi" per un secondo, fornendo lo stesso valore per un intero secondo.

  3. Il sistema operativo potrebbe passare a :59.999 e quindi tornare a :59.000 per ripetere il periodo coperto dal secondo intercalare. (grazie @Teo)

  4. Il sistema operativo potrebbe "drift" o "smear" per un po ', aggiungendo lentamente alcuni millisecondi alla volta all'orologio di sistema, fino a quando non ha raggiunto il secondo extra.

  5. Il sistema operativo potrebbe saltare direttamente su di esso e non fare nulla. L'orologio non sarà sincronizzato fino alla prossima sincronizzazione con NTP. E se è successo sincronizzare proprio al momento del secondo intercalare, probabilmente sarà sufficiente impostare l'ora su :59 o :00 e di nuovo essere fuori sincrono per un po '.

Consideriamo un esempio reale. Il valore 1341100800000 rappresenta il 1 ° luglio 2012 esattamente alla mezzanotte UTC. (È possibile verificarlo su this web site o nel proprio codice Java o Joda. Per verificare.) Se dividiamo per 86400000, otterremo esattamente i 15522 giorni trascorsi dal 1/1/1970 UTC.

Questo valore è compreso dei 35 secondi bisestile, compreso quello che è accaduto solo un secondo prima alla fine della giornata del 30 giugno 2012. È come se il secondo intercalare non fosse mai accaduto.

Quindi la maggior parte delle volte non è necessario preoccuparsi dei secondi bisestili. Fai finta che non esistano. Lascia che il tuo sistema operativo li gestisca nel modo che preferisce.

Se si richiedono misurazioni del tempo ultra precise, forse in un contesto scientifico, non si dovrebbe comunque utilizzare l'orologio di sistema del computer. Oltre al fatto che il secondo intercalare può essere trattenuto, allungato o ignorato, non è progettato per essere preciso di un timer. Invece, probabilmente dovresti lavorare con hardware di cronometraggio molto specializzato, come quelli offerti da this vendor.

Aggiornamento: Nei casi in cui è necessario occuparsi di secondi bisestili è se si registrano eventi rapidamente (molti eventi al secondo) e se il sistema operativo ha il comportamento descritto in # 3 sopra. In questo caso, la mia raccomandazione sarebbe quella di non ordinare per data e ora, ma invece di prendere in considerazione un numero di sequenza a parte monotonicamente crescente della tua, e ordinare invece quello.

Ad esempio, è possibile che nel database sia già presente un numero intero a incremento automatico. Si potrebbe ancora filtro per data e ora nella clausola where per ottenere dati per una data particolare, ma si ordinerà quindi dall'ID in modo che gli eventi siano in sequenza anche se i timestamp non lo erano.

Per altri suggerimenti, vedere Teo's answer.

+0

Cosa succede se si desidera la sincronizzazione tra i continenti per alcune funzionalità e hai a che fare con timestamp Unix recuperati da varie località? Se l'ordine del timestamp è importante per qualsiasi motivo, penso che non puoi semplicemente ignorarlo. – Sandman

+0

@Teo - I timestamp Unix sono * sempre * in UTC. Quando si verificano * secondi * bisestili, si verificano tutti alla stessa ora UTC in tutto il mondo. Quindi, se hai a che fare con timestamp Unix (o qualsiasi altro tipo di UTC o GMT), la posizione è irrilevante. –

+1

Sì, ma se è necessaria la sincronizzazione tra queste posizioni multiple? Una posizione potrebbe inviare un timestamp per x millisecondi per l'inserimento nel database e l'altro invia x + 500. Tuttavia, se sei all'interno di quel balzo secondo non potrebbe essere che x + 500 si verifica prima di x? Questo è descritto qui: http://en.wikipedia.org/wiki/Unix_time#Encoding_time_as_a_number – Sandman

Problemi correlati