问题
I am using Yesod on my first site and I have a list of news items:
NewsItem
date UTCTime default=CURRENT_TIME
title String
content String
author String
which are retrieved in my handler:
newsitems <- runDB $ selectList [] [Desc NewsItemDate]
and ultimately used in my template:
$if null newsitems
<p>No news.
$else
$forall Entity id entry <- newsitems
<article>
<h4>#{newsItemDate entry}
<p>#{newsItemContent entry}
But I get an error about datatypes:
Handler/Home.hs:20:11:
No instance for (Text.Blaze.ToMarkup
time-1.4:Data.Time.Clock.UTC.UTCTime)
arising from a use of `toHtml'
Possible fix:
add an instance declaration for
(Text.Blaze.ToMarkup time-1.4:Data.Time.Clock.UTC.UTCTime)
In the first argument of `toWidget', namely
`toHtml (newsItemDate entry_a6ev)'
In a stmt of a 'do' block:
toWidget (toHtml (newsItemDate entry_a6ev))
In the expression:
do { toWidget
((Text.Blaze.Internal.preEscapedText . Data.Text.pack)
"<article><h4>");
toWidget (toHtml (newsItemDate entry_a6ev));
toWidget
((Text.Blaze.Internal.preEscapedText . Data.Text.pack)
"</h4>\
\<p>");
toWidget (toHtml (newsItemContent entry_a6ev));
.... }
So I figure I would go ahead and add to my Import.hs:
import Data.Time (UTCTime)
import Data.Time.Format (formatTime)
import Text.Blaze (ToMarkup, toMarkup)
import Text.Blaze.Internal (string)
import System.Locale (defaultTimeLocale)
-- format date as 26 July 2012
instance ToMarkup UTCTime where
toMarkup a = string (formatTime defaultTimeLocale "%e %B %Y" a)
Which does compile, but gives me an error at runtime in the browser:
Internal Server Error
PersistMarshalError "Expected UTCTime, received PersistText \"2012-08-30\""
So I am not sure how to solve this, any ideas?
EDIT: Source code to the site in case it is needed or curious: https://github.com/iaefai/socrsite
回答1:
Without investigating the actual error, I think your approach is not great. You will very likely eventually want several ways of formatting a UTCTime
, after all, the type is there to store times, not just dates. By giving a ToMarkup UTCTime
instance, you fix this globally.
I would recommend to write functions renderAsDate :: UTCDate -> HTML
, renderAsTime :: UTCDate -> HTML
etc. and use them in your template, e.g. #{renderAsDate (newsItemDate entry)}
.
But this won’t solve the runtime error, which comes from the serialization layer and is likely independent of your templates.
回答2:
I'm pretty sure you could just use show in the hamlet? That's atleast what I've done...
#{show $ newsItemDate entry}
I've run into this instance thing before, and as this guy describes here it's something like this:
As part of this philosophy of frugality of expression Haskell doesn’t require type signatures — although an experienced Haskeller provides them for clarity — so type errors in this strongly typed language are often cryptic for the uninitiated. For instance, if you define a function f that adds two numbers and then call it with two strings, the compiler will not complain about bad arguments, it will complain about string not supporting operator plus. And it will formulate this complaint in a very non-obvious way. [1] Under "1. Haskell is Terse"...
[1] http://fpcomplete.com/ten-things-you-should-know-about-haskell-syntax/
来源:https://stackoverflow.com/questions/12275273/using-utctime-with-hamlet