Time Module

GX includes a time module for high-resolution timing, wall clock access, date/time components, formatting, and sleep. It works with TCC, clang, and gcc on Windows, Linux, and macOS.

Prerequisites

No external dependencies. The module uses standard C <time.h> plus platform-native high-resolution clocks (QueryPerformanceCounter on Windows, clock_gettime on POSIX).

Usage

import time

Build with -I modules:

gx myapp.gx -I modules -o myapp.exe

Quick Example

import time

fn main() {
    // Current date/time
    var now = time.gx_time_unix()
    var formatted = time.gx_time_format(now, "%Y-%m-%d %H:%M:%S")
    print("Now: {formatted}\n")

    // Benchmark something
    var t0 = time.gx_time_now_ns()
    // ... do work ...
    var t1 = time.gx_time_now_ns()
    var ms = time.gx_time_elapsed_ms(t0, t1)
    print("Took {ms} ms\n")

    // Sleep
    time.gx_time_sleep_ms(100)
}

High-Resolution Monotonic Clock

For measuring elapsed time (benchmarks, frame timing, profiling). Uses QueryPerformanceCounter on Windows and clock_gettime(CLOCK_MONOTONIC) on POSIX — sub-microsecond precision.

FunctionSignatureDescription
gx_time_now_ns() → i64Monotonic time in nanoseconds
gx_time_tick() → i64Raw high-res counter (platform units)
gx_time_tick_freq() → i64Ticks per second
var t0 = time.gx_time_now_ns()
// ... work ...
var t1 = time.gx_time_now_ns()

Elapsed Time Helpers

Convert a pair of now_ns() values to human-readable units:

FunctionSignatureDescription
gx_time_elapsed_ms(i64, i64) → f64Milliseconds between two timestamps
gx_time_elapsed_us(i64, i64) → f64Microseconds
gx_time_elapsed_s(i64, i64) → f64Seconds
var ms = time.gx_time_elapsed_ms(t0, t1)
var us = time.gx_time_elapsed_us(t0, t1)
var s  = time.gx_time_elapsed_s(t0, t1)

Wall Clock

FunctionSignatureDescription
gx_time_unix() → i64Current Unix epoch (seconds since 1970-01-01 UTC)
gx_time_diff_secs(i64, i64) → f64Difference between two epoch timestamps

Date/Time Components (Local)

All take an epoch timestamp and return a single component in local time. Month is 1-based (1 = January), year is actual (e.g. 2026).

FunctionSignatureDescription
gx_time_year(i64) → i32Year (e.g. 2026)
gx_time_month(i64) → i32Month (1–12)
gx_time_day(i64) → i32Day of month (1–31)
gx_time_hour(i64) → i32Hour (0–23)
gx_time_minute(i64) → i32Minute (0–59)
gx_time_second(i64) → i32Second (0–59)
gx_time_weekday(i64) → i32Day of week (0 = Sunday)
gx_time_yearday(i64) → i32Day of year (0–365)
var now = time.gx_time_unix()
var y  = time.gx_time_year(now)
var mo = time.gx_time_month(now)
var d  = time.gx_time_day(now)
var h  = time.gx_time_hour(now)
var mi = time.gx_time_minute(now)
var s  = time.gx_time_second(now)
print("{y}-{mo}-{d} {h}:{mi}:{s}\n")

Weekday Constants

ConstantValue
SUNDAY0
MONDAY1
TUESDAY2
WEDNESDAY3
THURSDAY4
FRIDAY5
SATURDAY6
if (time.gx_time_weekday(now) == time.SATURDAY) {
    print("Weekend!\n")
}

Date/Time Components (UTC)

Same as local, but in UTC:

FunctionSignatureDescription
gx_time_utc_year(i64) → i32Year (UTC)
gx_time_utc_month(i64) → i32Month 1–12 (UTC)
gx_time_utc_day(i64) → i32Day 1–31 (UTC)
gx_time_utc_hour(i64) → i32Hour 0–23 (UTC)
gx_time_utc_minute(i64) → i32Minute 0–59 (UTC)
gx_time_utc_second(i64) → i32Second 0–59 (UTC)

Building Timestamps

Create an epoch value from components (in local time):

FunctionSignatureDescription
gx_time_make(i32, i32, i32, i32, i32, i32) → i64Year, month, day, hour, min, sec → epoch
var new_year = time.gx_time_make(2026, 1, 1, 0, 0, 0)
var label = time.gx_time_format(new_year, "%A, %B %d, %Y")
print("New Year: {label}\n")  // "Thursday, January 01, 2026"

Formatting

Format a timestamp using strftime format codes. Returns a C string from a static buffer (valid until the next format call).

FunctionSignatureDescription
gx_time_format(i64, cstr) → cstrFormat as local time string
gx_time_format_utc(i64, cstr) → cstrFormat as UTC string

Common Format Codes

CodeDescriptionExample
%Y4-digit year2026
%mMonth (01–12)04
%dDay (01–31)03
%HHour 24h (00–23)14
%MMinute (00–59)30
%SSecond (00–59)05
%AFull weekday nameFriday
%BFull month nameApril
%aShort weekdayFri
%bShort monthApr
%pAM/PMPM
%IHour 12h (01–12)02
%ZTimezone nameCET
var now = time.gx_time_unix()

// ISO 8601
var iso = time.gx_time_format(now, "%Y-%m-%dT%H:%M:%S")

// Human readable
var human = time.gx_time_format(now, "%A, %B %d, %Y at %I:%M %p")

// Date only
var date = time.gx_time_format(now, "%Y-%m-%d")

Sleep

FunctionSignatureDescription
gx_time_sleep_ms(i64)Sleep for N milliseconds

Uses Sleep() on Windows, nanosleep() on POSIX.

time.gx_time_sleep_ms(16)   // ~60 FPS frame budget
time.gx_time_sleep_ms(1000) // 1 second

Common Patterns

Frame Timing

var last = time.gx_time_now_ns()
while (running) {
    var now = time.gx_time_now_ns()
    var dt = time.gx_time_elapsed_s(last, now)
    last = now
    // dt is delta time in seconds (e.g. 0.016 for 60 FPS)
    update(dt)
    render()
}

Benchmarking

var t0 = time.gx_time_now_ns()
do_expensive_work()
var t1 = time.gx_time_now_ns()
var ms = time.gx_time_elapsed_ms(t0, t1)
print("Took {ms} ms\n")

Timestamps for Logging

var now = time.gx_time_unix()
var ts = time.gx_time_format(now, "[%H:%M:%S]")
print("{ts} Server started\n")

Platform Notes

  • Windows: Uses QueryPerformanceCounter for nanosecond-precision monotonic clock and Sleep() for delays. Both available via kernel32 (auto-linked).
  • Linux/macOS: Uses clock_gettime(CLOCK_MONOTONIC) and nanosleep().
  • TCC: Fully supported on all platforms — no C11 or POSIX extensions required.
  • Thread safety: localtime() and gmtime() use static buffers. For single-threaded GX programs this is fine. Multi-threaded use (e.g. with par for) should avoid concurrent date/time calls.

Module Layout

modules/
  time/
    c/
      gx_time.h        Platform-conditional C helpers
    gx/
      time.gx           Module: extern declarations, weekday constants