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