Packages
timber
1.1.11
3.1.2
3.1.1
3.1.0
3.0.0
3.0.0-alpha.3
3.0.0-alpha.2
3.0.0-alpha.1
2.8.4
2.8.3
2.8.2
2.8.1
2.8.0
2.7.0
2.6.1
2.6.0
2.5.6
2.5.5
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.4.5
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.4
2.3.3
2.3.1
2.3.0
2.2.1
2.2.0
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.2
2.0.1
2.0.0
2.0.0-rc7
2.0.0-rc6
2.0.0-rc5
2.0.0-rc4
2.0.0-rc3
2.0.0-rc2
2.0.0-rc1
1.1.18
1.1.17
1.1.16
1.1.15
1.1.14
1.1.13
1.1.12
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
🌲 Great Elixir Logging Made Easy. Official Timber.io Integration.
Current section
Files
Jump to
Current section
Files
lib/timber/utils/timestamp.ex
defmodule Timber.Utils.Timestamp do
@moduledoc false
alias Timber.LoggerBackend
@doc """
Returns the current date and time in UTC including fractional portions of a second
"""
@spec now() :: LoggerBackend.timestamp
def now() do
now = DateTime.utc_now()
date = {now.year, now.month, now.day}
time = {now.hour, now.minute, now.second, now.microsecond}
{date, time}
end
@doc """
Formats a timestamp to the format `YYYY-MM-DDTHH:MM:SS.SSSSSSZ` as chardata
The precision of the fractional seconds is variable. BEAM only provides
precision timekeeping to the microsecond, which is equivalent to 1000 nanoseconds.
However, the Elixir `Logger` library defaults to millisecond precision
(1000 microseconds or 1,000,000 nanoseconds). When formatting the time
given by the Elixir `Logger` library, the fractional seconds are represented
to three decimal places. When formatting the time as microseconds, the
fractional seconds are represented to six decimal places.
In some cases, the time keeping library may indicate that the microseconds
have no precision. In this case, the fractional seconds will be left off
entirely, resulting in the following format: `YYYY-MM-DDTHH:MM:SSZ`.
"""
@spec format_timestamp(LoggerBackend.timestamp) :: IO.chardata
# If the precision for timekeeping of fractional seconds is 0, drop
# the fractional portion
def format_timestamp({date, {_, _, _, {_microseconds, 0}} = time}) do
date = format_date(date)
time = format_time(time)
[date | [?T | [time | [?Z]]]]
end
# Formatting a timestamp with microseconds
def format_timestamp({date, {_, _, _, {microseconds, _precision}} = time}) do
date = format_date(date)
time = format_time(time)
partial_seconds = pad6(microseconds)
[date | [?T | [time | [?. | [partial_seconds | [?Z]]]]]]
end
# Formatting a timestamp with milliseconds
def format_timestamp({date, {_, _, _, milliseconds} = time}) do
date = format_date(date)
time = format_time(time)
milliseconds = pad3(milliseconds)
[date | [?T | [time | [?. | [milliseconds | [?Z]]]]]]
end
# Common functionality for formatting a date as YYYY-MM-DD
@spec format_date(LoggerBackend.date) :: IO.chardata
defp format_date({year, month, day}) do
[Integer.to_string(year), ?-, pad2(month), ?-, pad2(day)]
end
# Common functionality for formatting time as HH:MM:SS
@spec format_time(LoggerBackend.time) :: IO.chardata
defp format_time({hours, minutes, seconds, _}) do
[pad2(hours), ?:, pad2(minutes), ?:, pad2(seconds)]
end
# These padding functions are based on the original functions in
# the Elixir `Logger` application. They each return the given
# integer as chardata padded to a certain number of positions.
#
# For example, `pad2(1)` will yield `"01"` (encoded as a binary)
# and `pad2(12)` will yield `"12"`. Likewise, `pad6(1)` will yield
# `"000001"`.
@spec pad2(integer) :: IO.chardata
defp pad2(int) when int < 10, do: [?0, Integer.to_string(int)]
defp pad2(int), do: Integer.to_string(int)
@spec pad3(integer) :: IO.chardata
defp pad3(int) when int < 10, do: [?0, ?0, Integer.to_string(int)]
defp pad3(int) when int < 100, do: [?0, Integer.to_string(int)]
defp pad3(int), do: Integer.to_string(int)
@spec pad6(integer) :: IO.chardata
defp pad6(int) when int < 10, do: [?0, ?0, ?0, ?0, ?0, Integer.to_string(int)]
defp pad6(int) when int < 100, do: [?0, ?0, ?0, ?0, Integer.to_string(int)]
defp pad6(int) when int < 1000, do: [?0, ?0, ?0, Integer.to_string(int)]
defp pad6(int) when int < 10000, do: [?0, ?0, Integer.to_string(int)]
defp pad6(int) when int < 100000, do: [?0, Integer.to_string(int)]
defp pad6(int), do: Integer.to_string(int)
end