Handling DateTime precision > 6

NaiveDateTime.from_erl/2 limits us to 6 digit precision.

How may we handle higher precision?

Case in point: {{2017, 11, 30}, {18, 37, 26, 2690120}} is pulled from a SQLServer datetime2(7) field.

see this:

my code is:

  defp to_date({year, month, day}), do: NaiveDateTime.from_erl!({{year, month, day}, {0, 0, 0}}, {0, 6}) |> NaiveDateTime.to_string()
  defp to_date({{year, month, day}, {hour, min, sec, msec}}) when msec < 1000000,
    do: NaiveDateTime.from_erl!({{year, month, day}, {hour, min, sec}}, {msec, 6}) |> NaiveDateTime.to_string()

  defp to_date(x), do: x

I’m using msec < 1000000 to prevent errors, but i’m loosing higher precision time-stamps.

Any suggestions please.

2 Likes

Clamping those to 1_000_000 will give you wrong result. You are basically multiplying the fractions with 10 and discarding 90% of the possible values.

The proper way is to throw away one level of precision by dividing by 10:

NaiveDateTime.from_erl!({{2017, 11, 30}, {18, 37, 26}}, div(2690120, 10))

Or alternatively using NaiveDateTime.add/3 to add a proper amount of nanoseconds, which will get truncatet to microseconds internally anyway:

iex(1)> {:ok, dt} = NaiveDateTime.from_erl({{2017, 11, 30}, {18, 37, 26}})              
{:ok, ~N[2017-11-30 18:37:26]}
iex(2)> NaiveDateTime.add(dt, 2690120 * 100, :nanoseconds)
~N[2017-11-30 18:37:26]
iex(3)> i(v(2))
Term
  ~N[2017-11-30 18:37:26]
Data type
  NaiveDateTime
Description
  This is a struct representing a "naive" datetime (that is, a datetime without a timezone). It is commonly represented
  using the `~N` sigil syntax, that is defined in the `Kernel.sigil_N/2` macro.
Raw representation
  %NaiveDateTime{calendar: Calendar.ISO, day: 30, hour: 18, microsecond: {269012, 0}, minute: 37, month: 11, second: 26, year: 2017}
Reference modules
  NaiveDateTime, Calendar, Map
Implemented protocols
  IEx.Info, String.Chars, Inspect

The field in the struct is called microseconds, any precision beyond 6 does not make any sense with that name.Also that field is of type Calendar.microsecond/0, which is defined as this: microsecond() :: {0..999999, 0..6}.

3 Likes

Thanks for spotting my error,

NaiveDateTime.from_erl!({{2017, 11, 30}, {18, 37, 26}}, div(2690120, 10))

Should give the correct roundup, although just for 7-digit precision which is still fine.

1 Like

In other words, We really cant go beyond below :microseconds precision.

Noted.

1 Like

But maybe asking on core might help to introduce a higher and/or more flexible way of specifying fractions of seconds?

1 Like

True. I wonder why the precision was not taken all the way to :nanoseconds being that the VM has support for that.

2 Likes

Well, in we could use those to save arbitrary timestamps from input with even higher precision, some data samples in a lab maybe?

2 Likes