Sam Houston
Sam Houston

Reputation: 3651

Combine date and time to a datetime

How can I convert a Date and a Time to a DateTime?

Say I have the following date and time

iex> date = ~D[2018-01-01]
iex> time = ~T[00:00:01.000]

How can I combine these to output the datetime: #DateTime<2018-01-01 00:00:01Z> in a clean way?

The best I come up with is using the Timex library:

Timex.add(Timex.to_datetime(date), Timex.Duration.from_time(time))

but I feel that surely there is a nicer, more readable way to combine this.

Upvotes: 0

Views: 1398

Answers (4)

Kevin Kalb
Kevin Kalb

Reputation: 1

If someone is still wondering and, like me, came from google-search, there is the possibility to create this with DateTime.new/4. This came with elixir v1.11.0, see here.

date = Date.new!(2024, 5, 1)
iex(2)> time = Time.new!(12, 0, 0)
iex(3)> datetime = DateTime.new!(date, time)

~U[2024-05-01 12:00:00Z]

Upvotes: 0

Penguin Brian
Penguin Brian

Reputation: 2131

If you are using the calendar library, you can use either the Calendar.DateTime.from_date_and_time_and_zone function or the Calendar.NaiveDateTime.from_date_and_time function:

iex(4)> Calendar.DateTime.from_date_and_time_and_zone(~D[2018-10-01], ~T[12:22:22], "Australia/Melbourne")
{:ok, #DateTime<2018-10-01 12:22:22+10:00 AEST Australia/Melbourne>}
iex(5)> Calendar.NaiveDateTime.from_date_and_time(~D[2018-10-01], ~T[12:22:22])                           
{:ok, ~N[2018-10-01 12:22:22]}

There are also from_date_and_time! and from_date_and_time! variants.

Upvotes: 3

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 120990

While the answer by @legoscia is perfectly valid, here is how you deal with date and time pair (without Timex, just pure Elixir standard library):

date = ~D[2018-01-01]
time = ~T[00:00:01.000]

{Date.to_erl(date), Time.to_erl(time)}
|> NaiveDateTime.from_erl!()
|> DateTime.from_naive("Etc/UTC")
#⇒ {:ok, #DateTime<2018-01-01 00:00:01Z>}

Upvotes: 3

legoscia
legoscia

Reputation: 41527

You can use NaiveDateTime.new/2:

iex> NaiveDateTime.new(date, time)
{:ok, ~N[2018-01-01 00:00:01.000]}

The reason it is a "naive datetime" instead of a datetime is that the Time struct doesn't contain time zone information. If you know the time zone, you can add that information using DateTime.from_naive/2:

iex> DateTime.from_naive(~N[2018-01-01 00:00:01.000], "Etc/UTC")
{:ok, #DateTime<2018-01-01 00:00:01.000Z>}

Upvotes: 4

Related Questions