繁体   English   中英

Elixir中2个DateTime(小时)之间的差异

[英]Difference between 2 DateTime in hours in Elixir

我的目标是找到从现在到一些提供的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.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)

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

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

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

你可以在这里找到diff / 3文档。

在这里完全忽略时区(要做到这一点,将所有内容转换为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).

(当然,以上内容可以在一条线上组成 - 但你为什么要这样做呢?

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

请记住: 在边缘情况下,时间计算是棘手的,微妙的,很难做到 大多数语言的标准库实际上得到了相当多的TZ和时间差异问题 - 如果你的情况可以,那就不用担心了。 在任何情况下,我建议至少在标准文档的Erlang页面中略读时间和时间校正 - 即使它不适用于您当前的情况,最终您可能会遇到细微的时序问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM