2012-06-13 20 views
6

Necesito analizar una cadena de duración, del formulario 98d 01h 23m 45s en milisegundos.Cadena de duración del análisis en milisegundos

Esperaba que hubiera un equivalente de SimpleDateFormat para duraciones como esta, pero no pude encontrar nada. ¿Alguien podría recomendar a favor o en contra de intentar usar SDF para este propósito?

Mi plan actual es el uso de expresiones regulares para que coincida con los números en contra y hacer algo como

Pattern p = Pattern.compile("(\\d+)"); 
Matcher m = p.matcher("98d 01h 23m 45s"); 

if (m.find()) { 
    int days = Integer.parseInt(m.group()); 
} 
// etc. for hours, minutes, seconds 

y luego usar TimeUnit a poner todo junto y convertir a milisegundos.

Supongo que mi pregunta es, esto parece exagerado, ¿se puede hacer más fácil? Aparecieron muchas preguntas sobre fechas y marcas de tiempo, pero esto es un poco diferente, tal vez.

+1

Su enfoque se ve bien hasta ahora. Sin embargo, hay que tener cuidado con 'Integer.parseInt()' y los ceros a la izquierda. Algo como '... 08h ...' se interpretará como octal y no se analizará. Elimina cualquier cerco a la izquierda. –

+0

@PhilippReichart ¿no es seguro como lo estoy usando anteriormente, ya que 'Integer.parseInt (" 08 ")' devuelve '8'? – Craigy

+0

Quizás su forma de pensar en espacios principales. 'System.out.println (" Integer.parseInt ("009")); 'imprime" 9 "en mi máquina. La' h' no se debe pasar a 'parseInt', sin embargo. – Gene

Respuesta

5

Usar un Pattern es una forma razonable de hacerlo. ¿Pero por qué no usar uno solo para obtener los cuatro campos?

Pattern p = Pattern.compile("(\\d+)d\\s+(\\d+)h\\s+(\\d+)m\\s+(\\d+)s"); 

A continuación, use la búsqueda del grupo indexado.

EDIT:

edificio fuera de su idea, que en última instancia, escribió el siguiente método

private static Pattern p = Pattern 
     .compile("(\\d+)d\\s+(\\d+)h\\s+(\\d+)m\\s+(\\d+)s"); 

/** 
* Parses a duration string of the form "98d 01h 23m 45s" into milliseconds. 
* 
* @throws ParseException 
*/ 
public static long parseDuration(String duration) throws ParseException { 
    Matcher m = p.matcher(duration); 

    long milliseconds = 0; 

    if (m.find() && m.groupCount() == 4) { 
     int days = Integer.parseInt(m.group(1)); 
     milliseconds += TimeUnit.MILLISECONDS.convert(days, TimeUnit.DAYS); 
     int hours = Integer.parseInt(m.group(2)); 
     milliseconds += TimeUnit.MILLISECONDS 
       .convert(hours, TimeUnit.HOURS); 
     int minutes = Integer.parseInt(m.group(3)); 
     milliseconds += TimeUnit.MILLISECONDS.convert(minutes, 
       TimeUnit.MINUTES); 
     int seconds = Integer.parseInt(m.group(4)); 
     milliseconds += TimeUnit.MILLISECONDS.convert(seconds, 
       TimeUnit.SECONDS); 
    } else { 
     throw new ParseException("Cannot parse duration " + duration, 0); 
    } 

    return milliseconds; 
} 
11

Echa un vistazo PeriodFormatter y PeriodParser de JodaTime library.

También puede utilizar PeriodFormatterBuilder para construir un analizador sintáctico para sus cadenas como éste

String periodString = "98d 01h 23m 45s"; 

PeriodParser parser = new PeriodFormatterBuilder() 
    .appendDays().appendSuffix("d ") 
    .appendHours().appendSuffix("h ") 
    .appendMinutes().appendSuffix("m ") 
    .appendSeconds().appendSuffix("s ") 
    .toParser(); 

MutablePeriod period = new MutablePeriod(); 
parser.parseInto(period, periodString, 0, Locale.getDefault()); 

long millis = period.toDurationFrom(new DateTime(0)).getMillis(); 

Ahora, todo esto (especialmente la parte toDurationFrom(...)) puede parecer complicado, pero realmente le aconsejará a mirar en JodaTime si se trata de períodos y duraciones en Java.

También vea at this answer about obtaining milliseconds from JodaTime period para una aclaración adicional.

+1

Gracias por la respuesta detallada. Lamentablemente, voy a utilizar un solución que no requiere agregar dependencias adicionales, pero estoy seguro de que alguien usará su código. – Craigy

+0

¡Tengo! Gracias! – Tom

4

La nueva clase java.time.Duration en Java 8 Vamos a analizar sintácticamente duraciones de la caja:

Duration.parse("P98DT01H23M45S").toMillis(); 

el formato es ligeramente diferente, por lo que sería necesario ajustar antes de realizar el análisis.

+0

Estaba a punto de publicar una nueva pregunta SO para analizar "00:07:21.5958786 "y devolver un número entero (en milis o en nanos). Gracias. Por cierto, la documentación se movió, por lo que vale la pena señalar que recomienda java.time.Duration, no otras clases de duración. – Daniel

+0

gracias, enlace roto fijo – Andrejs