84

Is there a common way to get the current time in or with milliseconds?

There is os.time(), but it only provides full seconds.

Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
okoman
  • 5,529
  • 11
  • 41
  • 45

12 Answers12

65

I use LuaSocket to get more precision.

require "socket"
print("Milliseconds: " .. socket.gettime()*1000)

This adds a dependency of course, but works fine for personal use (in benchmarking scripts for example).

waqas
  • 10,323
  • 2
  • 20
  • 11
  • 2
    Note that at least one person claims that on Windows this implementation is not high-resolution enough: http://lua-users.org/wiki/HiResTimer – Phrogz Apr 17 '14 at 03:33
  • 1
    Note that on my system after an update, this stopped working. I had to change it to `socket = require "socket"`, as otherwise `socket` was nil. – phemmer Dec 16 '20 at 15:18
60

If you want to benchmark, you can use os.clock as shown by the doc:

local x = os.clock()
local s = 0
for i=1,100000 do s = s + i end
print(string.format("elapsed time: %.2f\n", os.clock() - x))
Valerio Schiavoni
  • 1,373
  • 1
  • 12
  • 19
  • 9
    Rather than milliseconds however, this appears to work with a precision of 1/100 s. – schaul Aug 29 '12 at 20:42
  • 3
    and this does not work well if you have a call to a C function which uses threads. instead of the actual time taken, it reports the time taken by all threads, as a sum – Ciprian Tomoiagă Dec 13 '14 at 19:55
  • 1
    This function as well as the `os.time` function are highly system-dependent. Also note that documentation states that it returns the *cpu time* used by the program, which on most systems is very different from the actual "earth-time" spent. – dualed Jan 29 '16 at 11:49
  • 3
    Since I'm stuck with standard Lua and it must be portable and encapsulated (no external dll), this is the best solution I can find. +1 – Richard Feb 27 '16 at 14:40
  • "as shown by the doc" - @ValerioSchiavoni could you please provide a link to the doc you are referring to? – Shane Bishop Sep 01 '21 at 17:00
  • 2
    @ShaneBishop see https://www.lua.org/pil/22.1.html at the bottom of the page – Valerio Schiavoni Sep 02 '21 at 09:45
38

In standard C lua, no. You will have to settle for seconds, unless you are willing to modify the lua interpreter yourself to have os.time use the resolution you want. That may be unacceptable, however, if you are writing code for other people to run on their own and not something like a web application where you have full control of the environment.

Edit: another option is to write your own small DLL in C that extends lua with a new function that would give you the values you want, and require that dll be distributed with your code to whomever is going to be using it.

Kevlar
  • 8,804
  • 9
  • 55
  • 81
  • 6
    DLL or .so, etc. Depends on system... :-) – PhiLho Jan 20 '09 at 21:40
  • What are the decimals returned in `os.clock()`? – Kousha Jul 11 '19 at 18:58
  • @Kousha the decimals in `os.clock` are fractions of a second; however, `os.clock` reports program execution time not real world time. `os.clock` is also inconsistent arcoss platforms as it reports `real time` vs `cpu time` on Windows systems. – Nifim Jul 12 '19 at 19:38
20

Get current time in milliseconds.

os.time()

os.time()
return sec // only

posix.clock_gettime(clk)

https://luaposix.github.io/luaposix/modules/posix.time.html#clock_gettime

require'posix'.clock_gettime(0)
return sec, nsec

linux/time.h // man clock_gettime

/*
 * The IDs of the various system clocks (for POSIX.1b interval timers):
 */
#define CLOCK_REALTIME                  0
#define CLOCK_MONOTONIC                 1
#define CLOCK_PROCESS_CPUTIME_ID        2
#define CLOCK_THREAD_CPUTIME_ID         3
#define CLOCK_MONOTONIC_RAW             4
#define CLOCK_REALTIME_COARSE           5
#define CLOCK_MONOTONIC_COARSE          6

socket.gettime()

http://w3.impa.br/~diego/software/luasocket/socket.html#gettime

require'socket'.gettime()
return sec.xxx

as waqas says


compare & test

get_millisecond.lua

local posix=require'posix'
local socket=require'socket'

for i=1,3 do
    print( os.time() )
    print( posix.clock_gettime(0) )
    print( socket.gettime() )
    print''
    posix.nanosleep(0, 1) -- sec, nsec
end

output

lua get_millisecond.lua
1490186718
1490186718      268570540
1490186718.2686

1490186718
1490186718      268662191
1490186718.2687

1490186718
1490186718      268782765
1490186718.2688
Jujhar Singh
  • 373
  • 5
  • 16
yurenchen
  • 1,897
  • 19
  • 17
11

I made a suitable solution for lua on Windows. I basically did what Kevlar suggested, but with a shared library rather than a DLL. This has been tested using cygwin.

I wrote some lua compatible C code, compiled it to a shared library (.so file via gcc in cygwin), and then loaded it up in lua using package.cpath and require" ". Wrote an adapter script for convenience. Here is all of the source:

first the C code, HighResTimer.c

////////////////////////////////////////////////////////////////
//HighResTimer.c by Cody Duncan
//
//compile with:  gcc -o Timer.so -shared HighResTimer.c -llua5.1
//compiled in cygwin after installing lua (cant remember if I 
//   installed via setup or if I downloaded and compiled lua, 
//   probably the former)
////////////////////////////////////////////////////////////////
#include <windows.h>

typedef unsigned __int64 u64;
double mNanoSecondsPerCount;

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"


int prevInit = 0;
int currInit = 0;
u64 prevTime = 0;
u64 currTime = 0;
u64 FrequencyCountPerSec;

LARGE_INTEGER frequencyTemp;
static int readHiResTimerFrequency(lua_State *L)
{
    QueryPerformanceFrequency(&frequencyTemp);
    FrequencyCountPerSec = frequencyTemp.QuadPart;
    lua_pushnumber(L, frequencyTemp.QuadPart);
    return 1;
}

LARGE_INTEGER timerTemp;
static int storeTime(lua_State *L)
{
    QueryPerformanceCounter(&timerTemp);

    if(!prevInit)
    {
        prevInit = 1;
        prevTime = timerTemp.QuadPart;
    }
    else if (!currInit)
    {
        currInit = 1;
        currTime = timerTemp.QuadPart;
    }
    else
    {
        prevTime = currTime;
        currTime = timerTemp.QuadPart;
    }

    lua_pushnumber(L, timerTemp.QuadPart);
    return 1;
}

static int getNanoElapsed(lua_State *L)
{
    double mNanoSecondsPerCount = 1000000000/(double)FrequencyCountPerSec;
    double elapsedNano = (currTime - prevTime)*mNanoSecondsPerCount;
    lua_pushnumber(L, elapsedNano);
    return 1;
}


int luaopen_HighResolutionTimer (lua_State *L) {

    static const luaL_reg mylib [] = 
    {
        {"readHiResTimerFrequency", readHiResTimerFrequency},
        {"storeTime", storeTime},
        {"getNanoElapsed", getNanoElapsed},
        {NULL, NULL}  /* sentinel */
    };

    luaL_register(L,"timer",mylib);

    return 1;
}

--

--

Now lets get it loaded up in a lua script, HighResTimer.lua .

Note: I compiled the HighResTimer.c to a shared library, Timer.so

#!/bin/lua
------------------------------------
---HighResTimer.lua by Cody Duncan
---Wraps the High Resolution Timer Functions in
---   Timer.so
------------------------------------

package.cpath = "./Timer.so"     --assuming Timer.so is in the same directory
require "HighResolutionTimer"    --load up the module
timer.readHiResTimerFrequency(); --stores the tickFrequency


--call this before code that is being measured for execution time
function start()
    timer.storeTime();
end

--call this after code that is being measured for execution time
function stop()
    timer.storeTime();
end

--once the prior two functions have been called, call this to get the 
--time elapsed between them in nanoseconds
function getNanosElapsed()
    return timer.getNanoElapsed();
end

--

--

and Finally, utilize the timer, TimerTest.lua .

#!/bin/lua
------------------------------------
---TimerTest.lua by Cody Duncan
---
---HighResTimer.lua and Timer.so must 
---   be in the same directory as 
---   this script.
------------------------------------

require './HighResTimer' 

start();
for i = 0, 3000000 do io.write("") end --do essentially nothing 3million times.
stop();

--divide nanoseconds by 1 million to get milliseconds
executionTime = getNanosElapsed()/1000000; 
io.write("execution time: ", executionTime, "ms\n");

Note: Any comments were written after pasting the source code into the post editor, so technically this is untested, but hopefully the comments didn't befuddle anything. I will be sure to come back and provide a fix if it does.

Cody Duncan
  • 111
  • 1
  • 2
  • Useful! If anyone wants to port this to mac or linux, you could use the high resolution C code here: https://github.com/tylerneylon/oswrap/blob/master/oswrap_mac/now.c – Tyler Sep 18 '14 at 04:46
  • @Tyler: And how would you go about calling that from lua? – SuperJedi224 Jun 16 '15 at 02:28
  • @SuperJedi224 You'd have to create a C wrapper, something like `int getHighResTime(lua_State *L) { /* push the time onto the lua stack */ return 1; }`, add code to register the C fns with Lua, and then compile that with the Lua C API as a shared library. Here's a decent pdf on that process: http://cs.brynmawr.edu/Courses/cs380/fall2011/luar-topics2.pdf – Tyler Jun 16 '15 at 19:47
  • I'd also avoid wiping out the existing `package.cpath`; instead I'd prepend to it with `package.cpath = "./Timer.so;" .. package.cpath`... – SlySven Dec 21 '17 at 16:35
  • On Windows, you can call the [sys.clock()](https://www.luart.org/doc/sys/clock.html) function from LuaRT. – TSam May 21 '21 at 14:39
  • Awesome! Thank you very much. 100 / 10 when you somehow offer the build dll for newbies like me! – Ismoh Nov 25 '21 at 00:53
7

If you're using lua with nginx/openresty you could use ngx.now() which returns a float with millisecond precision

deepskyblue86
  • 350
  • 1
  • 4
  • 11
  • this is wrong https://github.com/openresty/lua-nginx-module#ngxnow from the docs: "Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library)." – smartius Mar 15 '16 at 23:22
  • You're really impolite. You can't affirm what I wrote is "wrong". I only suggested a possible solution (that I used for a load test and it worked perfectly), and I linked the documentation (so whoever interested in that could check the details). – deepskyblue86 Mar 17 '16 at 08:22
  • Moreover if you take a look at the sources, ngx.req.start_time that you're suggesting uses cached time too (ngx_timeofday). Therefore you'll probably get the same result of ngx.now or earlier. – deepskyblue86 Mar 17 '16 at 08:47
  • Sorry i was up for being impolite. I truly apologize. But if i understand it correctly, ngx.now() returns the timestamp from when the request been started + the time the current script was running until you actually call ngx.now() – smartius Mar 17 '16 at 10:57
  • No, it's an epoch timestamp. Both ngx.now() and ngx.req.start_time() internally use ngx_timeofday(), which is the nginx cached time (which is updated frequently though). Therefore it may happen that both functions return the same value, or most probably different values close to each other. – deepskyblue86 Mar 17 '16 at 15:43
  • Got recently into the same question. Solution seems to be using ngx.now() preceded with ngx.update_time() to force updating cached time as per https://github.com/openresty/lua-nginx-module#ngxupdate_time – esboych Aug 01 '18 at 06:09
4

If you're using OpenResty then it provides for in-built millisecond time accuracy through the use of its ngx.now() function. Although if you want fine grained millisecond accuracy then you may need to call ngx.update_time() first. Or if you want to go one step further...

If you are using luajit enabled environment, such as OpenResty, then you can also use ffi to access C based time functions such as gettimeofday() e.g: (Note: The pcall check for the existence of struct timeval is only necessary if you're running it repeatedly e.g. via content_by_lua_file in OpenResty - without it you run into errors such as attempt to redefine 'timeval')

if pcall(ffi.typeof, "struct timeval") then
        -- check if already defined.
else
        -- undefined! let's define it!
        ffi.cdef[[
           typedef struct timeval {
                long tv_sec;
                long tv_usec;
           } timeval;

        int gettimeofday(struct timeval* t, void* tzp);
]]
end
local gettimeofday_struct = ffi.new("struct timeval")
local function gettimeofday()
        ffi.C.gettimeofday(gettimeofday_struct, nil)
        return tonumber(gettimeofday_struct.tv_sec) * 1000000 + tonumber(gettimeofday_struct.tv_usec)
end

Then the new lua gettimeofday() function can be called from lua to provide the clock time to microsecond level accuracy.

Indeed, one could take a similar approaching using clock_gettime() to obtain nanosecond accuracy.

Pierz
  • 7,064
  • 52
  • 59
2

in openresty there is a function ngx.req.start_time.

From the docs:

Returns a floating-point number representing the timestamp (including milliseconds as the decimal part) when the current request was created.

smartius
  • 633
  • 3
  • 10
  • 24
  • Unfortunately in my case ngx.req.start_time() returns 0. Same as os.clock() btw. Openresty ver. I'm using: "openresty/1.13.6.2" – esboych Aug 01 '18 at 06:17
2

Kevlar is correct.

An alternative to a custom DLL is Lua Alien

Doug Currie
  • 40,708
  • 1
  • 95
  • 119
2

If you're on a system with a GNU-compatible implementation of date that you can execute, here's a one-liner to get the Epoch time in milliseconds:

local function gethammertime()
  return tonumber(assert(assert(io.popen'date +%s%3N'):read'a'))
end

Note that the assert calls are necessary to ensure that any failures to read or open date will propagate the errors, respectively. Also note that this relies on garbage collection (or finalizers, in Lua 5.4) to close the process handle: if using a pre-5.4 version of Lua and resource exhaustion is a concern, you may wish to extend this to three lines like Klesun's Windows-based answer and close the handle explicitly.

Stuart P. Bentley
  • 10,195
  • 10
  • 55
  • 84
1

If your environment is Windows and you have access to system commands, you can get time of centiseconds precision with io.popen(command):

local handle = io.popen("echo %time%")
local result = handle:read("*a")
handle:close()

The result will hold string of hh:mm:ss.cc format: (with trailing line break)

"19:56:53.90\n"

Note, it's in local timezone, so you probably want to extract only the .cc part and combine it with epoch seconds from os.time().

Klesun
  • 12,280
  • 5
  • 59
  • 52
  • 2
    I wouldn't recommend trying to combine numbers from two separate timestamps: that's liable to cause jumps if the time rolls over between the two, eg. if the `io.popen` call runs at 12:34:56.99 and the `os.time` call runs at 12:34:57.00 (or vice versa). – Stuart P. Bentley May 21 '21 at 07:48
0

You can use C function gettimeofday : http://www.opengroup.org/onlinepubs/000095399/functions/gettimeofday.html

Here C library 'ul_time', function sec_usec resides in 'time' global table and returns seconds, useconds. Copy DLL to Lua folder, open it with require 'ul_time'.

http://depositfiles.com/files/3g2fx7dij

qwer
  • 959
  • 6
  • 4