Skip to content

Commit 413d833

Browse files
wojtekmachJosé Valim
authored andcommitted
Update docs & typespecs for calendar modules (#6313)
1 parent 35fae47 commit 413d833

File tree

4 files changed

+147
-64
lines changed

4 files changed

+147
-64
lines changed

lib/elixir/lib/calendar/date.ex

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ defmodule Date do
6767
6868
## Examples
6969
70-
iex> Date.range(~D[2000-01-01], ~D[2001-01-01])
71-
#DateRange<~D[2000-01-01], ~D[2001-01-01]>
70+
iex> Date.range(~D[1999-01-01], ~D[2000-01-01])
71+
#DateRange<~D[1999-01-01], ~D[2000-01-01]>
72+
73+
iex> Date.range(~N[2000-01-01 09:00:00], ~D[1999-01-01])
74+
#DateRange<~N[2000-01-01 09:00:00], ~D[1999-01-01]>
7275
7376
A range of dates implements the `Enumerable` protocol, which means
7477
functions in the `Enum` module can be used to work with
@@ -83,7 +86,7 @@ defmodule Date do
8386
-366
8487
"""
8588

86-
@spec range(Date.t, Date.t) :: Date.Range.t
89+
@spec range(Calendar.date, Calendar.date) :: Date.Range.t
8790
def range(%{calendar: calendar} = first, %{calendar: calendar} = last) do
8891
{first_days, _} = to_rata_die(first)
8992
{last_days, _} = to_rata_die(last)
@@ -96,7 +99,8 @@ defmodule Date do
9699
}
97100
end
98101

99-
def range(%Date{}, %Date{}) do
102+
def range(%{calendar: _, year: _, month: _, day: _},
103+
%{calendar: _, year: _, month: _, day: _}) do
100104
raise ArgumentError, "both dates must have matching calendars"
101105
end
102106

@@ -125,7 +129,7 @@ defmodule Date do
125129
end
126130

127131
@doc """
128-
Returns true if the year in `date` is a leap year.
132+
Returns true if the year in the given `date` is a leap year.
129133
130134
## Examples
131135
@@ -149,7 +153,7 @@ defmodule Date do
149153
end
150154

151155
@doc """
152-
Returns the number of days in the given date month.
156+
Returns the number of days in the given `date` month.
153157
154158
## Examples
155159
@@ -309,7 +313,7 @@ defmodule Date do
309313
end
310314

311315
@doc """
312-
Converts a `Date` struct to an Erlang date tuple.
316+
Converts the given `date` to an Erlang date tuple.
313317
314318
Only supports converting dates which are in the ISO calendar,
315319
or other calendars in which the days also start at midnight.
@@ -375,7 +379,7 @@ defmodule Date do
375379
end
376380

377381
@doc """
378-
Compares two `Date` structs.
382+
Compares two date structs.
379383
380384
Returns `:gt` if first date is later than the second
381385
and `:lt` for vice versa. If the two dates are equal
@@ -424,15 +428,25 @@ defmodule Date do
424428
end
425429

426430
@doc """
427-
Converts a date from one calendar to another.
431+
Converts the given `date` from it's calendar to the given `calendar`.
428432
429433
Returns `{:ok, date}` if the calendars are compatible,
430434
or `{:error, :incompatible_calendars}` if they are not.
431435
432436
See also `Calendar.compatible_calendars?/2`.
437+
438+
## Examples
439+
440+
Imagine someone implements `Calendar.Julian`:
441+
442+
iex> Date.convert(~D[2000-01-01], Calendar.Julian)
443+
{:ok, %Date{calendar: Calendar.Julian, year: 1999, month: 12, day: 19}}
444+
433445
"""
434-
@spec convert(Calendar.date(), Calendar.calendar) :: {:ok, Date.t} | {:error, :incompatible_calendars}
435-
def convert(%Date{calendar: calendar} = date, calendar), do: {:ok, date}
446+
@spec convert(Calendar.date, Calendar.calendar) :: {:ok, t} | {:error, :incompatible_calendars}
447+
def convert(%{calendar: calendar, year: year, month: month, day: day}, calendar) do
448+
{:ok, %Date{calendar: calendar, year: year, month: month, day: day}}
449+
end
436450
def convert(%{calendar: calendar} = date, target_calendar) do
437451
if Calendar.compatible_calendars?(calendar, target_calendar) do
438452
result_date =
@@ -448,8 +462,16 @@ defmodule Date do
448462
@doc """
449463
Similar to `Date.convert/2`, but raises an `ArgumentError`
450464
if the conversion between the two calendars is not possible.
465+
466+
## Examples
467+
468+
Imagine someone implements `Calendar.Julian`:
469+
470+
iex> Date.convert!(~D[2000-01-01], Calendar.Julian)
471+
%Date{calendar: Calendar.Julian, year: 1999, month: 12, day: 19}
472+
451473
"""
452-
@spec convert!(Date.t, Calendar.calendar) :: Date.t
474+
@spec convert!(Calendar.date, Calendar.calendar) :: t
453475
def convert!(date, calendar) do
454476
case convert(date, calendar) do
455477
{:ok, value} ->
@@ -460,7 +482,7 @@ defmodule Date do
460482
end
461483

462484
@doc """
463-
Adds the number of days to the given date.
485+
Adds the number of days to the given `date`.
464486
465487
The days are counted as gregorian days. The date is returned in the same
466488
calendar as it was given in.
@@ -472,9 +494,12 @@ defmodule Date do
472494
iex> Date.add(~D[2000-01-01], 2)
473495
~D[2000-01-03]
474496
497+
iex> Date.add(~N[2000-01-01 09:00:00], 2)
498+
~D[2000-01-03]
499+
475500
"""
476-
@spec add(Date.t, integer()) :: Date.t
477-
def add(%Date{calendar: calendar} = date, days) do
501+
@spec add(Calendar.date, integer()) :: t
502+
def add(%{calendar: calendar} = date, days) do
478503
{rata_days, fraction} = to_rata_die(date)
479504
from_rata_die({rata_days + days, fraction}, calendar)
480505
end
@@ -493,16 +518,19 @@ defmodule Date do
493518
iex> Date.diff(~D[2000-01-01], ~D[2000-01-03])
494519
-2
495520
521+
iex> Date.diff(~D[2000-01-01], ~N[2000-01-03 09:00:00])
522+
-2
523+
496524
"""
497-
@spec diff(Date.t, Date.t) :: integer
498-
def diff(%Date{calendar: Calendar.ISO, year: year1, month: month1, day: day1},
499-
%Date{calendar: Calendar.ISO, year: year2, month: month2, day: day2}) do
525+
@spec diff(Calendar.date, Calendar.date) :: integer
526+
def diff(%{calendar: Calendar.ISO, year: year1, month: month1, day: day1},
527+
%{calendar: Calendar.ISO, year: year2, month: month2, day: day2}) do
500528
Calendar.ISO.date_to_rata_die_days(year1, month1, day1) -
501529
Calendar.ISO.date_to_rata_die_days(year2, month2, day2)
502530
end
503531

504-
def diff(%Date{} = date1, %Date{} = date2) do
505-
if Calendar.compatible_calendars?(date1.calendar, date2.calendar) do
532+
def diff(%{calendar: calendar1} = date1, %{calendar: calendar2} = date2) do
533+
if Calendar.compatible_calendars?(calendar1, calendar2) do
506534
{days1, _} = to_rata_die(date1)
507535
{days2, _} = to_rata_die(date2)
508536
days1 - days2
@@ -528,7 +556,7 @@ defmodule Date do
528556
end
529557

530558
@doc """
531-
Calculates the day of the week of a given `Date` struct.
559+
Calculates the day of the week of a given `date`.
532560
533561
Returns the day of the week as an integer. For the ISO 8601
534562
calendar (the default), it is an integer from 1 to 7, where

lib/elixir/lib/calendar/datetime.ex

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ defmodule DateTime do
1212
are structural and based on the DateTime struct fields. For proper
1313
comparison between datetimes, use the `compare/2` function.
1414
15+
The functions on this module work with the `DateTime` struct as well
16+
as any struct that contains the same fields as the `DateTime` struct.
17+
Such functions expect `t:Calendar.datetime/0` in their typespecs
18+
(instead of `t:t/0`).
19+
1520
Developers should avoid creating the DateTime struct directly
1621
and instead rely on the functions provided by this module as
1722
well as the ones in 3rd party calendar libraries.
@@ -52,13 +57,13 @@ defmodule DateTime do
5257
"Etc/UTC"
5358
5459
"""
55-
@spec utc_now(Calendar.calendar) :: DateTime.t
60+
@spec utc_now(Calendar.calendar) :: t
5661
def utc_now(calendar \\ Calendar.ISO) do
5762
System.os_time |> from_unix!(:native, calendar)
5863
end
5964

6065
@doc """
61-
Converts the given Unix time to DateTime.
66+
Converts the given Unix time to `DateTime`.
6267
6368
The integer can be given in different unit
6469
according to `System.convert_time_unit/3` and it will
@@ -86,7 +91,7 @@ defmodule DateTime do
8691
Negative Unix times are supported, up to -62167219200 seconds,
8792
which is equivalent to "0000-01-01T00:00:00Z" or 0 Gregorian seconds.
8893
"""
89-
@spec from_unix(integer, :native | System.time_unit, Calendar.calendar) :: {:ok, DateTime.t} | {:error, atom}
94+
@spec from_unix(integer, :native | System.time_unit, Calendar.calendar) :: {:ok, t} | {:error, atom}
9095
def from_unix(integer, unit \\ :second, calendar \\ Calendar.ISO) when is_integer(integer) do
9196
case Calendar.ISO.from_unix(integer, unit) do
9297
{:ok, {year, month, day}, {hour, minute, second}, microsecond} ->
@@ -100,7 +105,7 @@ defmodule DateTime do
100105
end
101106

102107
@doc """
103-
Converts the given Unix time to DateTime.
108+
Converts the given Unix time to `DateTime`.
104109
105110
The integer can be given in different unit
106111
according to `System.convert_time_unit/3` and it will
@@ -122,7 +127,7 @@ defmodule DateTime do
122127
#DateTime<2015-05-25 13:26:08.868569Z>
123128
124129
"""
125-
@spec from_unix!(integer, :native | System.time_unit, Calendar.calendar) :: DateTime.t
130+
@spec from_unix!(integer, :native | System.time_unit, Calendar.calendar) :: t
126131
def from_unix!(integer, unit \\ :second, calendar \\ Calendar.ISO) when is_atom(unit) do
127132
case from_unix(integer, unit, calendar) do
128133
{:ok, datetime} ->
@@ -133,7 +138,7 @@ defmodule DateTime do
133138
end
134139

135140
@doc """
136-
Converts the given NaiveDateTime to DateTime.
141+
Converts the given `NaiveDateTime` to `DateTime`.
137142
138143
It expects a time zone to put the NaiveDateTime in.
139144
Currently it only supports "Etc/UTC" as time zone.
@@ -145,7 +150,7 @@ defmodule DateTime do
145150
#DateTime<2016-05-24 13:26:08.003Z>
146151
147152
"""
148-
@spec from_naive(NaiveDateTime.t, Calendar.time_zone) :: {:ok, DateTime.t}
153+
@spec from_naive(NaiveDateTime.t, Calendar.time_zone) :: {:ok, t}
149154
def from_naive(naive_datetime, time_zone)
150155

151156
def from_naive(%NaiveDateTime{calendar: calendar,
@@ -157,7 +162,7 @@ defmodule DateTime do
157162
end
158163

159164
@doc """
160-
Converts the given NaiveDateTime to DateTime.
165+
Converts the given `NaiveDateTime` to `DateTime`.
161166
162167
It expects a time zone to put the NaiveDateTime in.
163168
Currently it only supports "Etc/UTC" as time zone.
@@ -168,7 +173,7 @@ defmodule DateTime do
168173
#DateTime<2016-05-24 13:26:08.003Z>
169174
170175
"""
171-
@spec from_naive!(non_neg_integer, :native | System.time_unit) :: DateTime.t
176+
@spec from_naive!(NaiveDateTime.t, Calendar.time_zone) :: t
172177
def from_naive!(naive_datetime, time_zone) do
173178
case from_naive(naive_datetime, time_zone) do
174179
{:ok, datetime} ->
@@ -179,9 +184,9 @@ defmodule DateTime do
179184
end
180185

181186
@doc """
182-
Converts the given DateTime to Unix time.
187+
Converts the given `datetime` to Unix time.
183188
184-
The DateTime is expected to be using the ISO calendar
189+
The `datetime` is expected to be using the ISO calendar
185190
with a year greater than or equal to 0.
186191
187192
It will return the integer with the given unit,
@@ -205,18 +210,18 @@ defmodule DateTime do
205210
-17412508655
206211
207212
"""
208-
@spec to_unix(DateTime.t, System.time_unit) :: non_neg_integer
213+
@spec to_unix(Calendar.datetime, System.time_unit) :: integer
209214
def to_unix(datetime, unit \\ :second)
210215

211-
def to_unix(%DateTime{utc_offset: utc_offset, std_offset: std_offset} = datetime, unit) do
216+
def to_unix(%{utc_offset: utc_offset, std_offset: std_offset} = datetime, unit) do
212217
{days, fraction} = to_rata_die(datetime)
213218
unix_units = Calendar.ISO.rata_die_to_unit({days - @unix_days, fraction}, unit)
214219
offset_units = System.convert_time_unit(utc_offset + std_offset, :second, unit)
215220
unix_units - offset_units
216221
end
217222

218223
@doc """
219-
Converts a `DateTime` into a `NaiveDateTime`.
224+
Converts the given `datetime` into a `NaiveDateTime`.
220225
221226
Because `NaiveDateTime` does not hold time zone information,
222227
any time zone related data will be lost during the conversion.
@@ -230,7 +235,8 @@ defmodule DateTime do
230235
~N[2000-02-29 23:00:07.0]
231236
232237
"""
233-
def to_naive(%DateTime{year: year, month: month, day: day, calendar: calendar,
238+
@spec to_naive(t) :: NaiveDateTime.t
239+
def to_naive(%DateTime{calendar: calendar, year: year, month: month, day: day,
234240
hour: hour, minute: minute, second: second, microsecond: microsecond}) do
235241
%NaiveDateTime{year: year, month: month, day: day, calendar: calendar,
236242
hour: hour, minute: minute, second: second, microsecond: microsecond}
@@ -251,6 +257,7 @@ defmodule DateTime do
251257
~D[2000-02-29]
252258
253259
"""
260+
@spec to_date(t) :: Date.t
254261
def to_date(%DateTime{year: year, month: month, day: day, calendar: calendar}) do
255262
%Date{year: year, month: month, day: day, calendar: calendar}
256263
end
@@ -270,6 +277,7 @@ defmodule DateTime do
270277
~T[23:00:07.0]
271278
272279
"""
280+
@spec to_time(t) :: Time.t
273281
def to_time(%DateTime{hour: hour, minute: minute, second: second, microsecond: microsecond, calendar: calendar}) do
274282
%Time{hour: hour, minute: minute, second: second, microsecond: microsecond, calendar: calendar}
275283
end
@@ -429,7 +437,7 @@ defmodule DateTime do
429437
end
430438

431439
@doc """
432-
Converts the given datetime to a string according to its calendar.
440+
Converts the given `datetime` to a string according to its calendar.
433441
434442
### Examples
435443
@@ -485,7 +493,7 @@ defmodule DateTime do
485493
end
486494

487495
@doc """
488-
Compares two `DateTime` structs.
496+
Compares two datetime structs.
489497
490498
Returns `:gt` if first datetime is later than the second
491499
and `:lt` for vice versa. If the two datetimes are equal
@@ -506,7 +514,7 @@ defmodule DateTime do
506514
:gt
507515
508516
"""
509-
@spec compare(DateTime.t, DateTime.t) :: :lt | :eq | :gt
517+
@spec compare(Calendar.datetime, Calendar.datetime) :: :lt | :eq | :gt
510518
def compare(%DateTime{utc_offset: utc_offset1, std_offset: std_offset1} = datetime1,
511519
%DateTime{utc_offset: utc_offset2, std_offset: std_offset2} = datetime2) do
512520
{days1, {parts1, ppd1}} =
@@ -552,9 +560,9 @@ defmodule DateTime do
552560
-18000
553561
554562
"""
555-
@spec diff(DateTime.t, DateTime.t) :: integer()
556-
def diff(%DateTime{utc_offset: utc_offset1, std_offset: std_offset1} = datetime1,
557-
%DateTime{utc_offset: utc_offset2, std_offset: std_offset2} = datetime2, unit \\ :second) do
563+
@spec diff(Calendar.datetime, Calendar.datetime) :: integer()
564+
def diff(%{utc_offset: utc_offset1, std_offset: std_offset1} = datetime1,
565+
%{utc_offset: utc_offset2, std_offset: std_offset2} = datetime2, unit \\ :second) do
558566
naive_diff =
559567
(datetime1 |> to_rata_die() |> Calendar.ISO.rata_die_to_unit(unit)) -
560568
(datetime2 |> to_rata_die() |> Calendar.ISO.rata_die_to_unit(unit))
@@ -585,8 +593,12 @@ defmodule DateTime do
585593
586594
"""
587595
@spec convert(Calendar.datetime, Calendar.calendar) :: {:ok, t} | {:error, :incompatible_calendars}
588-
def convert(%DateTime{calendar: calendar} = datetime, calendar) do
589-
{:ok, datetime}
596+
def convert(%{calendar: calendar, year: year, month: month, day: day,
597+
hour: hour, minute: minute, second: second, microsecond: microsecond,
598+
time_zone: time_zone, zone_abbr: zone_abbr, utc_offset: utc_offset, std_offset: std_offset}, calendar) do
599+
{:ok, %DateTime{calendar: calendar, year: year, month: month, day: day,
600+
hour: hour, minute: minute, second: second, microsecond: microsecond,
601+
time_zone: time_zone, zone_abbr: zone_abbr, utc_offset: utc_offset, std_offset: std_offset}}
590602
end
591603

592604
def convert(%{calendar: dt_calendar, microsecond: {_, precision}} = datetime, calendar) do

0 commit comments

Comments
 (0)