逝者如斯夫, 不捨晝夜.
時間戳的處理恐怕是咱們平常編程中常常要面對的問題, 尤爲是涉及到國際服務的時候, 如何存儲正確的時間, 就特別重要.編程
通常咱們使用 UTC 時間, 也就是 0 時區的時間做爲標準時間.spa
獲取當前的 UTC 時間戳:翻譯
iex(1)> DateTime.utc_now ~U[2019-05-20 04:50:52.943370Z]
這獲得的是個啥?實際上是一個 struct:code
iex(2)> Map.from_struct v() %{ calendar: Calendar.ISO, day: 20, hour: 4, microsecond: {943370, 6}, minute: 50, month: 5, second: 52, std_offset: 0, time_zone: "Etc/UTC", utc_offset: 0, year: 2019, zone_abbr: "UTC" }
這裏面有 calendar, 翻譯成 曆法 應該沒錯, 搜索了一下, 發現世界上有四十種曆法呢, 真了不得.ip
elixir 標準庫裏默認用的是最經常使用的 ISO 國際標準曆法, 也就是咱們使用的公曆. 能夠看到上面的 DateTime 表示的是 "2019 年 5 月 20 日 4 小時 50 分鐘 52 秒, 時區 'Etc/UTC'". 注意到
microsecond 微秒有些特別, 它的元組的第二位表示精度, 也就是轉換成其它格式的時候必需要顯示幾位數字, 這裏 6 表示要顯示 6 位.rem
Calendar 模塊裏面定義了一系列的 callback, 若是你想實現一個本身的歷法模塊, 就須要實現這些 callbacks.it
咱們看看標準的 Calendar.ISO 是如何實現這些 callbacks 的:class
@spec days_in_month(year, month) :: 28..31 @impl true def days_in_month(year, month) def days_in_month(year, 2) do if leap_year?(year), do: 29, else: 28 end def days_in_month(_, month) when month in [4, 6, 9, 11], do: 30 def days_in_month(_, month) when month in 1..12, do: 31
某年的某月有多少天.cli
@impl true @spec months_in_year(year) :: 12 def months_in_year(_year) do @months_in_year end
某年有多少月.date
@spec leap_year?(year) :: boolean() @impl true def leap_year?(year) when is_integer(year) do rem(year, 4) === 0 and (rem(year, 100) !== 0 or rem(year, 400) === 0) end
某年是不是閏年.
@spec day_of_week(year, month, day) :: 1..7 @impl true def day_of_week(year, month, day) when is_integer(year) and is_integer(month) and is_integer(day) do iso_days_to_day_of_week(date_to_iso_days(year, month, day)) end defp iso_days_to_day_of_week(iso_days) do Integer.mod(iso_days + 5, 7) + 1 end
某年某月某日是星期幾.
@spec day_of_year(year, month, day) :: 1..366 @impl true def day_of_year(year, month, day) when is_integer(year) and is_integer(month) and is_integer(day) do ensure_day_in_month!(year, month, day) days_before_month(month) + leap_day_offset(year, month) + day end
某年某月某日是這年的第幾天.
@spec quarter_of_year(year, month, day) :: 1..4 @impl true def quarter_of_year(year, month, day) when is_integer(year) and is_integer(month) and is_integer(day) do div(month - 1, 3) + 1 end
某年某月某日是這年的第幾季度.
@spec year_of_era(year) :: {year, era :: 0..1} @impl true def year_of_era(year) when is_integer(year) and year > 0 do {year, 1} end def year_of_era(year) when is_integer(year) and year < 1 do {abs(year) + 1, 0} end
某年的紀元(公元后, 公元前)
還有一些這裏這就贅述了, 感興趣的朋友能夠看 elixir Calendar.ISO 模塊的代碼.