9

ファイルの変更時刻を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)

私の質問は

時間を変換するためのより良い/より簡単な方法はありますか?(多分異なるライブラリを使用しています)

4

2 に答える 2

9

Data.Convertible.convert(変換可能なパッケージから) 以下を使用することもできます。

import Data.Convertible (convert)
import System.Posix.Types (EpochTime(..))
import Data.Time.Clock (UTCTime(..))

utcTimeToEpochTime :: UTCTime -> EpochTime
utcTimeToEpochTime = convert
于 2012-02-02T23:32:49.020 に答える
8

Data.Timeはサポートされている最も優れた時間ライブラリであるため、Exifデータから取得した日付と時刻の文字列表現を解析するためにこれを使用するという選択に間違いなく同意します。

ファイルの変更時刻を設定する必要がありますか?それは珍しいことです。しかし、そうであれば、はい、System.PosixPosixシステムでライブラリを使用する必要があります。

ファイルの変更を読み取るだけでよい場合は、より一般的な関数を使用することをお勧めします System.Directory.getModificationTime。残念ながら、この関数は、この場合はSystem.Time非推奨の長いold-timeパッケージからの非標準の時間ライブラリも使用します。したがって、同様の策略を行う必要があります。

POSIXTimeこの特定のケースでは、からへの変換はEpochTimeたまたま問題ありませんが、一般的には理想的な方法ではありません。

このEpochTimeタイプ、別名time_tCのタイプは、オペレーティングシステムによっては必ずしも整数である必要はありませんが、整数値を経由せずにHaskellで直接構築する方法をサポートしていません。これらの潜在的な1秒の端数が重要である場合は、FFIを使用してC経由で移動できます。%Sここでは、小数部分を持たないフォーマットパラメータから秒を取得しているため、これは確かに重要ではありません。ともかく。UTCTime非整数型からに移行するには、何らかの丸めまたは切り捨てを行う必要がありますEpochTime

Enum現在、のインスタンスを使用POSIXTimeして丸め/切り捨てを行っていますが、それを行うことにしました。繰り返しますが、この特定のケースでは、値が整数になることがわかっているため、実際には問題ではありません。floorただし、一般的には、、、ceilingまたはを使用して明示的に指定することをお勧めしますround。例えば、

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

case(明示的に書き出す必要はないことに注意してください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
于 2010-11-16T18:04:50.377 に答える