Hi! I spent a long time trying to figure out the best way to get all entries in a specific date range. So wanted to share my solution and see if there’s a better way.
Is this the best way to go about it? Set all NaiveDateTime’s time to 00:00:00.0000 for today and tomorrow, then get today >= and < tomorrow’s entries.
I use the following code to search for “published” records in a database - that means records that are available only during a specific period of time (date range):
from(q in queryable
where: fragment("now() between ? and coalesce(?, now())", q.start_date, q.end_date)
)
Since the range can be open-ended (end_date == NULL), I use coalesce to avoid problems. Other than that, Postgres between and now() functions are very useful.
If you want to return all entries from said date then how about simply converting PostgreSQL’s timestamp to date?
Here is an example script:
Mix.install([:ecto_sql, :postgrex])
defmodule Migration do
use Ecto.Migration
def change do
create table("tests") do
add(:timestamp, :naive_datetime)
end
end
end
defmodule Repo do
use Ecto.Repo, adapter: Ecto.Adapters.Postgres, otp_app: :my_app
end
defmodule Test do
use Ecto.Schema
schema "tests" do
field(:timestamp, :naive_datetime_usec)
end
end
defmodule Example do
alias Ecto.Query
require Query
def cleanup do
Repo.stop()
end
def prepare do
Application.put_env(:my_app, Repo,
database: "example",
password: "postgres",
username: "postgres"
)
_ = Repo.__adapter__().storage_down(Repo.config())
:ok = Repo.__adapter__().storage_up(Repo.config())
{:ok, _} = Supervisor.start_link([Repo], strategy: :one_for_one)
Ecto.Migrator.up(Repo, 0, Migration)
end
def sample do
now = NaiveDateTime.utc_now()
Test
|> Query.from(as: :test)
|> Query.where(
[test: test],
fragment("?::date = ?::date", test.timestamp, type(^now, :naive_datetime))
)
|> Query.select([test: test], test.timestamp)
|> Repo.all()
|> IO.inspect()
end
def seed do
seconds_in_day = 24 * 60 * 60
now = NaiveDateTime.utc_now()
yesterday = NaiveDateTime.add(now, seconds_in_day * -1, :second)
tomorrow = NaiveDateTime.add(now, seconds_in_day, :second)
Repo.insert(%Test{timestamp: yesterday})
Repo.insert(%Test{timestamp: now})
Repo.insert(%Test{timestamp: tomorrow})
end
end
Example.prepare()
Example.seed()
Example.sample()
Example.cleanup()