To support OTP 17 and 18 (and later) at the same time, you will need to detect the OTP version at compile time. The following is an example from 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 has indicated the use of a semantic version (or close to it), so anything smaller than OTP 17 has a version number starting with R (for example, R16).
Then in 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 are using a mix, you can define erlc_options , as is done in 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
erlc_options can be referenced in the Erlang or Elixir code for the project (similar to the solution 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