2010-11-16 11 views
8

Quiero establecer el tiempo de modificación de un archivo a la hora que obtuve de los datos exif.¿Existe alguna forma mejor de convertir de UTCTime a EpochTime?

para obtener el tiempo de Exif, que encontré:

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

Para ajustar la hora de modificación del archivo, que encontré:

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

Suponiendo que encuentro una vez en Exif, necesito convertir una Cadena en un EpochTime.

  • Con parseTime Puedo obtener un UTCTime.
  • Con utcTimeToPOSIXSeconds puedo conseguir un POSIXTime
  • Con un POSIXTime puedo más o menos tener una EpochTime

Para convertir de un UTCTime a EpochTime esta typechecks, pero no estoy seguro de que es correcta:

fromIntegral . fromEnum . utcTimeToPOSIXSeconds $ etime 

Esto es parte de un getTime función que devolverá el tiempo desde Exif datos, si prese nt, de lo contrario la hora de modificación del archivo:

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) 

Mi pregunta es

¿Existe una manera mejor/más fácil de convertir el tiempo? (Tal vez usando diferentes librerias)

Respuesta

8

Data.Time es la biblioteca vez más seguidores, por lo que definitivamente estoy de acuerdo con su opción de utilizarlo para analizar la representación de cadena de fecha y hora que se obtiene de los datos Exif.

¿Estás seguro de que necesitas establecer el tiempo de modificación de un archivo? Eso es inusual. Pero si es así, entonces sí, necesitará usar las bibliotecas System.Posix en un sistema Posix.

Si sólo necesita leer la modificación de un archivo, que sería mejor usar la función más genérica System.Directory.getModificationTime. Desafortunadamente, esa función también usa una biblioteca de tiempo no estándar, System.Time del paquete largamente obsoleto old-time en este caso. Así que todavía necesitarías hacer algunas maquinaciones similares.

Su conversión de POSIXTime a EpochTime pasa a ser OK en este caso particular, pero en general no es la forma ideal de hacerlo.

El tipo EpochTime, a.k.al tipo time_t de C, does no admite ninguna forma directa de construirse en Haskell sin pasar por un valor integral, aunque en sí mismo no es necesariamente integral dependiendo de su sistema operativo. Puede ir a través de C usando el FFI si esas fracciones potenciales de un segundo son importantes para usted. Aquí ciertamente no es importante, porque está obteniendo los segundos de un parámetro de formato %S que no puede tener una parte fraccionaria. De todos modos. aún tendrá que hacer algún tipo de redondeo o truncado para obtener del tipo UTCTime no integral al EpochTime.

Actualmente estas simplemente utilizando la instancia de EnumPOSIXTime para hacer el redondeo /truncar para usted, sin embargo, decide. Una vez más, en este caso particular, realmente no importa, porque pasamos a para saber que el valor será integral. Pero, en general, es mejor especificarlo usted mismo explícitamente usando floor, ceiling o round. Por ejemplo,

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

(Tenga en cuenta que no es necesario escribir la case explícitamente, puede utilizar la función maybe del preludio.)

aviso de que estoy también de manera explícita usando fromInteger para empujar la conversión a través de el tipo Integer. Si quieres ir a través de Int lugar (cuidado con el "problema del año 2038" en máquinas de 32 bits), me gustaría definir una función de conversión separado que esto quede claro:

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 
+0

estoy copiando imágenes desde un sistema de archivos a otro, usando copyFile fecha del archivo se pierde, por lo que tenga que configurar de nuevo para que coincida con el tiempo se tomó la fotografía. –

+0

@David V .: Sí, eso lo hará. 'System.Posix' es. – Yitz

8

También puede utilizar Data.Convertible.convert (del paquete convertible):

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

utcTimeToEpochTime :: UTCTime -> EpochTime 
utcTimeToEpochTime = convert 
+1

Data.Convertible está limpio. Si se encuentra con un problema de dependencia con él: cabal install convertible --reinstall – Joe

Cuestiones relacionadas