【问题标题】:Is there a better way to convert from UTCTime to EpochTime?有没有更好的方法将 UTC 时间转换为纪元时间?
【发布时间】:2011-05-10 19:25:42
【问题描述】:

我想将文件的修改时间设置为我从 exif 数据中获取的时间。

为了从 exif 中获取时间,我发现:

Graphics.Exif.getTag :: Exif -> String -> IO (Maybe String)

要设置文件修改时间,我发现:

System.Posix.Files.setFileTimes :: FilePath -> EpochTime -> EpochTime -> IO ()

假设我确实在 Exif 中找到了时间,我需要将字符串转换为 EpochTime。

  • 使用parseTime,我可以获得UTCTime
  • 使用utcTimeToPOSIXSeconds 我可以获得POSIXTime
  • 有了POSIXTime,我或多或少可以得到EpochTime

要从 UTCTime 转换为 EpochTime 这种类型检查,但我不是 确定它是正确的:

fromIntegral . fromEnum . utcTimeToPOSIXSeconds $ etime

这是函数 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)

我的问题是

有没有更好/更简单的方法来转换时间? (可能使用不同的库)

【问题讨论】:

    标签: haskell time epoch


    【解决方案1】:

    您也可以使用Data.Convertible.convert(来自convertible 包):

    import Data.Convertible (convert)
    import System.Posix.Types (EpochTime(..))
    import Data.Time.Clock (UTCTime(..))
    
    utcTimeToEpochTime :: UTCTime -> EpochTime
    utcTimeToEpochTime = convert
    

    【讨论】:

    • Data.Convertible 很整洁。如果遇到依赖问题:cabal install convertible --reinstall
    【解决方案2】:

    Data.Time 是最受支持的时间库,所以我绝对同意 您选择使用它来解析日期和时间的字符串表示 让你摆脱 Exif 数据。

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

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

    您从POSIXTimeEpochTime 的转换恰好是 在这种特殊情况下可以,但总的来说这不是理想的方法。

    EpochTime 类型, 又名 C 中的 time_t 类型,确实 不支持任何直接在 Haskell 中构建而不通过的方式 一个整数值,即使它本身不一定是整数 取决于您的操作系统。 如果这些潜在的几分之一秒是,您可以使用 FFI 通过 C 对你很重要。 这当然不重要,因为 您从不能有小数部分的%S 格式参数中获取秒数。 反正。您仍然需要进行某种舍入或截断 从非整数的UTCTime 类型到EpochTime

    您目前只是使用POSIXTimeEnum 实例来执行 舍入/截断 对你来说,不管它决定。 同样,在这种特殊情况下,这并不重要,因为我们发生了 知道该值将是整数。 但总的来说,最好指定它 明确地使用floorceilinground。例如,

    return $ maybe ftime (fromInteger . round . utcTimeToPOSIXSeconds) etime
    

    (请注意,您不需要明确写出case, 您可以使用 Prelude 中的 maybe 函数。)

    请注意,我还明确使用 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
    

    【讨论】:

    • 我正在将图片从一个文件系统复制到另一个文件系统,使用 copyFile 文件的日期丢失了,所以我需要重新设置它以匹配照片的拍摄时间。
    • @David V.:是的,可以的。 System.Posix 是。
    猜你喜欢
    • 1970-01-01
    • 2021-12-31
    • 2019-09-26
    • 2020-09-14
    • 2016-02-06
    • 2019-04-19
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    相关资源
    最近更新 更多