Skip to content

Time Module

The time module provides comprehensive date and time manipulation utilities for Lua scripts. All timestamps are exchanged as ISO8601 strings for consistency and timezone awareness.

Time Format

All time values use ISO8601 format:

  • UTC time: "2024-01-15T14:30:45.123456Z"
  • Local time with offset: "2024-01-15T14:30:45.123456-05:00"

Functions

Current Time

time.now()

Returns the current local time as an ISO8601 string.

lua
local current = time.now()
print(current)  -- "2024-01-15T14:30:45.123456-05:00"

time.utc_now()

Returns the current UTC time as an ISO8601 string.

lua
local utc = time.utc_now()
print(utc)  -- "2024-01-15T19:30:45.123456Z"

Time Parsing and Validation

time.parse(timestamp)

Parses and validates an ISO8601 timestamp string.

Parameters:

  • timestamp (string): ISO8601 formatted timestamp

Returns:

  • Valid ISO8601 string on success
  • nil and error message on failure
lua
local valid = time.parse("2024-01-15T14:30:45Z")
local invalid, err = time.parse("not a date")
if not invalid then
    print("Error:", err)
end

Time Manipulation

time.add(timestamp, seconds)

Adds or subtracts seconds from a timestamp.

Parameters:

  • timestamp (string): ISO8601 timestamp
  • seconds (number): Seconds to add (negative to subtract)
lua
local now = time.utc_now()
local hour_later = time.add(now, 3600)
local hour_ago = time.add(now, -3600)

time.add_minutes(timestamp, minutes)

Adds or subtracts minutes from a timestamp.

lua
local meeting = "2024-01-15T14:00:00Z"
local delayed = time.add_minutes(meeting, 30)  -- 14:30

time.add_hours(timestamp, hours)

Adds or subtracts hours from a timestamp.

lua
local start = "2024-01-15T09:00:00Z"
local lunch = time.add_hours(start, 3.5)  -- 12:30

time.add_days(timestamp, days)

Adds or subtracts days from a timestamp.

lua
local today = time.utc_now()
local next_week = time.add_days(today, 7)
local yesterday = time.add_days(today, -1)

time.shift(timestamp, options)

Shifts a timestamp by multiple time units simultaneously.

Parameters:

  • timestamp (string): ISO8601 timestamp
  • options (table): Table with time units as keys
    • years: Number of years to add
    • months: Number of months to add (approximated as 30 days)
    • weeks: Number of weeks to add
    • days: Number of days to add
    • hours: Number of hours to add
    • minutes: Number of minutes to add
    • seconds: Number of seconds to add
lua
local start = "2024-01-15T12:00:00Z"
local shifted = time.shift(start, {
    days = 1,
    hours = 2,
    minutes = 30
})
print(shifted)  -- "2024-01-16T14:30:00Z"

Time Comparison

time.compare(timestamp1, timestamp2)

Compares two timestamps.

Returns:

  • -1 if timestamp1 is earlier than timestamp2
  • 0 if timestamps are equal
  • 1 if timestamp1 is later than timestamp2
lua
local past = "2024-01-14T12:00:00Z"
local future = "2024-01-16T12:00:00Z"
print(time.compare(past, future))  -- -1
print(time.compare(future, past))  -- 1
print(time.compare(past, past))    -- 0

time.diff(timestamp1, timestamp2, unit)

Calculates the difference between two timestamps.

Parameters:

  • timestamp1 (string): First timestamp
  • timestamp2 (string): Second timestamp
  • unit (string, optional): Unit of measurement ("seconds", "minutes", "hours", "days"). Default: "seconds"

Returns: The difference as a number (timestamp2 - timestamp1)

lua
local start = "2024-01-15T09:00:00Z"
local end = "2024-01-15T17:30:00Z"

local hours = time.diff(start, end, "hours")
print(hours)  -- 8.5

local minutes = time.diff(start, end, "minutes")
print(minutes)  -- 510

time.before(timestamp1, timestamp2)

Checks if timestamp1 is before timestamp2.

lua
local past = "2024-01-14T12:00:00Z"
local future = "2024-01-16T12:00:00Z"
print(time.before(past, future))   -- true
print(time.before(future, past))   -- false

time.is_after(timestamp1, timestamp2)

Checks if timestamp1 is after timestamp2.

lua
local past = "2024-01-14T12:00:00Z"
local future = "2024-01-16T12:00:00Z"
print(time.is_after(future, past))   -- true
print(time.is_after(past, future))   -- false

Time Conversion

time.to_unix(timestamp)

Converts an ISO8601 timestamp to Unix time (seconds since epoch).

lua
local ts = "2024-01-15T12:00:00Z"
local unix = time.to_unix(ts)
print(unix)  -- 1705320000

time.from_unix(unix_timestamp)

Converts Unix time to an ISO8601 timestamp.

lua
local unix = 1705320000
local ts = time.from_unix(unix)
print(ts)  -- "2024-01-15T12:00:00Z"

time.to_date(timestamp)

Extracts the date portion from a timestamp.

lua
local ts = "2024-01-15T14:30:45.123456Z"
local date = time.to_date(ts)
print(date)  -- "2024-01-15"

time.to_time(timestamp)

Extracts the time portion from a timestamp.

lua
local ts = "2024-01-15T14:30:45.123456Z"
local time_part = time.to_time(ts)
print(time_part)  -- "14:30:45.123456"

Time Formatting

time.format(timestamp, format_string)

Formats a timestamp using a format string.

Format Specifiers:

  • %Y - Year (4 digits)
  • %m - Month (01-12)
  • %d - Day of month (01-31)
  • %H - Hour (00-23)
  • %M - Minute (00-59)
  • %S - Second (00-59)
  • %a - Short weekday name (Mon, Tue, etc.)
  • %A - Full weekday name (Monday, Tuesday, etc.)
  • %b - Short month name (Jan, Feb, etc.)
  • %B - Full month name (January, February, etc.)
  • %z - Timezone offset (+00:00)
  • %Z - Timezone name
lua
local ts = "2024-01-15T14:30:45Z"

print(time.format(ts, "%Y-%m-%d"))           -- "2024-01-15"
print(time.format(ts, "%H:%M:%S"))           -- "14:30:45"
print(time.format(ts, "%A, %B %d, %Y"))      -- "Monday, January 15, 2024"
print(time.format(ts, "%a %b %d %H:%M:%S"))  -- "Mon Jan 15 14:30:45"

Time Boundaries

time.start_of_day(timestamp)

Returns the beginning of the day for the given timestamp.

lua
local ts = "2024-01-15T14:30:45Z"
local start = time.start_of_day(ts)
print(start)  -- "2024-01-15T00:00:00Z"

time.end_of_day(timestamp)

Returns the end of the day for the given timestamp.

lua
local ts = "2024-01-15T14:30:45Z"
local end_day = time.end_of_day(ts)
print(end_day)  -- "2024-01-15T23:59:59.999999Z"

time.start_of_month(timestamp)

Returns the beginning of the month for the given timestamp.

lua
local ts = "2024-01-15T14:30:45Z"
local start = time.start_of_month(ts)
print(start)  -- "2024-01-01T00:00:00Z"

time.end_of_month(timestamp)

Returns the end of the month for the given timestamp.

lua
local ts = "2024-01-15T14:30:45Z"
local end_month = time.end_of_month(ts)
print(end_month)  -- "2024-01-31T23:59:59.999999Z"

time.start_of_week(timestamp, start_day)

Returns the beginning of the week for the given timestamp.

Parameters:

  • timestamp (string): ISO8601 timestamp
  • start_day (string, optional): Day the week starts on ("monday", "sunday", etc.). Default: "monday"
lua
local ts = "2024-01-17T14:30:45Z"  -- Wednesday
local monday = time.start_of_week(ts)
print(monday)  -- "2024-01-15T00:00:00Z"

local sunday = time.start_of_week(ts, "sunday")
print(sunday)  -- "2024-01-14T00:00:00Z"

time.end_of_week(timestamp, start_day)

Returns the end of the week for the given timestamp.

lua
local ts = "2024-01-17T14:30:45Z"  -- Wednesday
local sunday = time.end_of_week(ts)
print(sunday)  -- "2024-01-21T23:59:59.999999Z"

local saturday = time.end_of_week(ts, "sunday")
print(saturday)  -- "2024-01-20T23:59:59.999999Z"

Practical Examples

Date Range Generation

lua
function generate_date_range(start_date, days)
    local dates = {}
    for i = 0, days - 1 do
        local date = time.add_days(start_date, i)
        table.insert(dates, time.to_date(date))
    end
    return dates
end

local week = generate_date_range("2024-01-15T00:00:00Z", 7)
-- {"2024-01-15", "2024-01-16", ..., "2024-01-21"}

Business Hours Check

lua
function is_business_hours(timestamp)
    local time_str = time.to_time(timestamp)
    local hour = tonumber(string.sub(time_str, 1, 2))

    -- Check if it's a weekday
    local day_name = time.format(timestamp, "%A")
    local is_weekday = day_name ~= "Saturday" and day_name ~= "Sunday"

    -- Business hours: 9 AM to 5 PM on weekdays
    return is_weekday and hour >= 9 and hour < 17
end

local office_time = "2024-01-15T10:30:00Z"  -- Monday 10:30 AM
local weekend = "2024-01-20T10:30:00Z"      -- Saturday 10:30 AM

print(is_business_hours(office_time))  -- true
print(is_business_hours(weekend))      -- false

Age Calculation

lua
function calculate_age(birth_date, current_date)
    local days = time.diff(birth_date, current_date, "days")
    local years = math.floor(days / 365.25)  -- Account for leap years
    return years
end

local birth = "1990-05-15T00:00:00Z"
local today = time.utc_now()
local age = calculate_age(birth, today)
print("Age:", age, "years")

Deadline Tracking

lua
function days_until_deadline(deadline)
    local now = time.utc_now()
    if time.is_after(now, deadline) then
        return 0, "Deadline has passed"
    end

    local days = time.diff(now, deadline, "days")
    if days < 1 then
        local hours = time.diff(now, deadline, "hours")
        return hours, "hours remaining"
    end

    return days, "days remaining"
end

local project_due = "2024-02-01T17:00:00Z"
local remaining, unit = days_until_deadline(project_due)
print(string.format("%.1f %s", remaining, unit))

Recurring Events

lua
function next_occurrence(start_date, interval_days)
    local now = time.utc_now()
    local current = start_date

    -- Find the next occurrence after now
    while time.before(current, now) do
        current = time.add_days(current, interval_days)
    end

    return current
end

-- Weekly meeting every Monday at 10 AM
local first_meeting = "2024-01-01T10:00:00Z"  -- A Monday
local next_meeting = next_occurrence(first_meeting, 7)
print("Next meeting:", time.format(next_meeting, "%A, %B %d at %H:%M"))

Time Zone Aware Operations

lua
function schedule_across_timezones(utc_time)
    -- Format times for different regions
    local schedule = {
        UTC = time.format(utc_time, "%H:%M %Z"),
        -- Note: Actual timezone conversion would require additional logic
        -- This is a simplified example
        Eastern = time.format(time.add_hours(utc_time, -5), "%H:%M EST"),
        Pacific = time.format(time.add_hours(utc_time, -8), "%H:%M PST"),
        Tokyo = time.format(time.add_hours(utc_time, 9), "%H:%M JST")
    }

    return schedule
end

local meeting = "2024-01-15T15:00:00Z"
local times = schedule_across_timezones(meeting)
for zone, time_str in pairs(times) do
    print(zone .. ":", time_str)
end

Error Handling

All time functions return nil and an error message when given invalid input:

lua
local result, error = time.parse("invalid date")
if not result then
    print("Error:", error)  -- "Error: invalid"
end

-- Safe time operations
function safe_add_days(timestamp, days)
    local result, err = time.add_days(timestamp, days)
    if not result then
        print("Failed to add days:", err)
        return timestamp  -- Return original on error
    end
    return result
end

Best Practices

  1. Always validate timestamps before operations:

    lua
    local function process_timestamp(ts)
        local valid = time.parse(ts)
        if not valid then
            return nil, "Invalid timestamp"
        end
        -- Process valid timestamp
        return time.add_hours(valid, 1)
    end
  2. Use UTC for storage and calculations:

    lua
    -- Store as UTC
    local event_time = time.utc_now()
    cache.put("event_timestamp", event_time)
    
    -- Convert for display
    local stored = cache.get("event_timestamp")
    local formatted = time.format(stored, "%Y-%m-%d %H:%M:%S %Z")
  3. Handle timezone offsets consistently:

    lua
    -- Preserve timezone information
    local user_time = "2024-01-15T14:30:00-05:00"
    local shifted = time.add_hours(user_time, 2)
    -- Result maintains the -05:00 offset
  4. Use appropriate time units:

    lua
    -- For short durations, use seconds or minutes
    local process_time = time.diff(start_time, end_time, "seconds")
    
    -- For longer periods, use days
    local project_duration = time.diff(project_start, project_end, "days")
  5. Cache formatted strings for repeated use:

    lua
    local function get_formatted_time(timestamp, format)
        local cache_key = "formatted:" .. timestamp .. ":" .. format
        local cached = cache.get(cache_key)
        if cached then return cached end
    
        local formatted = time.format(timestamp, format)
        cache.put_ttl(cache_key, formatted, 300)  -- Cache for 5 minutes
        return formatted
    end

Connect. Combine. Collaborate.
The pioneering open integration platform, dedicated to transforming connectivity in the printing industry.