[elixir! #0048] 好玩的時間戳數據格式

逝者如斯夫, 不捨晝夜.

時間戳的處理恐怕是咱們平常編程中常常要面對的問題, 尤爲是涉及到國際服務的時候, 如何存儲正確的時間, 就特別重要.編程

通常咱們使用 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

clipboard.png

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 模塊的代碼.

相關文章
相關標籤/搜索