You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现产品插入日期/范围查询?解决:utc_datetime转换报错

问题:产品插入日期筛选功能报错,无法将日期字符串转为:utc_datetime

需要实现按产品插入日期过滤的功能,支持单日期(起始/结束)或日期范围筛选,但修改查询语句后一直报错,不确定代码是否正确,求改进建议和解决方案。

表单代码

<%= form_for @conn, Routes.products_path(@conn, :index), [method: :get, as: :search, class: "ml-2 row", page_size: @page.page_size, page: @page.page_number], fn f -> %>
  <div class="col-12 align-items-end row">
    <label class="form-label col-1">
      <%= search_input f, :start_date,  class: "form-control", placeholder: "From" %>
    </label>
    <label class="form-label col-1">
      <%= search_input f, :end_date,  class: "form-control", placeholder: "To" %>
    </label>
    <label class="form-label col-1">
      <%= submit "Search", class: "btn btn-primary" %>
    </label>
  </div>
<% end %>

控制器index函数代码

products = ProductsRepo.get_products_by_insertion_date(start_date, end_date)

page =
  products
  |> ProductsRepo.paginate()
render(conn, "index.html", products: page.entries, page: page)

查询函数代码

def get_products_by_insertion_date(nil, nil) do
  Products
end

def get_products_by_insertion_date(start_date, nil) do
  from(p in Products, where: p.inserted_at >= ^start_date)
end

def get_products_by_insertion_date(nil, end_date) do
  from(p in Products, where: p.inserted_at <= ^end_date)
end

def get_products_by_insertion_date(start_date, end_date) do
  from(p in Products,
  where: p.inserted_at >= ^start_date and
  p.inserted_at <= ^end_date
  )
end

当前报错信息

值 "2023-01-13" 在 where 条件中无法转换为类型 :utc_datetime


解决方案

报错核心原因:表单提交的是纯字符串格式日期(如"2023-01-13"),但数据库inserted_at字段是:utc_datetime类型,Ecto无法直接将无时间信息的日期字符串转换为带UTC时间的日期类型。

步骤1:在控制器中转换日期参数

需要把表单传来的日期字符串解析为Ecto可识别的DateTime类型,同时处理空值和日期范围的边界问题(比如结束日期要包含当天的最后一秒):

def index(conn, %{"search" => search_params}) do
  start_date = parse_date(search_params["start_date"], false)
  end_date = parse_date(search_params["end_date"], true)

  products = ProductsRepo.get_products_by_insertion_date(start_date, end_date)
  page = products |> ProductsRepo.paginate()
  render(conn, "index.html", products: page.entries, page: page)
end

# 辅助解析函数:处理日期字符串转UTC DateTime
defp parse_date(nil, _), do: nil
defp parse_date("", _), do: nil
defp parse_date(date_str, false) do
  # 起始日期:转为当天00:00:00的UTC时间
  case NaiveDateTime.from_iso8601("#{date_str}T00:00:00") do
    {:ok, naive_dt} -> DateTime.from_naive!(naive_dt, "Etc/UTC")
    _ -> nil
  end
end
defp parse_date(date_str, true) do
  # 结束日期:转为当天23:59:59的UTC时间
  case NaiveDateTime.from_iso8601("#{date_str}T23:59:59") do
    {:ok, naive_dt} -> DateTime.from_naive!(naive_dt, "Etc/UTC")
    _ -> nil
  end
end

步骤2:优化查询函数(可选)

可以将多子句查询简化为单函数,通过条件拼接减少代码重复:

def get_products_by_insertion_date(start_date, end_date) do
  query = from p in Products

  query = if start_date, do: from p in query, where: p.inserted_at >= ^start_date, else: query
  query = if end_date, do: from p in query, where: p.inserted_at <= ^end_date, else: query

  query
end

额外优化建议

  • 表单中使用date_input替代search_input,浏览器会提供标准日期选择器,确保提交的日期格式为YYYY-MM-DD,减少格式错误:
    <%= date_input f, :start_date, class: "form-control", placeholder: "From" %>
    <%= date_input f, :end_date, class: "form-control", placeholder: "To" %>
    
  • 增加参数验证逻辑,若日期格式无效,返回前端友好提示,避免无效查询。

内容的提问来源于stack exchange,提问作者Kacper Wielki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 05:52:57