2011-12-20 17 views
10

Estoy tratando de escribir un código para dormir hasta el comienzo del próximo minuto en la zona horaria local, pero estoy teniendo una gran dificultad para hacerlo. La biblioteca time siempre ha sido uno de mis puntos débiles, así que supongo que hay una manera fácil de hacerlo.Dormir hasta el comienzo del próximo minuto

Pensé en solo computar un nuevo TimeOfDay, pero eso no manejaría 23:59 a 00:00, y presumiblemente haría cosas muy confusas con el cambio de horario de verano.

Manejar segundos interminables sería una buena bonificación también.

Utilizar Control.Concurrent.threadDelay para dormir me parece el método más simple, por lo que una pregunta alternativa sería: ¿Cómo puedo obtener el número de microsegundos hasta el comienzo del próximo minuto? DiffTime y NominalDiffTime serían formas perfectamente aceptables de lograr esto.

+0

¿Podría obtener segundos componentes de la hora actual y luego dormir (60 segundos)? Con segundos de diferencia, eso debería funcionar razonablemente bien. ¿Qué tan preciso es el despertar? –

+0

Eso funcionaría si realmente no hay otra manera de hacerlo sin un cálculo completamente manual, pero sería una pena perder la mayor precisión que podía obtener con los mismos datos. Aunque no es un gran problema; estar un segundo o así tarde no es un problema, pero definitivamente me gustaría evitar despertar * antes de * que comience el próximo minuto - el error que produce solo se corregirá al minuto siguiente. Es cierto que los segundos intercalares no son muy comunes. – ehird

+0

Hmm, la documentación para 'UTCTime' parece implicar que los segundos intercalares no son manejados por las acciones de medición como' getCurrentTime', por lo que sería una solución aceptable después de todo; el campo de segundos en realidad está dado con precisión de picosegundo, por lo que daría la mejor precisión que podría esperar. Lo probaré. – ehird

Respuesta

10

Me preocupa que esto no sea lo que quieres dado tus últimos comentarios. Creo que esto toleraría los años bisiestos, los cambios en la zona horaria y los cambios de día, pero no en segundos.

import Control.Concurrent (threadDelay) 
import Data.Time.Clock 

sleepToNextMinute :: IO() 
sleepToNextMinute = do t <- getCurrentTime 
         let secs = round (realToFrac $ utctDayTime t) `rem` 60 
         threadDelay $ 1000000 * (60 - secs) 

main = do putStrLn "Starting..." 
      sleepToNextMinute 
      putStrLn "Minute 1" 
      sleepToNextMinute 
      putStrLn "Minute 2" 
+0

Resultó que terminé usando algo sustancialmente similar a esto, para admitir más de 60 s; solo utilicé 'delta '- mod' (utctDayTime t) delta' y luego lo convertí en microsegundos. ¡Gracias! – ehird

+0

Para intervalos de tiempo pequeños que podrían funcionar siempre que el valor de threadDelay sea inferior a maxBound :: Int – Jonke

2

Quizás esto te ayude: PLEAC-Haskell: Dates and Times.

Con la ayuda de esto, debe poder obtener el minuto actual con el que puede crear el tiempo del comienzo del siguiente minuto. Entonces solo tome la diferencia como tiempo de sueño.

+0

Sé cómo obtener el minuto actual, pero obteniendo el comienzo del próximo minuto es mucho más complicado que eso, ya que depende de los cambios de día, año, cambios de zona horaria, etc. * Podría * simplemente conectar en cascada minuto → hora → día → mes → año e ignorar el horario de verano (que sería muy inconveniente ...), pero eso sería un montón de código manual para algo que debería ser una operación bastante simple de expresar ... puede terminar siendo que esta es la única manera de hacerlo. (En cuyo caso necesitamos una mejor biblioteca de tiempo). – ehird

+0

Ah, y también tendría que manejar años bisiestos manualmente. Ugh. – ehird

+0

Ah, ahora entiendo su problema con tiempos especiales ... Pero, ¿qué sucede si la diferencia "11:60:00" (comienza el próximo minuto) y "11:59:42" (hora actual) se calcula correctamente? Entonces depende del cálculo de la interpretación/diferencia de las bibliotecas (si 11:60:00 se interpreta como 12:00:00 etc. todo está bien). – user905686

1

No soy un experto en el paquete time, pero ¿qué tal algo como esto:

import Data.Time -- need Clock and LocalTime 

curTime <- getCurrentTime 
let curTOD = timeToTimeOfDay $ utctDayTime curTime 
    last = TimeOfDay (todHour curTOD) (todMin curTOD) 0 
    diff = timeOfDayToTime last + 60 - utctDayTime curTime 

Esto dará lugar a diff :: DiffTime con la diferencia correcta en cuestión de segundos; todos los límites y años bisiestos deben ser contabilizados. No estoy seguro de los segundos interminables; probablemente necesitarías agregarlos manualmente.

Esto no tiene en cuenta ningún cambio específico de zona horaria, pero como getCurrentTime devuelve un tiempo UTC, creo que funcionará en general. Puede intentar usar utcToLocalTimeOfDay en lugar de timeToTimeOfDay para administrar cosas específicas de la zona horaria, pero luego tendría que hacer un trabajo extra para administrar las compensaciones diarias.

Cuestiones relacionadas