3 minute read

A fun side project I’ve been helping out on has me digging into quite a bit of Lua recently. It’s been been interesting to dig into, not withstanding the general headscratching (😠 arrays that start at 1…twitch). Since so many new games are developing their plugins and UI components in Lua, it’s a nice language to have in the toolkit.

A recent challenge revolved around checking if an the current moment fell within an “event” timer–a month, day, and duration range.

Caveats

  • Exact start date and duration are knowns and vital; exact end dates are irrelevant as the duration is all that matters.
  • No two events will overlap (hah, they say that now… I’ll read this post in a few months to remind myself of this pain).

This sanitized list of calendar events provides an example of the data–events have fixed start dates and durations, but the years are left off so that events can easily repeat year-over-year, matching the requirements.

local events = {
  { name = "Spring Fundraising", start_month = 3, start_day = 10, duration = 5 },
  { name = "Summer Carnival", start_month = 7, start_day = 15, duration = 60 },
  { name = "Winter Festival", start_month = 12, start_day = 20, duration = 15 },
}

Next, to get whether or not “now” falls in one of those events:

ns.event.getCurrentEvent = function()
  local month = os.date("%m")
  local day = os.date("%d")

  for _, evt in ipairs(events) do
    -- things should go here
  end
end

The first assumption would to just convert everything into timestamps and compare start <= now <= end; however, timestamps factor in the year, so cross-year events, such as the Winter Festival get screwed up.

Here’s the solution I came up with, focusing on building mini-calendars of the date ranges and comparing the current month and day to it. The year is included to create the os.time table; however, only the month and day are compared.

ns.event.getCurrentEvent = function()
  local month = os.date("%m")
  local day = os.date("%d")
  local year = os.date("%Y")

  for _, evt in ipairs(events) do
      local start = os.time {year = year, month = evt.start_month, day = evt.start_day}
    
      for i = 0, evt.duration, 1 do
        -- 24*60*60 to convert our "day" duration
        local m = os.date("%m",start+(i*24*60*60))
        local d = os.date("%d",start+(i*24*60*60))
        if month == m and day == d then
          -- match found; stop and return
          return evt
        end
      end  
  end
end

For now, it’s not perfect, but it works and ticks the use cases for this tiny project.

So, Lua experts out there–is there a cleaner way to handle blanket date ranges or is date/time manipulation in Lua a black hole of joy like every other programming language out there?

comments powered by Disqus