2011-10-27 72 views
8

我想從Lua中的JSON數據解析完整的ISO8601日期時間。 我遇到了匹配模式的問題。Lua ISO 8601日期時間解析模式

到目前爲止,這是我所:

-- 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}) 

我被困在如何應對上的圖案的時區,因爲沒有邏輯的或將要處理的 - 或+或無。 雖然我知道lua不支持os.time函數中的時區,但至少我知道它需要如何調整。

我曾考慮剝離「。」後面的所有內容。 (毫秒和時區),但我真的沒有有效的日期時間。毫秒不是那麼重要,我不介意丟失它,但時區改變了事情。

注:有人可能有這樣一些更好的代碼,我還沒結婚呢,我只需要得到一些有用的東西出來的時間字符串:)

+0

BTW kikito的答案是好的;只是一個說明:接受''(空格)以及'T'來分隔日期/時間可能是一個好的舉動,因爲許多許多人和工具以這種方式寫ISO樣式的日期時間(可能超過使用'T'!)。 – snogglethorpe

+0

感謝您的指針。就我而言,我不需要擔心它太多,因爲這種模式是已知的:2011-10-25T00:29:55.503-04:00 –

回答

10

完整的ISO 8601格式可以」的用一個模式匹配來完成。變化太多了。

一些例子from the wikipedia page

  • 有一個 「壓縮」 格式,不包含獨立數字:YYYYMMDD VS YYYY-MM-DD
  • 一天可以被遺漏:YYYY-MM-DDYYYY-MM都是有效日期
  • 順序日期也有效:YYYY-DDD,其中DDD是一年中的某天(1-365/6)
  • 當代表t IME時,分,秒,可以中省略:hh:mm:sshh:mmhh都是有效的時間
  • 此外,時間也有一個壓縮版本:hhmmsshhmm
  • 而且最重要的是,一次使用接受分數,都點或逗號表示時間段中較低時間元素的分數。 14:30,51430,514:30.51430.5都代表14小時30秒半。
  • 最後,時區部分是可選的。當存在時,它可以是字母Z,±hh:mm±hh±hhmm

因此,如果要根據完整規範進行解析,可能有很多例外需要考慮。在這種情況下,你的初始代碼可能是這樣的:

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 

然後,你需要創建parseDateparseTimeparseOffset。後者應該從UTC返回時間偏移量,而前兩者將不得不考慮壓縮格式,時間分數,逗號或點分隔符等等。

parseDate可能會在模式匹配開始時使用"^"字符,因爲日期必須位於字符串的開頭。parseTime的模式可能會從"T"開始。並且parseOffset將以"$"結尾,因爲時間偏移量在它們存在時處於末尾。

「全ISO」 parseOffset功能可能看起來與此類似:

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 

順便說一句,我假設你的計算機在UTC時間的工作。如果情況並非如此,那麼您必須在您的小時/分鐘內加上一個額外的偏移量來解釋這一點。

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 

要獲得您當地的抵消額,您可能需要查看http://lua-users.org/wiki/TimeZone

我希望這會有所幫助。問候!

+0

我有一些優勢,因爲我知道服務器上的格式是什麼但是我不想改變它以更好地適應Lua,因爲那時其他客戶可能會遇到問題。 –

+0

小時的時區偏移不正確。它需要從小時中減去以獲得格林尼治標準時間的正確時間。 – CanSpice

+0

@ CanSpice謝謝,修復! – kikito