有没有更好的方法将UTCTime转换为EpochTime?

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

从转换UTCTimeEpochTime这个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)

我的问题是

是否有更好/更简单的方式来转换时间?(也许使用不同的图书馆)

Yit*_*itz 8

Data.Time 是最好的支持时间库,所以我绝对同意你选择使用它来解析你从Exif数据中获取的日期和时间的字符串表示.

您确定需要设置文件的修改时间吗?这很不寻常.但如果是这样,那么是的,你需要System.Posix在Posix系统上使用这些库.

如果您只需要阅读文件的修改,最好使用更通用的功能 System.Directory.getModificationTime.不幸的是,该函数还使用了非标准时间库,在这种情况下System.Time来自长期弃用的old-time包.所以你仍然需要做一些类似的阴谋.

从转换POSIXTimeEpochTime恰好是OK在这种特殊情况下,但总的来说它不是去理想的方式.

EpochTime类型,又名time_t从C型,不支持在Haskell来构造,而不通过积分值去任何直接的方式,尽管它本身并不一定是不可或缺根据您的操作系统上.你可以使用FFI通过C,如果那些潜在的分数对你很重要.这当然不重要,因为你从一个%S格式参数得到秒数,这个参数没有小数部分.无论如何.你仍然需要做一些舍入或截断来从非整数UTCTime类型到EpochTime.

您目前只是使用Enum实例POSIXTime来为您进行舍入/截断,但它决定使用.同样,在这种特殊情况下,它并不重要,因为我们碰巧知道该值将是积分的.但在一般情况下,最好是自己使用明确的指定floor,ceilinground.例如,

return $ maybe ftime (fromInteger . round . utcTimeToPOSIXSeconds) etime
Run Code Online (Sandbox Code Playgroud)

(注意,您不需要case明确写出来,您可以使用maybePrelude中的函数.)

请注意,我也明确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)


The*_*ard 8

您也可以使用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)