如何在Elm中获取当前时间?

21

几个工作示例:http://stackoverflow.com/a/35120279/480608(使用 Elm v0.16.0)。 - Raine Revere
可能是如何在Elm 0.17/0.18中获取当前时间?的重复问题。 - clozach
8个回答

19
0.19更新:使用标准库无法获取当前时间。您需要使用elm/time。与0.18一样,您只需要一个命令和消息处理结果
type Msg
    = OnTime Time.Posix 

getTime : Cmd Msg
getTime = 
    Task.perform OnTime Time.now 

0.18版本更新。这变得更简单了。现在所有你需要的是一个命令和一条消息来处理结果。

type Msg
    = OnTime Time 

getTime : Cmd Msg
getTime = 
    Task.perform OnTime Time.now 

查看此Ellie

使用0.17版本,现在变得更加简单了。 Time库中现已有一个任务。因此,例如,我们现在拥有:

Time.now
|> Task.Perform NoOp CurrentTime

1
为了每个人的利益,我已经在这里(0.17版本)重新提出了问题,链接为https://dev59.com/_VoT5IYBdhLWcg3w6i23。从我的观点看来,像你展示的那样获得时间很容易。但是要获取任意消息发生的时间则更加困难(几乎不可能)。许多应用程序都有这种簿记要求,需要维护“created_at”或“updated_at”值。 - Mark Bolusmjak
{ 类型 =“leaf”,主页=“任务”,价值=执行<任务>} :平台。命令。Cmd Repl.Msg如何获取实际的“时间”? - user2167582
请查看链接到的Ellie。 - Simon H
FYI,在 Elm 0.19 中,Time.now 已被移至单独的包elm/time中。 - glennsl
1
谢谢,不过我必须说这甚至一点都不容易,更别提变得更容易了。 - Daniel
时间和随机数在纯语言中总是很难处理 :-) - Simon H

11
你可以使用时间包(Time package)和/或者日期包(Date package)。 下面是一个使用两个包的人为示例:
import Signal
import Time exposing (every, second)
import Date exposing (year, hour, minute, second, fromTime)
import Graphics.Element exposing (show)

main =
  Signal.map currentTime (Time.every Time.second)

currentTime t =
  let date' = fromTime t
      hour' = toString (Date.hour date')
      minute' = toString (Date.minute date')
      second' = toString (Date.second date')
      year' = toString (year date')
      now = "The current time is: " ++ hour' ++ ":" ++ minute' ++ ":" ++ second'
  in 
      show now

1
很遗憾,这并没有回答我的问题,我的问题很简单:“如何在 Elm 中获取当前时间”。这个回答的是另一个问题:“如何按照时间频率执行任务,并将时间传递给它”。这种方法能否被改进以解决“调用一个函数并返回当前系统时间”的情况? - Tom Kludy
1
@TomKludy 我认为你所请求的是不可能的,因为该函数必然是不纯的。根据 @Apanatshka 的观点,您可以使用 Task 并传递回调,该回调将在系统调用后接收时间,或者使用 TaskMailbox,这将导致值在可用后发送回您的程序。请参见链接链接以了解有关链接任务和与邮箱通信的信息。 - pdoherty926
10
我认为这是那些会让从业者迅速放弃使用函数式语言的具体问题之一。你正在编写解码器来解析传入的消息,但是如果消息本身没有时间戳,你就没有优雅的方式添加时间戳。这有点像智能手机,只有在将某人添加为联系人后才能给她打电话... - Gabor
3
任何编写过覆盖getSystemTime()调用的代码单元测试的人都可以证明,测试在给定相同参数时执行不同操作的代码是很困难的。采用函数式方法进行单元测试实际上变得令人愉悦!实践者应该喜欢这种方法。好吧,你可以使用依赖注入或猴子补丁,但我们知道这些解决方案不是很令人满意。 - Martin Capodici
@MartinCapodici,你能解释一下为什么获取随机数很容易,但获取当前时间却不是吗? :P编辑:我撤回了这句话。只是因为有关如何生成随机数的文档,但没有关于如何获取当前时间的文档。 - Daniel

8
为了解决自己的问题,我创建了一个包含每个操作时间戳的StartApp变体。
因此,更新函数具有以下签名:
update : action -> Time -> model -> (model, Effects action)
Gist在这里。 https://gist.github.com/z5h/41ca436679591b6c3e51

确实是一个很好的方法。我曾考虑过使用模型中的特殊值来表示时间,但这种方法在最抽象的层面上运作,不需要了解你的应用程序或模型。它非常优雅。 - Martin Capodici

8

Elm 0.19

下面的代码将初始时间设置为Unix时间戳起点Time.millisToPosix 0,但你可以将其设置为Nothing,然后再将其设置为Just time或用Flag传递它。

module Main exposing (main)

import Browser
import Html exposing (Html)
import Task
import Time exposing (Posix)


main : Program () Model Msg
main =
    Browser.element
        { init = \_ -> init
        , view = view
        , update = update
        , subscriptions = \_ -> Sub.none
        }



-- MODEL


type alias Model =
    { zone : Time.Zone
    , now : Posix
    }


init : ( Model, Cmd Msg )
init =
    ( Model Time.utc (Time.millisToPosix 0), Task.perform Zone Time.here )



-- UPDATE


type Msg
    = Zone Time.Zone
    | Now Posix


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Zone zone ->
            ( { model | zone = zone }, Task.perform Now Time.now )

        Now now ->
            ( { model | now = now }, Cmd.none )



-- VIEW


formatTime zone posix =
    (String.padLeft 2 '0' <| String.fromInt <| Time.toHour zone posix)
        ++ ":"
        ++ (String.padLeft 2 '0' <| String.fromInt <| Time.toMinute zone posix)
        ++ ":"
        ++ (String.padLeft 2 '0' <| String.fromInt <| Time.toSecond zone posix)


view : Model -> Html Msg
view model =
    Html.div []
        [ Html.text <| formatTime model.zone model.now
        ]

5
如果您想要程序开始时的时间,可以按照以下方式操作: Now.elm
module Now where

import Native.Now

loadTime : Float
loadTime = Native.Now.loadTime

Native/Now.js

Elm.Native.Now = {};

Elm.Native.Now.make = function(localRuntime) {

  localRuntime.Native = localRuntime.Native || {};


  localRuntime.Native.Now = localRuntime.Native.Now || {};

  if (localRuntime.Native.Now.values) {
    return localRuntime.Native.Now.values;
  }

  var Result = Elm.Result.make(localRuntime);

  return localRuntime.Native.Now.values = {
    loadTime: (new window.Date).getTime()
  };

};

你的代码

programStart = Now.loadTime

我解决了我的问题,感谢!关键是在我的elm-package.json文件中包括以下内容:"native-modules": true - Tom Kludy

4
你可以参考 pdoherty926的答案 来使用 Elm 处理当前时间。 elm-repl 不能处理 Signal,而时间会随着时间的推移而改变,因此它是一个信号。 目前我不知道有没有获取时间的 Task。也没有一种在 repl 中执行任务的方法,尽管我希望这将成为未来的特性。

1
我能想到两种主要方法来处理 Elm 中的当前时间:
  1. 编写/使用本地模块来创建一个返回毫秒级当前时间(或返回执行相同操作的任务)的函数。这种方法通常不建议使用。我认为第二种方法更好。但是可以在此处找到#1的示例:https://github.com/evancz/task-tutorial/blob/1.0.2/src/TaskTutorial.elm(请参见 getCurrentTime 函数)。
  2. 使用 Elm 应用程序架构(https://github.com/evancz/elm-architecture-tutorial/)编写程序,然后将当前时间信号作为输入提供给更新周期,在您选择的每个间隔中使用新的当前时间更新模型。然后,您的所有其他方法都可以从模型中同步获取当前时间。

1
在第二个想法上进行扩展,我认为这是最好的:type Action = Tick Time | ... 并在更新中使用:Tick time -> {model | time = time} - mgold

0

Simon H的答案(0.18)让我朝着正确的方向开始了,但是我确实遇到了一些麻烦,不知道如何实际操作这个时间。(user2167582在评论中问了同样的问题:如何“取出时间”?)。

我的具体问题是,我想在POST请求的正文中包含当前时间。

最终我解决了这个问题,并对结果感到非常满意——使用Task.andThen意味着在我的postTime函数中,我可以将timestamp作为“常规”的浮点值参数使用(当任务运行时,我想它就是这样)。

我的完整SO答案在这里

下面是我想出的解决方案,在Ellie中的演示

module Main exposing (..)

import Html exposing (..)
import Html.Events exposing (..)
import Http
import Json.Decode as JD
import Json.Encode as JE
import Task
import Time


type alias Model =
    { url : String
    }


type Msg
    = PostTimeToServer
    | PostDone (Result Http.Error String)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        PostTimeToServer ->
            ( model, postTimeToServer model.url )

        PostDone _ ->
            ( model, Cmd.none )


view : Model -> Html Msg
view model =
    div []
        [ div []
            [ button [ onClick PostTimeToServer ] [ Html.text "POST the current time." ]
            ]
        ]


postTimeToServer : String -> Cmd Msg
postTimeToServer url =
    let
        getTime =
            Time.now

        postTime t =
            JD.string
                |> Http.post url (JE.float t |> Http.jsonBody)
                |> Http.toTask

        request =
            getTime                                            <<-- Here is
                |> Task.andThen postTime                       <<-- the key bit.
    in
        Task.attempt PostDone request


main =
    Html.program
        { init = ( Model "url_here", Cmd.none )
        , update = update
        , view = view
        , subscriptions = always Sub.none
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接