Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable dateField to put a timestamp with a local time zone #458

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions hakyll.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ Library
tagsoup >= 0.13.1 && < 0.15,
text >= 0.11 && < 1.3,
time >= 1.4 && < 1.7,
timerep >= 2.0 && < 2.1,
time-locale-compat >= 0.1 && < 0.2,
unordered-containers >= 0.2 && < 0.3,
vector >= 0.11 && < 0.12,
Expand Down Expand Up @@ -265,6 +266,7 @@ Test-suite hakyll-tests
tagsoup >= 0.13.1 && < 0.15,
text >= 0.11 && < 1.3,
time >= 1.4 && < 1.7,
timerep >= 2.0 && < 2.1,
time-locale-compat >= 0.1 && < 0.2,
unordered-containers >= 0.2 && < 0.3,
vector >= 0.11 && < 0.12,
Expand Down
31 changes: 24 additions & 7 deletions src/Hakyll/Web/Feed.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,17 @@
module Hakyll.Web.Feed
( FeedConfiguration (..)
, renderRss
, renderRssWith
, renderAtom
, renderAtomWith
) where


--------------------------------------------------------------------------------
import Control.Monad ((<=<))
import Data.Time.Format (TimeLocale (..), defaultTimeLocale)


--------------------------------------------------------------------------------
import Hakyll.Core.Compiler
import Hakyll.Core.Compiler.Internal
Expand Down Expand Up @@ -106,9 +113,14 @@ renderRss :: FeedConfiguration -- ^ Feed configuration
-> Context String -- ^ Item context
-> [Item String] -- ^ Feed items
-> Compiler (Item String) -- ^ Resulting feed
renderRss config context = renderFeed
renderRss = renderRssWith defaultTimeLocale

-- | This is an extended version of 'renderRss' that allows you to
-- specify a time locale that is used for parsing the date.
renderRssWith :: TimeLocale -> FeedConfiguration -> Context String -> [Item String] -> Compiler (Item String)
renderRssWith locale config context = renderFeed
"templates/rss.xml" "templates/rss-item.xml" config
(makeItemContext "%a, %d %b %Y %H:%M:%S UT" context)
(makeItemContext locale RFC822 context)


--------------------------------------------------------------------------------
Expand All @@ -117,13 +129,18 @@ renderAtom :: FeedConfiguration -- ^ Feed configuration
-> Context String -- ^ Item context
-> [Item String] -- ^ Feed items
-> Compiler (Item String) -- ^ Resulting feed
renderAtom config context = renderFeed
renderAtom = renderAtomWith defaultTimeLocale

-- | This is an extended version of 'renderAtom' that allows you to
-- specify a time locale that is used for parsing the date.
renderAtomWith :: TimeLocale -> FeedConfiguration -> Context String -> [Item String] -> Compiler (Item String)
renderAtomWith locale config context = renderFeed
"templates/atom.xml" "templates/atom-item.xml" config
(makeItemContext "%Y-%m-%dT%H:%M:%SZ" context)
(makeItemContext locale RFC3339 context)


--------------------------------------------------------------------------------
-- | Copies @$updated$@ from @$published$@ if it is not already set.
makeItemContext :: String -> Context a -> Context a
makeItemContext fmt context = mconcat
[dateField "published" fmt, context, dateField "updated" fmt]
makeItemContext :: TimeLocale -> DateFormat -> Context a -> Context a
makeItemContext locale fmt context = mconcat
[dateFieldWith locale "published" fmt, context, dateFieldWith locale "updated" fmt]
45 changes: 37 additions & 8 deletions src/Hakyll/Web/Template/Context.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
module Hakyll.Web.Template.Context
( ContextField (..)
, Context (..)
, DateFormat (..)
, field
, boolField
, constField
Expand All @@ -22,6 +23,7 @@ module Hakyll.Web.Template.Context
, dateField
, dateFieldWith
, getItemUTC
, getItemTime
, getItemModificationTime
, modificationTimeField
, modificationTimeFieldWith
Expand All @@ -36,9 +38,13 @@ import Control.Applicative (Alternative (..))
import Control.Monad (msum)
import Data.List (intercalate)
import Data.Time.Clock (UTCTime (..))
import Data.Time.Format (formatTime)
import Data.Time.Format (ParseTime, formatTime)
import qualified Data.Time.Format as TF
import Data.Time.LocalTime (ZonedTime (..))
import Data.Time.Locale.Compat (TimeLocale, defaultTimeLocale)
import Data.Time.RFC822 (formatTimeRFC822)
import Data.Time.RFC3339 (formatTimeRFC3339)
import GHC.Exts (IsString, fromString)
import Hakyll.Core.Compiler
import Hakyll.Core.Compiler.Internal
import Hakyll.Core.Identifier
Expand All @@ -56,6 +62,16 @@ data ContextField
= StringField String
| forall a. ListField (Context a) [Item a]

--------------------------------------------------------------------------------
-- | Date format: RFC822 for RSS, RFC3339 for Atom, or custom format string
data DateFormat
= RFC822
| RFC3339
| DateFormat String

instance IsString DateFormat where
fromString = DateFormat


--------------------------------------------------------------------------------
-- | The 'Context' monoid. Please note that the order in which you
Expand Down Expand Up @@ -239,6 +255,8 @@ titleField = mapContext takeBaseName . pathField
--
-- * @2010-09-06 00:01:00+0000@
--
-- * @2010-09-06 00:01:00 +0000@
--
-- * @2010-09-06 00:01:00@
--
-- * @September 06, 2010 00:01 AM@
Expand All @@ -259,7 +277,7 @@ titleField = mapContext takeBaseName . pathField
-- In case of multiple matches, the rightmost one is used.

dateField :: String -- ^ Key in which the rendered date should be placed
-> String -- ^ Format to use on the date
-> DateFormat -- ^ Format to use on the date
-> Context a -- ^ Resulting context
dateField = dateFieldWith defaultTimeLocale

Expand All @@ -270,11 +288,14 @@ dateField = dateFieldWith defaultTimeLocale
-- details, see 'dateField'.
dateFieldWith :: TimeLocale -- ^ Output time locale
-> String -- ^ Destination key
-> String -- ^ Format to use on the date
-> DateFormat -- ^ Format to use on the date
-> Context a -- ^ Resulting context
dateFieldWith locale key format = field key $ \i -> do
time <- getItemUTC locale $ itemIdentifier i
return $ formatTime locale format time
time <- getItemTime locale $ itemIdentifier i :: Compiler ZonedTime
return $ case format of
RFC822 -> formatTimeRFC822 time
RFC3339 -> formatTimeRFC3339 time
DateFormat str -> formatTime locale str time


--------------------------------------------------------------------------------
Expand All @@ -285,7 +306,14 @@ getItemUTC :: MonadMetadata m
=> TimeLocale -- ^ Output time locale
-> Identifier -- ^ Input page
-> m UTCTime -- ^ Parsed UTCTime
getItemUTC locale id' = do
getItemUTC = getItemTime

-- | General version of `getItemUTC` that returns an instance of `ParseTime`
getItemTime :: (MonadMetadata m, ParseTime t)
=> TimeLocale -- ^ Output time locale
-> Identifier -- ^ Input page
-> m t -- ^ Parsed time
getItemTime locale id' = do
metadata <- getMetadata id'
let tryField k fmt = lookupString k metadata >>= parseTime' fmt
paths = splitDirectories $ toFilePath id'
Expand All @@ -295,13 +323,14 @@ getItemUTC locale id' = do
[tryField "date" fmt | fmt <- formats] ++
[parseTime' "%Y-%m-%d" $ intercalate "-" $ take 3 $ splitAll "-" fnCand | fnCand <- reverse paths]
where
empty' = fail $ "Hakyll.Web.Template.Context.getItemUTC: " ++
empty' = fail $ "Hakyll.Web.Template.Context.getItemTime: " ++
"could not parse time for " ++ show id'
parseTime' = parseTimeM True locale
formats =
[ "%a, %d %b %Y %H:%M:%S %Z"
, "%Y-%m-%dT%H:%M:%S%Z"
, "%Y-%m-%d %H:%M:%S%Z"
, "%Y-%m-%d %H:%M:%S %Z"
, "%Y-%m-%d"
, "%B %e, %Y %l:%M %p"
, "%B %e, %Y"
Expand Down Expand Up @@ -371,7 +400,7 @@ missingField = Context $ \k _ i -> fail $
"Missing field $" ++ k ++ "$ in context for item " ++
show (itemIdentifier i)

parseTimeM :: Bool -> TimeLocale -> String -> String -> Maybe UTCTime
parseTimeM :: ParseTime t => Bool -> TimeLocale -> String -> String -> Maybe t
#if MIN_VERSION_time(1,5,0)
parseTimeM = TF.parseTimeM
#else
Expand Down
8 changes: 8 additions & 0 deletions tests/Hakyll/Web/Template/Context/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Test.HUnit (Assertion, (@=?))


--------------------------------------------------------------------------------
import Data.Time.Format (TimeLocale (..), defaultTimeLocale)
import Data.Time.LocalTime (TimeZone (..))
import Hakyll.Core.Compiler
import Hakyll.Core.Identifier
import Hakyll.Core.Provider
Expand Down Expand Up @@ -42,6 +44,12 @@ testDateField = do
dateField "date" "%B %e, %Y"
date2 @=? "August 26, 2010"

let jst = defaultTimeLocale { knownTimeZones = [TimeZone (9 * 60) False "JST"] }
date3 <- testContextDone store provider
"posts/2016-08-02-localtime.md" "date" $
dateFieldWith jst "date" "%Y-%m-%d %H:%M:%S %z"
"2016-08-02 23:01:03 +0900" @=? date3

cleanTestEnv


Expand Down
3 changes: 3 additions & 0 deletions tests/data/posts/2016-08-02-localtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
published: 2016-08-02 23:01:03 JST
---