Does Anybody Really Know What Time It Is?

Time and Date Handling in Elixir

Hal E. Fulton

Times/dates are a pain

Earth's rotation

Moon's revolution

Earth's revolution

None of these are integral
multiples of each other.

Culture

Language

Law

Business

Government

Religion

Tradition

Leap seconds?  0..59, 0..60, 0..61

Calendar change? England, Italy?

"Proleptic"? C'est what?

Time zones...

So... what's in Elixir?

Calendar

  • This is a behaviour
  • It defines 18 types...
  • 2 functions...
  • and 14 callbacks

Date

Time

NaiveDateTime

DateTime

year, month, day, calendar

hour, minute, second, microsecond, calendar

year, month, day, hour, minute, second, microsecond, calendar

year, month, day, hour, minute, second, microsecond, std_offset, time_zone, utc_offset, zone_abbr, calendar
(only conversion functions and UTC)

Timex

the library that attempts to fix everything

A glance at Timex...

Instantiation...

now()  now(tz)  today()              beginning_of_day(datetime)
beginning_of_month(datetime)         beginning_of_month(year, month)
beginning_of_quarter(datetime)       beginning_of_week(date)
beginning_of_week(date, weekstart)   beginning_of_year(year)
end_of_day(datetime)                 end_of_month(datetime)
end_of_month(year, month)            end_of_quarter(datetime)
end_of_quarter(year, month)          end_of_week(datetime)
end_of_week(datetime, weekstart)     end_of_year(year)   
# Example...
iex(7)> t = Timex.now
#DateTime<2018-02-19 22:16:48.464360Z>
iex(8)> Timex.beginning_of_month(t)
#DateTime<2018-02-01 00:00:00Z>

A glance at Timex...

Comparison...

after?(a, b)    before?(a, b)  
between?(a, start, ending, options \\ [])
compare(a, b)
compare(a, b, granularity)
equal?(a, a, granularity \\ :seconds)
iex(14)> t2 = Timex.now
#DateTime<2018-02-19 22:20:22.474409Z>
iex(15)> Timex.after?(t, t2)
false
iex(16)> Timex.before?(t, t2)
true
iex(17)> t < t2     # Never do this!
true?

A glance at Timex...

Conversion...

from_iso_day(day)
from_iso_day(day, year)
from_iso_triplet(arg)
from_now(datetime)
from_now(datetime, locale)
from_now(datetime, reference_date, locale)
from_unix(secs, unit \\ :seconds)
to_date(date)                        to_datetime(from)
to_datetime(from, timezone)          to_erl(date)
to_gregorian_microseconds(datetime)
to_gregorian_seconds(datetime)       to_julian(datetime)
to_naive_datetime(date)              to_unix(datetime)

A glance at Timex...

Parsing...

parse(datetime_string, format_string)
parse(datetime_string, format_string, tokenizer)
parse!(datetime_string, format_string)
parse!(datetime_string, format_string, tokenizer)

Formatting...

format(datetime, format_string)
format(datetime, format_string, formatter)
format!(datetime, format_string)
format!(datetime, format_string, formatter)
format_duration(timestamp)
format_duration(timestamp, formatter)

A glance at Timex...

Arithmetic...

add(date, duration)
diff(a, b)
diff(a, b, granularity)
subtract(date, duration)

(and other stuff0

Takeaways

It's all about the struct fields. If you think two things are compatible, they probably are.

Remember microseconds is a tuple like {123456, 6}

Never use comparison operators on dates and times.

If you're worried about monotonic time, leap seconds matter. Otherwise, you're probably wasting time to think about them.

Try to stay away from October 1583.

Time zones are a pain, and daylight saving is an abomination.

Times/Dates in Elixir

By hal_9000

Times/Dates in Elixir

  • 414