1
1
defmodule Date.Range do
2
2
@ moduledoc """
3
- Defines a range of dates.
3
+ Returns an inclusive range between dates.
4
4
5
- A range of dates represents a discrete number of dates where
6
- the first and last values are dates with matching calendars.
5
+ Ranges must be created with the `Date.range/2` function.
7
6
8
- Ranges of dates can be either increasing (`first <= last`) or
9
- decreasing (`first > last`). They are also always inclusive.
7
+ The following fields are public:
10
8
11
- A range of dates implements the `Enumerable` protocol, which means
12
- functions in the `Enum` module can be used to work with
13
- ranges:
14
-
15
- iex> range = Date.range(~D[2001-01-01], ~D[2002-01-01])
16
- iex> Enum.count(range)
17
- 366
18
- iex> Enum.member?(range, ~D[2001-02-01])
19
- true
20
- iex> Enum.reduce(range, 0, fn(_date, acc) -> acc - 1 end)
21
- -366
9
+ * `:first` - the initial date on the range
10
+ * `:last` - the last date on the range
22
11
12
+ The remaining fields are private and should not be accessed.
23
13
"""
24
14
25
- @ opaque t :: % __MODULE__ { first: Date . t , last: Date . t }
26
- @ doc false
15
+ @ type t :: % __MODULE__ { first: Date . t , last: Date . t ,
16
+ first_rata_die: rata_die_days , last_rata_die: rata_die_days }
17
+
18
+ @ opaque rata_die_days :: Calendar . days
19
+
27
20
defstruct [ :first , :last , :first_rata_die , :last_rata_die ]
28
21
29
22
defimpl Enumerable do
30
- def member? ( % Date.Range { first: % { calendar: calendar , year: first_year , month: first_month , day: first_day } ,
31
- last: % { calendar: calendar , year: last_year , month: last_month , day: last_day } ,
32
- first_rata_die: first_rata_die , last_rata_die: last_rata_die } ,
33
- % Date { calendar: calendar , year: year , month: month , day: day } ) do
23
+ def member? ( % { first: % { calendar: calendar , year: first_year , month: first_month , day: first_day } ,
24
+ last: % { calendar: calendar , year: last_year , month: last_month , day: last_day } ,
25
+ first_rata_die: first_rata_die , last_rata_die: last_rata_die } ,
26
+ % Date { calendar: calendar , year: year , month: month , day: day } ) do
34
27
first = { first_year , first_month , first_day }
35
28
last = { last_year , last_month , last_day }
36
29
date = { year , month , day }
@@ -50,29 +43,40 @@ defmodule Date.Range do
50
43
{ :ok , abs ( first_rata_die - last_rata_die ) + 1 }
51
44
end
52
45
53
- def reduce ( % Date.Range { first_rata_die: first_rata_die , last_rata_die: last_rata_die , first: % { calendar: c } } , acc , fun ) do
54
- reduce ( first_rata_die , last_rata_die , acc , & ( fun . ( Date . from_rata_die_days ( & 1 , c ) , & 2 ) ) , first_rata_die <= last_rata_die )
46
+ def reduce ( % Date.Range { first_rata_die: first_rata_die , last_rata_die: last_rata_die ,
47
+ first: % { calendar: calendar } } , acc , fun ) do
48
+ reduce ( first_rata_die , last_rata_die , acc , fun , calendar , first_rata_die <= last_rata_die )
55
49
end
56
50
57
- defp reduce ( _x , _y , { :halt , acc } , _fun , _up? ) do
51
+ defp reduce ( _x , _y , { :halt , acc } , _fun , _calendar , _up? ) do
58
52
{ :halted , acc }
59
53
end
60
54
61
- defp reduce ( x , y , { :suspend , acc } , fun , up? ) do
62
- { :suspended , acc , & reduce ( x , y , & 1 , fun , up? ) }
55
+ defp reduce ( x , y , { :suspend , acc } , fun , calendar , up? ) do
56
+ { :suspended , acc , & reduce ( x , y , & 1 , fun , calendar , up? ) }
63
57
end
64
58
65
- defp reduce ( x , y , { :cont , acc } , fun , _up ? = true ) when x <= y do
66
- reduce ( x + 1 , y , fun . ( x , acc ) , fun , _up? = true )
59
+ defp reduce ( x , y , { :cont , acc } , fun , calendar , up ? = true ) when x <= y do
60
+ reduce ( x + 1 , y , fun . ( date_from_rata_days ( x , calendar ) , acc ) , fun , calendar , up? )
67
61
end
68
62
69
- defp reduce ( x , y , { :cont , acc } , fun , _up ? = false ) when x >= y do
70
- reduce ( x - 1 , y , fun . ( x , acc ) , fun , _up? = false )
63
+ defp reduce ( x , y , { :cont , acc } , fun , calendar , up ? = false ) when x >= y do
64
+ reduce ( x - 1 , y , fun . ( date_from_rata_days ( x , calendar ) , acc ) , fun , calendar , up? )
71
65
end
72
66
73
- defp reduce ( _ , _ , { :cont , acc } , _fun , _up ) do
67
+ defp reduce ( _ , _ , { :cont , acc } , _fun , _calendar , _up ) do
74
68
{ :done , acc }
75
69
end
70
+
71
+ defp date_from_rata_days ( days , Calendar.ISO ) do
72
+ { year , month , day } = Calendar.ISO . date_from_rata_die_days ( days )
73
+ % Date { year: year , month: month , day: day , calendar: Calendar.ISO }
74
+ end
75
+
76
+ defp date_from_rata_days ( days , calendar ) do
77
+ { year , month , day , _ , _ , _ , _ } = calendar . naive_datetime_from_rata_die ( { days , { 0 , 86400000000 } } )
78
+ % Date { year: year , month: month , day: day , calendar: calendar }
79
+ end
76
80
end
77
81
78
82
defimpl Inspect do
0 commit comments