Dav*_* V. 8 time haskell epoch
我想将文件的修改时间设置为从exif数据获得的时间.
为了从exif获得时间,我发现:
Graphics.Exif.getTag :: Exif -> String -> IO (Maybe String)
Run Code Online (Sandbox Code Playgroud)
要设置文件修改时间,我发现:
System.Posix.Files.setFileTimes :: FilePath -> EpochTime -> EpochTime -> IO ()
Run Code Online (Sandbox Code Playgroud)
假设我确实在Exif中找到了Time,我需要将String转换为EpochTime.
parseTime
我可以得到一个UTCTime
.utcTimeToPOSIXSeconds
我可以得到一个POSIXTime
POSIXTime
我可以或多或少得到一个EpochTime
从转换UTCTime
到EpochTime
这个typechecks,但我不知道它是正确的:
fromIntegral . fromEnum . utcTimeToPOSIXSeconds $ etime
Run Code Online (Sandbox Code Playgroud)
这是函数getTime的一部分,它将从Exif数据返回时间(如果存在),否则返回文件的修改时间:
getTime (path,stat) = do
let ftime = modificationTime $ stat
err (SomeException _) = return ftime
time <- liftIO $ handle err $ do
exif <- Exif.fromFile path
let getExifTime = MaybeT . liftIO . Exif.getTag exif
res <- runMaybeT $ do
tmp <- msum . map getExifTime $ [ "DateTimeOriginal","DateTimeDigitized", "DateTime" ]
MaybeT . return . parseTime defaultTimeLocale "%Y:%m:%d %H:%M:%S" $ tmp
case res of
Nothing -> return ftime
Just etime -> return . fromIntegral . fromEnum . utcTimeToPOSIXSeconds $ etime
return (path,time)
Run Code Online (Sandbox Code Playgroud)
我的问题是
是否有更好/更简单的方式来转换时间?(也许使用不同的图书馆)
Data.Time
是最好的支持时间库,所以我绝对同意你选择使用它来解析你从Exif数据中获取的日期和时间的字符串表示.
您确定需要设置文件的修改时间吗?这很不寻常.但如果是这样,那么是的,你需要System.Posix
在Posix系统上使用这些库.
如果您只需要阅读文件的修改,最好使用更通用的功能
System.Directory.getModificationTime
.不幸的是,该函数还使用了非标准时间库,在这种情况下System.Time
来自长期弃用的old-time
包.所以你仍然需要做一些类似的阴谋.
从转换POSIXTime
到EpochTime
恰好是OK在这种特殊情况下,但总的来说它不是去理想的方式.
该EpochTime
类型,又名time_t
从C型,不支持在Haskell来构造,而不通过积分值去任何直接的方式,尽管它本身并不一定是不可或缺根据您的操作系统上.你可以使用FFI通过C,如果那些潜在的分数对你很重要.这当然不重要,因为你从一个%S
格式参数得到秒数,这个参数没有小数部分.无论如何.你仍然需要做一些舍入或截断来从非整数UTCTime
类型到EpochTime
.
您目前只是使用Enum
实例POSIXTime
来为您进行舍入/截断,但它决定使用.同样,在这种特殊情况下,它并不重要,因为我们碰巧知道该值将是积分的.但在一般情况下,最好是自己使用明确的指定floor
,ceiling
或round
.例如,
return $ maybe ftime (fromInteger . round . utcTimeToPOSIXSeconds) etime
Run Code Online (Sandbox Code Playgroud)
(注意,您不需要case
明确写出来,您可以使用maybe
Prelude中的函数.)
请注意,我也明确fromInteger
用于通过Integer
类型推送转换.如果你想通过Int
(请注意32位机器上的"2038年问题"),我会定义一个单独的转换函数来明确:
return $ maybe ftime utcTimeToEpochTime etime
...
-- Convert from UTCTime to EpochTime via Int
utcTimeToEpochTime :: UTCTime -> EpochTime
utcTimeToEpochTime = fromIntegral . toSecs
where
toSecs :: UTCTime -> Int
toSecs = round . utcTimeToPOSIXSeconds
Run Code Online (Sandbox Code Playgroud)
您也可以使用Data.Convertible.convert
(来自可转换套餐):
import Data.Convertible (convert)
import System.Posix.Types (EpochTime(..))
import Data.Time.Clock (UTCTime(..))
utcTimeToEpochTime :: UTCTime -> EpochTime
utcTimeToEpochTime = convert
Run Code Online (Sandbox Code Playgroud)