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

如何用Absinthe获取指定日期后创建的用户?解决NaiveDateTime类型错误

在Phoenix & Absinthe中实现指定日期后的用户筛选解决方案

嘿,我明白你遇到的问题了——你以为NaiveDateTime能直接解析纯日期字符串,但Absinthe默认的标量规则其实要求带时间的ISO格式。下面给你两种靠谱的解决办法:

方法1:直接用标准NaiveDateTime格式查询

这是最快的解决方式,不用改代码,只需要调整你的GraphQL变量,给日期加上时间部分就行:

你的查询语句不变:

query($filter: UserFilter){
  allUsers(filter: $filter){
    id firstName lastName
  }
}

把变量改成带时间的格式:

{
  "filter": {
    "insertedAfter": "2018-05-13T00:00:00"
  }
}

这样Absinthe就能自动把这个字符串转成Elixir的NaiveDateTime类型,你的resolver和过滤逻辑完全不用动,直接就能用。

方法2:自定义日期标量(支持纯日期输入)

如果你希望API更友好,能接受"2018-05-13"这种纯日期字符串,那可以自定义一个标量来处理转换:

第一步:在types.ex里添加自定义标量

use Absinthe.Schema.Notation
use Absinthe.Ecto, repo: ElixirBlog.Repo
import_types Absinthe.Type.Custom

# 自定义支持纯日期的标量,自动转成当天0点的NaiveDateTime
scalar :date do
  parse fn input ->
    with %Absinthe.Blueprint.Input.String{value: date_str} <- input,
         {:ok, date} <- Date.from_iso8601(date_str),
         {:ok, naive_dt} <- NaiveDateTime.new(date, ~T[00:00:00]) do
      {:ok, naive_dt}
    else
      _ -> :error
    end
  end

  serialize fn naive_dt ->
    naive_dt |> NaiveDateTime.to_date() |> Date.to_iso8601()
  end
end

# ... 原来的:user类型定义保持不变

第二步:修改UserFilter的字段类型

在schema.ex里,把筛选字段的类型从:naive_datetime换成我们自定义的:date:

input_object :user_filter do
  field :id, :integer
  field :first_name, :string
  field :last_name, :string
  field :email, :string
  field :inserted_before, :date  # 替换成自定义标量
  field :inserted_after, :date   # 替换成自定义标量
end

第三步:Resolver逻辑不用改

你的filter_with函数里的日期比较逻辑完全没问题,因为自定义标量已经把纯日期字符串转成了NaiveDateTime(当天的00:00:00),可以直接和数据库的inserted_at字段对比。

进阶:支持多种格式的灵活标量

如果想同时支持纯日期和带时间的格式,可以把自定义标量的解析逻辑写得更灵活:

scalar :flexible_datetime do
  parse fn input ->
    with %Absinthe.Blueprint.Input.String{value: str} <- input do
      # 先尝试解析成完整的NaiveDateTime
      case NaiveDateTime.from_iso8601(str) do
        {:ok, ndt} -> {:ok, ndt}
        _ ->
          # 失败就尝试解析成Date,再转成当天0点
          case Date.from_iso8601(str) do
            {:ok, date} -> NaiveDateTime.new(date, ~T[00:00:00])
            _ -> :error
          end
      end
    end
  end

  serialize fn ndt -> NaiveDateTime.to_iso8601(ndt) end
end

然后把UserFilter里的字段类型改成:flexible_datetime就可以同时接受两种格式的输入了。


内容的提问来源于stack exchange,提问作者Yuki Umetsu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:58:28