I’m trying to determine the fastest way to add UTC time stamps with a resolution of 1 s to automated logs of data reading and processing. This is used frequently as data are read into memory and processed. Suggestions would be welcome; my questions are at the bottom.
Trial solutions below are adapted from Higher resolution DateTime/TimeStamp - #45 by yakir12 . The first two give higher-resolution time stamps than I need, but that’s fine for comparison purposes.
using AstroTime, BenchmarkTools, Dates, Base.Libc
timestamp0() = string(Dates.now(Dates.UTC))
timestamp1() = string(AstroTime.now()) # not UTC??
function timestamp2()
  t = Dates.unix2datetime(Dates.time())
  Y, M, D, h, m, s = year(t), month(t), day(t),
    hour(t), minute(t), second(t)
  Ys = lpad(Y, 4, "0")
  Ms = lpad(M, 2, "0")
  Ds = lpad(D, 2, "0")
  hs = lpad(h, 2, "0")
  ms = lpad(m, 2, "0")
  ss = lpad(s, 2, "0")
  return string(Ys, "-", Ms, "-", Ds, "T", hs, ":", ms, ":", ss)
end
I swear I’m 20 years rusty at C and not even fond of external calls, but then there’s this, adapted from Getting the value of a pointer in Julia | juliabloggers.com …
mutable struct TBuf
  t::Base.RefValue{Int64}
  m::TmStruct
  b::Array{UInt8,1}
  f::String
  p::Ptr{UInt8}
  function TBuf()
    T = new(Ref{Int64}(0), TmStruct(), zeros(UInt8,20),
            "%FT%T", Ptr{UInt8}())
    T.p = pointer(T.b)
    return T
  end
end
const T = TBuf()
function timestamp3()
  ccall(:time, Nothing, (Ptr{Int64},), T.t)
  ccall(Sys.iswindows() ? :gmtime_s : :gmtime_r, Nothing,
        (Ptr{Int64}, Ref{TmStruct}), T.t, T.m)
  ccall(:strftime, Nothing,
        (Cstring, Cint, Cstring, Ref{TmStruct}),
        T.p, Int32(20), T.f, T.m)
  return unsafe_string(T.p)
end
Results
Intel(R) Core™ i7-6820HQ CPU @ 2.70GHz
15862 MiB RAM
Ubuntu 18.04 (bionic)
Julia 1.3.1
| Method | Mem | t | 
|---|---|---|
| timestamp0 | 912 B | 701.199 ns | 
| timestamp1 | 1.63 KB | 3.610 μs | 
| timestamp2 | 688 B | 584.849 ns | 
| timestamp3 | 48 B | 313.776 ns | 
My questions
- Are the C calls in timestamp3()safe as written? Do I need to set appropriate return Types, even though they modify variables in-place, or can I leave as Nothing?
- Is a memory-resident structure with Ref and Ptr as fields OK, or is this a spectacularly bad idea? For example, are there gc issues?
- Any suggestions that I might have missed?
Thanks, and my apologies for the length of the post.