In a package for a MongoDB driver, I needed a function to generate a unique document ID.
This function uses :erlang.now()
that is deprecated in v18
I look for help on how to migrate but no success.
My actual code (shortened):
defmodule MyModule_v17 do
use Bitwise, only_operators: true
def gen_trans_prefix do
{gs, s, ms} = :erlang.now
(gs * 1000000000000 + s * 1000000 + ms) &&& 281474976710655
end
end
best I came up with:
defmodule MyModule_v18 do
use Bitwise, only_operators: true
Kernel.if Keyword.get(:erlang.module_info, :exports) |> Enum.any?(fn({:system_time, 1}) -> true; (_) -> false end) do
def gen_trans_prefix do
:erlang.system_time(:micro_seconds) &&& 281474976710655
end
else
def gen_trans_prefix do
{gs, s, ms} = :erlang.now
(gs * 1000000000000 + s * 1000000 + ms) &&& 281474976710655
end
end
end
It does the job, but I don't feel it's the best way.
Any suggestion?
This is already covered in the "Time and Time Correction in Erlang" documentation and also in the "Time Goes On" postscript to the wonderful "Learn You Some Erlang" book.
To support both OTP 17 and 18 (and beyond) at the same time, you'll need to detect the OTP version at compile time. Here is an example from the rebar.config for the lftpc project:
{erl_opts, [
{platform_define, "(?=^[0-9]+)(?!^17$)", time_correction}
]}.
This regular expression check works because the release of OTP 17 marked the use of semantic versioning (or close to it), so anything less than OTP 17 has a version number that starts with R (like R16).
Then, in your Erlang code you can do something like this:
-ifdef(time_correction).
gen_trans_prefix() ->
{GS, S, MS} = erlang:timestamp(),
(GS * 1000000000000 + S * 1000000 + MS) band 281474976710655.
-else.
gen_trans_prefix() ->
{GS, S, MS} = erlang:now(),
(GS * 1000000000000 + S * 1000000 + MS) band 281474976710655.
-endif.
If you're using mix, you can define the erlc_options
as done in the mix.exs for the jose project:
def erlc_options do
extra_options = try do
case :erlang.list_to_integer(:erlang.system_info(:otp_release)) do
v when v >= 18 ->
[{:d, :time_correction}]
_ ->
[]
end
catch
_ ->
[]
end
extra_options
end
The erlc_options
can be referenced by Erlang or Elixir code for the project (similar to the solution you mentioned in your question):
defmodule MyModule do
use Bitwise, only_operators: true
if Enum.member?(Mix.Project.get!.project[:erlc_options] || [], {:d, :time_correction}) do
def gen_trans_prefix do
{gs, s, ms} = :erlang.timestamp
(gs * 1000000000000 + s * 1000000 + ms) &&& 281474976710655
end
else
def gen_trans_prefix do
{gs, s, ms} = :erlang.now
(gs * 1000000000000 + s * 1000000 + ms) &&& 281474976710655
end
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With