Codereview: java Datas diff (em resolução dia)

votos
2

Agradar a sua opinião sobre o seguinte código.

Eu preciso calcular o diff em dias entre 2 objetos Date. assegurou-se que ambos os objetos Date são dentro do mesmo fuso horário.

public class DateUtils {
public final static long DAY_TIME_IN_MILLIS = 24 * 60 * 60 * 1000;

/**
 * Compare between 2 dates in day resolution.
 * 
 * @return positive integer if date1 > date2, negative if date1 < date2. 0 if they are equal.
 */
public static int datesDiffInDays(final Date date1, final Date date2){
    long date1DaysMS = date1.getTime() - (date1.getTime() % DAY_TIME_IN_MILLIS);
    long date2DaysMS = date2.getTime() - (date2.getTime() % DAY_TIME_IN_MILLIS);

    long timeInMillisDiff = (date1DaysMS - date2DaysMS);
    int ret = (int) (timeInMillisDiff / DAY_TIME_IN_MILLIS); 
    return ret;
}

Você pode apontar para um problema que eu poderia ter perdido?

EDIT: @mmyers perguntou se passar no meu teste de unidade. Bem, sim. Mas eu não tenho nenhuma experiência real com datas e sei que é um grande assunto. Postado abaixo do teste de unidade que eu estou usando.

public class TestMLDateUtils {

@Test
public final void testDatesDiffInDays() {
    TimeZone.setDefault(TimeZone.getTimeZone(UTC));

    // 00:00:00.000 1.1.1970
    Calendar cal1970 = Calendar.getInstance();
    cal1970.setTimeInMillis(0);

    Calendar tested = Calendar.getInstance();
    tested.setTimeInMillis(0);

    // Add 1 millisecond, date = 00:00:00.001 1.1.1970
    tested.add(Calendar.MILLISECOND, 1);

    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == 0);

    // Add 1 second, date = 00:00:01.001 1.1.1970
    tested.add(Calendar.SECOND, 1);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == 0);

    // Add 1 minute, date = 00:01:01.001 1.1.1970
    tested.add(Calendar.MINUTE, 1);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == 0);

    // Add 1 hour, date = 01:01:01.001 1.1.1970
    tested.add(Calendar.HOUR_OF_DAY, 1);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == 0);

    // date = 23:59:59.999 1.1.1970
    tested.setTimeInMillis(0);
    tested.add(Calendar.MILLISECOND, 999);
    tested.add(Calendar.SECOND, 59);
    tested.add(Calendar.MINUTE, 59);
    tested.add(Calendar.HOUR_OF_DAY, 23);
    //System.out.println(D:  + tested.getTime());
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == 0);

    // date = 00:00:00.000 2.1.1970
    tested.setTimeInMillis(0);
    tested.add(Calendar.DAY_OF_MONTH, 1);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == -1);
    assertTrue(DateUtils.datesDiffInDays(tested.getTime(), cal1970.getTime()) == 1);

    // date = 00:00:00.001 2.1.1970
    tested.add(Calendar.MILLISECOND, 1);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == -1);
    assertTrue(DateUtils.datesDiffInDays(tested.getTime(), cal1970.getTime()) == 1);

    // date = 00:00:01.001 2.1.1970
    tested.add(Calendar.SECOND, 1);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == -1);
    assertTrue(DateUtils.datesDiffInDays(tested.getTime(), cal1970.getTime()) == 1);

    // date = 00:01:01.001 2.1.1970
    tested.add(Calendar.MINUTE, 1);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == -1);
    assertTrue(DateUtils.datesDiffInDays(tested.getTime(), cal1970.getTime()) == 1);

    // date = 01:01:01.001 2.1.1970
    tested.add(Calendar.HOUR_OF_DAY, 1);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == -1);
    assertTrue(DateUtils.datesDiffInDays(tested.getTime(), cal1970.getTime()) == 1);

    // date = 13:01:01.001 2.1.1970
    tested.add(Calendar.HOUR_OF_DAY, 12);
    assertTrue(DateUtils.datesDiffInDays(cal1970.getTime(), tested.getTime()) == -1);
    assertTrue(DateUtils.datesDiffInDays(tested.getTime(), cal1970.getTime()) == 1);
}
}
Publicado 19/05/2009 em 17:47
fonte usuário
Em outras línguas...                            


5 respostas

votos
8

  • problema imediato: dias pode ter menos ou mais de 24 horas devido ao horário de verão mudanças de tempo.

  • problema secundário: normalmente quando as pessoas pensam em dias, eles realmente querem dizer "dias humanos" em vez de "períodos de 24 horas". Em outras palavras, muitas pessoas diriam que sete horas - sete horas no dia seguinte é uma diferença de um dia, enquanto que 7 AM-7PM no mesmo dia é uma diferença de zero dias. Ambos são 12 horas. Nesse ponto, você realmente precisa saber o calendário que está sendo considerado.

Claro, isso pode não importa para a sua situação, mas nós realmente não sei o que é.

  • Terceiro problema: você está usando o calendário API embutida em vez de Joda Tempo . Isso é quase nunca é uma boa idéia - é horrível e cheio de armadilhas e problemas. E sim, os regulares aqui vai te dizer que é sempre parte da minha resposta quando se trata de datas e horários Java - e por boas razões. É realmente muito importante.

EDIT: O teste define o fuso horário padrão para ser UTC. Isso não é realmente uma boa idéia (especialmente sem redefini-lo em um finally). fusos horários são complicadas, mas você deve realmente pensar sobre o que valoriza você tem, o que eles significam, e qual o tempo zonas estão envolvidos.

Respondeu 19/05/2009 em 18:02
fonte usuário

votos
1

Existem muitas dimensões para uma revisão de código; ao invés de correção, dirigida por outros, deixe-me concentrar um pouco sobre o estilo. Isto, claro, ser um pouco mais subjetiva do que uma revisão concentrando-se em correção.

Eu inline variável "ret". Ele aumenta o tamanho do método sem aumentando a legibilidade.

Eu consideraria que separa a conversão entre milissegundos e dias em uma função separada. Sua classe cheia provavelmente executa a divisão em vários lugares. Mesmo se não for, é útil na medida em que é mais fácil de funções de nomes que fazem apenas uma coisa.

Falando de nomear, gostaria de mudar o nome da função, talvez para "dayDifference" - abreviaturas causar muitos problemas, não menos do que é a dificuldade de se lembrar que abreviatura foi utilizado em que circunstância. Se você usar nenhum, nunca, que determinada fonte de confusão é eliminada. Da mesma forma, gostaria de mudar o nome da constante MILLISECONDS_PER_DAY.

Respondeu 19/05/2009 em 18:54
fonte usuário

votos
1

Outro problema que não tenha sido mencionado ainda é saltar segundos . Dias pode ter mais ou menos de 24 * 60 * 60segundos devido a ajustes na hora UTC para mantê-lo mais ou menos em sintonia com o ano solar médio. Provavelmente não um grande negócio para o seu uso, mas você deve pelo menos estar ciente da possibilidade.

Uma boa API é o que você precisa se você tiver requisitos não triviais para lidar com datas e horários. O link para Joda Time in a resposta de Jon Skeet parece estar quebrado, então aqui está um link que não funciona.

Respondeu 19/05/2009 em 18:11
fonte usuário

votos
1

O fuso horário, se houver, dentro do objeto Date é irrelevante, desde que você está usando getTime(); que "[r] eturns o número de milissegundos desde 1 de janeiro de 1970, 00:00:00 GMT representado por este objeto Date."

No entanto, você não está representando segundos bissextos, que algumas implementações podem retornar. Assim, se o intervalo de dias que você dá tem um ou mais segundos bissextos nele, e seus tempos estão perto o suficiente para a mesma hora do dia, o seu cálculo pode estar errado por um dia. Dito isto, parece haver nenhuma maneira de ver se qualquer implementação particular responde por segundos bissextos ou não (eu espero que a maioria não), ea diferença é muito danado trivial de qualquer maneira.

Respondeu 19/05/2009 em 18:09
fonte usuário

votos
-4

Data já tem esse método, procure Date.compareTo (Data) em Javadoc.

Respondeu 19/05/2009 em 17:57
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more