Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

erlang:now() deprecated in v18, what's the best transition

Tags:

elixir

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?

like image 681
jerome Avatar asked Dec 01 '15 14:12

jerome


2 Answers

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.

like image 158
Steve Vinoski Avatar answered Sep 23 '22 21:09

Steve Vinoski


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
like image 26
potatosalad Avatar answered Sep 22 '22 21:09

potatosalad