-
-
Notifications
You must be signed in to change notification settings - Fork 181
/
datetime.ex
103 lines (83 loc) · 2.46 KB
/
datetime.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
defmodule Ash.Type.DateTime do
@moduledoc """
Represents a datetime, with configurable precision and timezone.
"""
@beginning_of_day Time.new!(0, 0, 0)
@constraints [
precision: [
type: {:one_of, [:microsecond, :second]},
default: :second
],
timezone: [
type: {:one_of, [:utc]},
default: :utc
]
]
use Ash.Type
@impl true
def constraints, do: @constraints
@impl true
def init(constraints) do
{precision, constraints} = Keyword.pop(constraints, :precision)
precision = precision || :second
{:ok, [{:precision, precision} | constraints]}
end
@impl true
@spec storage_type(nonempty_maybe_improper_list()) :: any()
def storage_type([{:precision, :microsecond} | _]) do
:utc_datetime_usec
end
def storage_type(_constraints) do
:utc_datetime
end
@impl true
def generator(_constraints) do
# Waiting on blessed date/datetime generators in stream data
# https://github.com/whatyouhide/stream_data/pull/161/files
StreamData.constant(DateTime.utc_now())
end
@impl true
def cast_input(%Date{} = date, constraints) do
case DateTime.new(date, @beginning_of_day) do
{:ok, value} ->
cast_input(value, constraints)
_ ->
{:error, "Date could not be converted to datetime"}
end
end
def cast_input(
%DateTime{microsecond: {_, _} = microseconds} = datetime,
[{:precision, :second} | _] = constraints
)
when microseconds != {0, 0} do
cast_input(%{datetime | microsecond: {0, 0}}, constraints)
end
def cast_input(
%DateTime{microsecond: {0, 0}} = datetime,
[{:precision, :microsecond} | _] = constraints
) do
cast_input(%{datetime | microsecond: {0, 6}}, constraints)
end
def cast_input(
%DateTime{microsecond: nil} = datetime,
[{:precision, :microsecond} | _] = constraints
) do
cast_input(%{datetime | microsecond: {0, 6}}, constraints)
end
def cast_input(value, constraints) do
Ecto.Type.cast(storage_type(constraints), value)
end
@impl true
def cast_stored(nil, _), do: {:ok, nil}
def cast_stored(value, constraints) when is_binary(value) do
cast_input(value, constraints)
end
def cast_stored(value, constraints) do
Ecto.Type.load(storage_type(constraints), value)
end
@impl true
def dump_to_native(nil, _), do: {:ok, nil}
def dump_to_native(value, constraints) do
Ecto.Type.dump(storage_type(constraints), value)
end
end