2011-10-27 12 views
8

Sto tentando di analizzare un valore di data/ora ISO8601 completo dai dati JSON in Lua. Ho problemi con il modello di corrispondenza.Lua ISO 8601 pattern di parsing con datetime

Finora, questo è quello che ho:

-- Example datetime string 2011-10-25T00:29:55.503-04:00 
local datetime = "2011-10-25T00:29:55.503-04:00" 
local pattern = "(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)%.(%d+)" 
local xyear, xmonth, xday, xhour, xminute, 
     xseconds, xmillies, xoffset = datetime:match(pattern) 

local convertedTimestamp = os.time({year = xyear, month = xmonth, 
     day = xday, hour = xhour, min = xminute, sec = xseconds}) 

Sono bloccato a come affrontare il fuso orario sul modello perché non c'è logica o che gestirà il - o + o nessuno. Anche se so che lua non supporta il fuso orario nella funzione os.time, almeno saprei come ha dovuto essere regolato.

Ho pensato di togliere tutto dopo il "." (millisecondi e fuso orario), ma in realtà non avrei un datetime valido. I millisecondi non sono poi così importanti e non mi dispiacerebbe perdere, ma il fuso orario cambia le cose.

Nota: Qualcuno può avere qualche codice molto meglio per fare questo e io non sono sposato, ho solo bisogno di ottenere qualcosa di utile dalla stringa datetime :)

+0

BTW La risposta di kikito è buona; solo una nota: potrebbe essere una buona mossa accettare "" (spazio) e "T" per separare la data/ora, perché molte molte persone e strumenti scrivono in questo modo le date in stile ISO in quel modo (forse più di usa 'T'!). – snogglethorpe

+0

Grazie per quel puntatore. Nel mio caso, non ho bisogno di preoccuparmi troppo perché il modello è noto: 2011-10-25T00: 29: 55.503-04: 00 –

risposta

10

La piena formato ISO 8601 può' si può fare con un solo pattern match. C'è troppa variazione.

Alcuni esempi: from the wikipedia page

  • v'è un formato "compresso" che fa numeri non separate: YYYYMMDD vs YYYY-MM-DD
  • La giornata può essere omited: YYYY-MM-DD e YYYY-MM sono entrambe date valide
  • La data ordinale è valida anche: YYYY-DDD, dove DDD è il giorno dell'anno (1-365/6)
  • Quando si rappresenta la t ime, minuti e secondi possono essere ommited: hh:mm:ss, hh:mm e hh sono sempre validi
  • Inoltre, il tempo ha anche una versione compressa: hhmmss, hhmm
  • E per di più, il tempo accetta frazioni, utilizzando sia il punto o la virgola per indicare le frazioni dell'elemento temporale inferiore nella sezione temporale. 14:30,5, 1430,5, 14:30.5 o 1430.5 rappresentano tutte 14 ore, 30 secondi e mezzo.
  • Infine, la sezione del fuso orario è facoltativa. Quando presente, può essere la lettera Z, ±hh:mm, ±hh o ±hhmm.

Quindi, ci sono molte possibili eccezioni da tenere in considerazione, se si intende analizzare secondo le specifiche complete. In questo caso, il codice iniziale potrebbe assomigliare a questo:

function parseDateTime(str) 
    local Y,M,D = parseDate(str) 
    local h,m,s = parseTime(str) 
    local oh,om = parseOffset(str) 
    return os.time({year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s}) 
end 

E poi si dovrebbe creare parseDate, parseTime e parseOffset. Le versioni successive dovrebbero restituire le correzioni dell'ora da UTC, mentre le prime due dovrebbero prendere in considerazione aspetti come formati compressi, frazioni temporali, separatori di virgola o punti e simili.

parseDate probabilmente utilizzerà il carattere "^" all'inizio delle sue corrispondenze modello, poiché la data deve essere all'inizio della stringa.Gli schemi parseTime inizieranno probabilmente con "T". E gli parseOffset terminano con "$", poiché le compensazioni temporali, quando esistono, sono alla fine.

Una funzione "full ISO" parseOffset potrebbe essere simile a questo:

function parseOffset(str) 
    if str:sub(-1)=="Z" then return 0,0 end -- ends with Z, Zulu time 

    -- matches ±hh:mm, ±hhmm or ±hh; else returns nils 
    local sign, oh, om = str:match("([-+])(%d%d):?(%d?%d?)$") 
    sign, oh, om = sign or "+", oh or "00", om or "00" 

    return tonumber(sign .. oh), tonumber(sign .. om) 
end 

A proposito, sto supponendo che il computer sta lavorando in ora UTC. Se questo non è il caso, dovrai includere un offset aggiuntivo sulle ore/minuti per renderlo conto.

function parseDateTime(str) 
    local Y,M,D = parseDate(str) 
    local h,m,s = parseTime(str) 
    local oh,om = parseOffset(str) 
    local loh,lom = getLocalUTCOffset() 
    return os.time({year=Y, month=M, day=D, hour=(h+oh-loh), min=(m+om-lom), sec=s}) 
end 

per ottenere il vostro locale di offset si potrebbe desiderare di guardare http://lua-users.org/wiki/TimeZone.

Spero che questo aiuti. Saluti!

+0

Ho qualche vantaggio perché so quale sarà il formato sul server lato, tuttavia non volevo alterarlo alla suite Lua meglio, perché poi altri client potrebbero avere problemi. –

+0

L'offset del fuso orario per l'ora non è corretto. Deve essere sottratto dall'ora per ottenere l'ora corretta in GMT. – CanSpice

+0

@CanSpice Grazie, risolto! – kikito

Problemi correlati