【问题标题】:Difference between 2 DateTime in hours in ElixirElixir中2个日期时间之间的差异
【发布时间】:2018-04-04 18:59:37
【问题描述】:

我的目标是找出现在与某些提供的 date_time 之间的小时数差异。我正在尝试这样做:

pry(1)> dt1
#DateTime<2017-10-24 05:12:46.000000Z>

pry(2)> Ecto.DateTime.to_erl(dt1)
** (FunctionClauseError) no function clause matching in Ecto.DateTime.to_erl/1    

    The following arguments were given to Ecto.DateTime.to_erl/1:

        # 1
        #DateTime<2017-10-24 05:12:46.000000Z>

    Attempted function clauses (showing 1 out of 1):

        def to_erl(%Ecto.DateTime{year: year, month: month, day: day, hour: hour, min: min, sec: sec})

    (ecto) lib/ecto/date_time.ex:608: Ecto.DateTime.to_erl/1
    # ............

如何解决这个问题? 或者有没有更好的方法来实现我的目标?

注意,我不使用 timex,也不会使用它,也不会使用任何第三方库。只有 Elixir/Erlang/Phoenix 内置的。

【问题讨论】:

    标签: datetime elixir


    【解决方案1】:

    在主题作者编辑他的问题并从范围中排除外部库之前添加了此答案。但是,我不会删除它,因为我发现 Timex 非常有用,也许有人也会有兴趣使用它(我与 Timex 的创建者无关)

    我强烈推荐使用Timex 库。它非常适合具有不同格式和时区的日期/时间计算。 因此,在您的情况下,要轻松计算时差,您只需要:

    Timex.diff(dt1, DateTime.utc_now, :hours)
    

    您可以找到 diff/3 文档here

    【讨论】:

      【解决方案2】:

      在这里完全忽略时区(最简单的方法是将所有内容转换为 UTC,然后转换为本地的),纯粹的 Erlang 方法是按照这些思路做一些事情。

      1> Event = {{2017,05,23},{13,11,23}}.
      {{2017,5,23},{13,11,23}}
      2> Now = calendar:local_time().
      {{2017,10,24},{14,44,1}}
      3> EventGSec = calendar:datetime_to_gregorian_seconds(Event).
      63662764283
      4> NowGSec = calendar:datetime_to_gregorian_seconds(Now).
      63676075441
      5> Elapsed = NowGSec - EventGSec.
      13311158     
      6> calendar:seconds_to_daystime(Elapsed).
      {154,{1,32,38}}
      

      当然,确切的解决方案取决于您需要的分辨率。将其提取到一个返回 {Days, {Hours, Minutes, Seconds}} 形式的元组的函数中可以得到:

      -spec elapsed_time(calendar:datetime()) -> {Days, Time}
          when Days :: non_neg_integer(),
               Time :: calendar:time().
      
      elapsed_time(Event) ->
          Now = calendar:local_time(),
          EventGSec = calendar:datetime_to_gregorian_seconds(Event),
          NowGSec = calendar:datetime_to_gregorian_seconds(Now),
          Elapsed = NowGSec - EventGSec,
          calendar:seconds_to_daystime(Elapsed).
      

      (当然,上面的内容可以写成一行——但是why would you ever do that?

      我确信有一些 wazoo Elixir 库以完全不同的方式做事。玩得开心。该答案仅针对底层本机库。 Erlang 标准库中的大多数时间函数现在都基于基于整数的时间单位(秒、毫秒或纳秒),而不是旧的 erlang:now() 时间戳形式(现已弃用)。您应该编写上述函数版本的确切方式取决于您需要什么样的分辨率和原始输入的格式(例如,对于我自己处理的时间戳类型,Unix 时代的纳秒是很常见的——但是不适用于日期时间数据类型)。

      请记住:时间计算非常棘手、微妙且难以在极端情况下正确处理。大多数语言的标准库实际上有很多 TZ 和时间差异问题是错误的——如果这对你的情况没问题,那么就不用担心了。无论如何,我建议至少浏览一下标准文档的 Time and Time Correction in Erlang 页面——即使它不适用于您当前的情况,最终您可能会遇到微妙的时间问题很重要的情况。

      【讨论】:

        【解决方案3】:

        你可以使用DateTime.diff/3:

        iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT",
        ...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},
        ...>                 utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"}
        iex> dt2 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET",
        ...>                 hour: 23, minute: 0, second: 7, microsecond: {0, 0},
        ...>                 utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"}
        iex> DateTime.diff(dt1, dt2)
        18000
        iex> DateTime.diff(dt2, dt1)
        -18000
        

        由于DateTime.diff/3 返回秒数,因此您必须从结果中计算小时数,如下所示:

        result_in_hours = result_in_seconds/(60*60)
        

        【讨论】:

        • 你现在可以做DateTime.diff(dt1, dt2, :hours)
        猜你喜欢
        • 2012-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-20
        • 2010-09-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多