Шаблон анализа даты и времени Lua ISO 8601 - PullRequest
8 голосов
/ 27 октября 2011

Я пытаюсь проанализировать полное время даты ISO8601 из данных JSON в Lua. У меня проблемы с шаблоном матча.

Пока что вот что у меня есть:

-- 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, по крайней мере, я бы знал, как его нужно настроить.

Я подумал об удалении всего после "." (миллисекунды и часовой пояс), но тогда у меня действительно не будет действительной даты и времени. Миллисекунды не так уж важны, и я не против потерять их, но часовой пояс меняет положение вещей.

Примечание: у кого-то может быть гораздо лучший код для этого, и я не женат на этом, мне просто нужно извлечь что-то полезное из строки datetime:)

Ответы [ 2 ]

10 голосов
/ 27 октября 2011

Полный формат ISO 8601 не может быть сделан с одним совпадением шаблона. Слишком много вариаций.

Некоторые примеры со страницы википедии :

  • Существует «сжатый» формат, который не разделяет числа: YYYYMMDD против YYYY-MM-DD
  • День можно опустить: YYYY-MM-DD и YYYY-MM являются действительными датами
  • Порядковая дата также действительна: YYYY-DDD, где DDD - день года (1-365 / 6)
  • При представлении времени минуты и секунды могут быть опущены: hh:mm:ss, hh:mm и hh - все действительные времена
  • Кроме того, время также имеет сжатую версию: hhmmss, hhmm
  • Кроме того, время принимает дроби, , используя как точку, так и запятую для обозначения дробей младшего элемента времени в отрезке времени . 14:30,5, 1430,5, 14:30.5 или 1430.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

И тогда вам придется создать parseDate, parseTime и parseOffset. Последний должен возвращать смещения времени из UTC, в то время как первые два должны учитывать такие вещи, как сжатые форматы, доли времени, разделители запятых или точек и т. П.

parseDate, скорее всего, будет использовать символ "^" в начале совпадений с образцом, поскольку дата должна быть в начале строки. Шаблоны parseTime, скорее всего, начнутся с "T". И parseOffset будет заканчиваться "$", поскольку смещения времени, когда они существуют, заканчиваются.

Функция "full 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 .

Надеюсь, это поможет. Привет!

1 голос
/ 27 марта 2015

Существует также пакет luadate , который поддерживает iso8601.(Возможно, вам нужна исправленная версия )

...