Skip to content

Instantly share code, notes, and snippets.

@zwh8800
Last active February 21, 2023 10:28
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zwh8800/9b0442efadc97408ffff248bc8573064 to your computer and use it in GitHub Desktop.
Save zwh8800/9b0442efadc97408ffff248bc8573064 to your computer and use it in GitHub Desktop.
lua ISO 8601 datetime parser - https://repl.it/IQuI/5
function parse_json_date(json_date)
local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%+%-])(%d?%d?)%:?(%d?%d?)"
local year, month, day, hour, minute,
seconds, offsetsign, offsethour, offsetmin = json_date:match(pattern)
local timestamp = os.time{year = year, month = month,
day = day, hour = hour, min = minute, sec = seconds}
local offset = 0
if offsetsign ~= 'Z' then
offset = tonumber(offsethour) * 60 + tonumber(offsetmin)
if xoffset == "-" then offset = offset * -1 end
end
return timestamp + offset
end
print(string.format('%d', parse_json_date('2017-05-25T06:21:43Z')))
print(string.format('%d', parse_json_date('2017-05-25T06:21:43+0830')))
print(string.format('%d', parse_json_date('2017-05-25T06:21:43-0400')))
print(string.format('%d', parse_json_date('2017-05-25T06:21:43.213Z')))
@SirLynix
Copy link

I love you for this

@wsmathews
Copy link

You have my love too.

@wsmathews
Copy link

Do you want to change this: tonumber(offsethour) * 60 + tonumber(offsetmin)
I think you want this: tonumber(offsethour) * 60 * 60 + tonumber(offsetmin) *60

@wsmathews
Copy link

I still love you for this! I also think you want to change "xoffset" to "offsetsign " to apply the -1. But really, the offset is the timezone. I would only add it back to the time to convert local time to GMT (after reversing sign) My time 14:00:00-04:00 means 18:00:00Z right? Anyone?

@GordonMcKinney
Copy link

GordonMcKinney commented Aug 14, 2019

I noticed the conversion was incorrect when running this code in a different TZ (not GMT). I corrected it by adding the following between line 6 and 7.

    timestamp=timestamp-(date():getbias()*60) -- Make it Zulu

@slavanap
Copy link

A little fixed version: time in UTC (not in local time zone), assume os.time returns seconds

function parse_json_date(json_date)
    local pattern = "(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%+%-])(%d?%d?)%:?(%d?%d?)"
    local year, month, day, hour, minute, 
        seconds, offsetsign, offsethour, offsetmin = json_date:match(pattern)
    local timestamp = os.time{year = year, month = month, 
        day = day, hour = hour, min = minute, sec = seconds} - os.time{year=1970, month=1, day=1, hour=0}
    local offset = 0
    if offsetsign ~= 'Z' then
      offset = tonumber(offsethour) * 60 + tonumber(offsetmin)
      if xoffset == "-" then offset = offset * -1 end
    end
    
    return timestamp + offset * 60
end

@birchb1024
Copy link

xoffset used but not defined, maybe it should be:

if offsetsign == "-" then offset = offset * -1 end

@slavanap
Copy link

I've forgotten to update. There's my final version I currently use below.

local epoch = os.time{year=1970, month=1, day=1, hour=0}
function parse_json_date(json_date)
          local year, month, day, hour, minute, seconds, offsetsign, offsethour, offsetmin = json_date:match("(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%+%- ])(%d?%d?)%:?(%d?%d?)")
          local timestamp = os.time{year = year, month = month, day = day, hour = hour, min = minute, sec = seconds} - epoch
          local offset = 0
          if offsetsign ~= 'Z' then
            offset = tonumber(offsethour) * 60 + tonumber(offsetmin)
            if offsetsign == "-" then offset = -offset end
          end
          return timestamp - offset * 60
        end

@sunny352
Copy link

I've forked this and fix an error "time result cannot be represented in this installation", but I can't create pull request for the gist...

I've forgotten to update. There's my final version I currently use below.

local epoch = os.time{year=1970, month=1, day=1, hour=0}
function parse_json_date(json_date)
          local year, month, day, hour, minute, seconds, offsetsign, offsethour, offsetmin = json_date:match("(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:([%d%.]+)([Z%+%- ])(%d?%d?)%:?(%d?%d?)")
          local timestamp = os.time{year = year, month = month, day = day, hour = hour, min = minute, sec = seconds} - epoch
          local offset = 0
          if offsetsign ~= 'Z' then
            offset = tonumber(offsethour) * 60 + tonumber(offsetmin)
            if offsetsign == "-" then offset = -offset end
          end
          return timestamp - offset * 60
        end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment