Defina a hora para 00:00:00

121

Eu tenho um problema ao redefinir horas em Java. Para uma determinada data, desejo definir as horas como 00:00:00.

Este é o meu código:

/**
     * Resets milliseconds, seconds, minutes and hours from the provided date
     *
     * @param date
     * @return
     */
    public static Date trim(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR, 0);

        return calendar.getTime();
    }

O problema é que às vezes a hora é 12:00:00e às vezes é 00:00:00e quando eu procuro no banco de dados uma entidade que foi salva 07.02.2013 00:00:00e a hora real da entidade, que está armazenada, 12:00:00a consulta falha.

Eu sei disso 12:00:00 == 00:00:00!

Estou usando o AppEngine. Este é um bug do appengine, problema ou algum outro problema? Ou depende de outra coisa?

Adelin
fonte
Isso pode ter algo a ver com locais diferentes ou isso acontece no mesmo PC o tempo todo?
LostBoy
isso acontece quando eu implanto no appengine.
Adelin
Muitas outras soluções para reduzir o tempo: stackoverflow.com/a/1908955/2646526
heenenee
Para sua informação, as antigas classes problemáticas de data e hora como java.util.Date, java.util.Calendare java.text.SimpleDateFormatagora são legadas , suplantadas pelas classes java.time construídas em Java 8 e Java 9. Consulte o Tutorial da Oracle .
Basil Bourque
1
Eu usei calendar.set(Calendar.HOUR_OF_DAY, 0);, para meu propósito, funciona bem.
hariprasad

Respostas:

209

Use outra constante em vez de Calendar.HOUR, use Calendar.HOUR_OF_DAY.

calendar.set(Calendar.HOUR_OF_DAY, 0);

Calendar.HOURusa 0-11 (para uso com AM / PM) e Calendar.HOUR_OF_DAYusa 0-23.

Para citar os Javadocs:

public static final int HOUR

Número do campo para obter e definir indicando a hora da manhã ou da tarde. HOUR é usado para o relógio de 12 horas (0 - 11). O meio-dia e a meia-noite são representados por 0, não por 12. Por exemplo, às 10h04: 15h25, a HORA é 10.

e

public static final int HOUR_OF_DAY

Número do campo para obter e definir indicando a hora do dia. HOUR_OF_DAY é usado para o relógio de 24 horas. Por exemplo, às 10: 04: 15.250, HOUR_OF_DAY é 22

Teste ("agora" é atualmente 14h55 de 23 de julho de 2013, horário de verão do Pacífico):

public class Main
{
   static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args)
    {
        Calendar now = Calendar.getInstance();
        now.set(Calendar.HOUR, 0);
        now.set(Calendar.MINUTE, 0);
        now.set(Calendar.SECOND, 0);
        System.out.println(sdf.format(now.getTime()));
        now.set(Calendar.HOUR_OF_DAY, 0);
        System.out.println(sdf.format(now.getTime()));
    }
}

Resultado:

$ javac Main.java
$ java Main
2013-07-23 12:00:00
2013-07-23 00:00:00
rgettman
fonte
3
@JarrodRoberson Mas usar Calendar.HOURnão definiria PM como AM, deixando-o como 12:00.
rgettman
Você pode me ajudar a construir um LocalDate com horas, minutos e segundos? Eu sei que uma opção é seguir DateTime.
Woody
11
Quem criou o campo HOUR e HOUR_OF_DAY deveria ter sido açoitado e receber rações.
AndroidDev
1
@AndroidDev quem inventou am / pm merece o mesmo ... Isso também vale para padrões não métricos
Dedicado em
1
Para sua informação, as antigas classes problemáticas de data e hora como java.util.Date, java.util.Calendare java.text.SimpleDateFormatagora são legadas , suplantadas pelas classes java.time construídas em Java 8 e Java 9. Consulte o Tutorial da Oracle .
Basil Bourque
29

java.time

Usando a java.timeestrutura integrada em Java 8 e posterior. Veja o tutorial .

import java.time.LocalTime;
import java.time.LocalDateTime;

LocalDateTime now = LocalDateTime.now(); # 2015-11-19T19:42:19.224
# start of a day
now.with(LocalTime.MIN); # 2015-11-19T00:00
now.with(LocalTime.MIDNIGHT); # 2015-11-19T00:00

Se você não precisa da hora do dia (hora, minuto, segundo, etc. partes), considere usar a LocalDateclasse.

LocalDate.now(); # 2015-11-19
Przemek
fonte
Essa deve ser a nova resposta aceita, já que o Java 1.8 foi lançado, desde que essa pergunta foi feita pela primeira vez.
Mate para o dia
LocalDateTimeé exatamente a classe errada a ser usada para isso. Não pode representar um momento, pois carece de qualquer conceito de fuso horário ou deslocamento do UTC. Ligar LocalDateTime.nowquase nunca faz sentido. Use em seu ZonedDateTimelugar. Caso contrário, você estará ignorando questões cruciais de fuso horário. Por um lado, algumas datas em algumas zonas não começam às 00:00!
Basil Bourque
12

Aqui estão algumas funções utilitárias que uso para fazer exatamente isso.

/**
 * sets all the time related fields to ZERO!
 *
 * @param date
 *
 * @return Date with hours, minutes, seconds and ms set to ZERO!
 */
public static Date zeroTime( final Date date )
{
    return DateTimeUtil.setTime( date, 0, 0, 0, 0 );
}

/**
 * Set the time of the given Date
 *
 * @param date
 * @param hourOfDay
 * @param minute
 * @param second
 * @param ms
 *
 * @return new instance of java.util.Date with the time set
 */
public static Date setTime( final Date date, final int hourOfDay, final int minute, final int second, final int ms )
{
    final GregorianCalendar gc = new GregorianCalendar();
    gc.setTime( date );
    gc.set( Calendar.HOUR_OF_DAY, hourOfDay );
    gc.set( Calendar.MINUTE, minute );
    gc.set( Calendar.SECOND, second );
    gc.set( Calendar.MILLISECOND, ms );
    return gc.getTime();
}

fonte
6

Mais um modo JAVA 8:

LocalDateTime localDateTime = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);

Mas é muito mais útil editar a data que já existe.

Thorinkor
fonte
1
LocalDateTimenão pode representar um momento, pois carece de qualquer conceito de fuso horário ou deslocamento do UTC. Ligar LocalDateTime.nowquase nunca faz sentido. Você deveria estar usando ZonedDateTime.
Basil Bourque
3

É melhor definir principalmente o fuso horário para o componente DateFormat, como este:

DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

Então você pode obter o tempo "00:00:00" passando 0 milissegundos para o formatador:

String time = dateFormat.format(0);

ou você pode criar o objeto Date:

Date date = new Date(0); // also pass milliseconds
String time = dateFormat.foramt(date);

ou você pode ter mais possibilidades usando o componente Calendário, mas também deve definir o fuso horário como GMT para a instância do calendário:

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.US);
calendar.set(Calendar.HOUR_OF_DAY, 5);
calendar.set(Calendar.MINUTE, 37);
calendar.set(Calendar.SECOND, 27);

dateFormat.format(calendar.getTime());
Dmitriy Smerchinskiy
fonte
2

tl; dr

myJavaUtilDate                                 // The terrible `java.util.Date` class is now legacy. Use *java.time* instead.
.toInstant()                                   // Convert this moment in UTC from the legacy class `Date` to the modern class `Instant`.
.atZone( ZoneId.of( "Africa/Tunis" ) )         // Adjust from UTC to the wall-clock time used by the people of a particular region (a time zone).
.toLocalDate()                                 // Extract the date-only portion.
.atStartOfDay( ZoneId.of( "Africa/Tunis" ) )   // Determine the first moment of that date in that zone. The day does *not* always start at 00:00:00.

java.time

Você está usando classes terríveis de data e hora que foram suplantadas anos atrás pelas classes java.time modernas definidas no JSR 310.

DateInstant

A java.util.Daterepresenta um momento no UTC. Sua substituição é Instant. Chame os novos métodos de conversão adicionados às classes antigas.

Instant instant = myJavaUtilDate.toInstant() ;

Fuso horário

Especifique o fuso horário no qual deseja que a nova hora do dia faça sentido.

Especifique um nome próprio fuso horário no formato Continent/Region, como America/Montreal, Africa/Casablanca, ou Pacific/Auckland. Nunca use o 2-4 letras, como ESTou ISTcomo eles são não zonas verdadeiros tempo, não padronizados, e nem mesmo única (!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;

ZonedDateTime

Aplique o ZoneIdao Instantpara obter um ZonedDateTime. Mesmo momento, mesmo ponto na linha do tempo, mas com um relógio de parede diferente.

ZonedDateTime zdt = instant.atZone( z ) ;

Mudando a hora do dia

Você pediu para alterar a hora do dia. Aplique a LocalTimepara alterar todas as partes da hora do dia: hora, minuto, segundo, segundo fracionário. Um novo ZonedDateTimeé instanciado, com valores baseados no original. As classes java.time usam esse padrão de objetos imutáveis para fornecer segurança de thread .

LocalTime lt = LocalTime.of( 15 , 30 ) ;  // 3:30 PM.
ZonedDateTime zdtAtThreeThirty = zdt.with( lt ) ; 

Primeiro momento do dia

Mas você pediu especificamente para 00:00. Então, aparentemente, você quer o primeiro momento do dia. Cuidado: alguns dias em algumas zonas não começam às 00:00:00. Eles podem iniciar em outro horário, como 01:00:00 devido a anomalias como horário de verão (DST).

Deixe java.time determinar o primeiro momento. Extraia a parte apenas da data. Em seguida, passe o fuso horário para obter o primeiro momento.

LocalDate ld = zdt.toLocalDate() ;
ZonedDateTime zdtFirstMomentOfDay = ld.atStartOfDay( z ) ;

Ajustar para UTC

Se você precisar voltar ao UTC, extraia um Instant.

Instant instant = zdtFirstMomentOfDay.toInstant() ;

InstantDate

Se você precisar java.util.Dateinteroperar com o código antigo ainda não atualizado para java.time , converta.

java.util.Date d = java.util.Date.from( instant ) ;
Basil Bourque
fonte
1

Fazer isso poderia ser mais fácil (em Java 8)

LocalTime.ofNanoOfDay(0)
meszias
fonte
Obrigado, trabalhei com outras coisas nos últimos 2 anos e Java 6/7 antes disso. Voltei ao Java agora (depois de trabalhar com algumas coisas no Groovy) e estou gostando das diferenças do Java 8.
meszias
1

Podemos definir a parte do tempo java.util.Date para 00:00:00 usando a classe LocalDate do Java 8 / Joda-datetime api :

Date datewithTime = new Date() ; // ex: Sat Apr 21 01:30:44 IST 2018
LocalDate localDate = LocalDate.fromDateFields(datewithTime);
Date datewithoutTime = localDate.toDate(); // Sat Apr 21 00:00:00 IST 2018
Atishay
fonte
1

Se você precisar do formato 00:00:00 em string, deve usar SimpleDateFormat conforme abaixo. Usando "H" em vez de "h".

Date today = new Date();
SimpleDateFormat ft = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); 
//not SimpleDateFormat("dd-MM-yyyy hh:mm:ss")
Calendar calendarDM = Calendar.getInstance();
calendarDM.setTime(today);
calendarDM.set(Calendar.HOUR, 0);
calendarDM.set(Calendar.MINUTE, 0);
calendarDM.set(Calendar.SECOND, 0);
System.out.println("Current Date: " + ft.format(calendarDM.getTime()));

//Result is: Current Date: 29-10-2018 00:00:00
Ngô Ngọc Quang
fonte
0

Outra maneira de fazer isso seria usar um DateFormat sem segundos:

public static Date trim(Date date) {
    DateFormat format = new SimpleDateFormat("dd.MM.yyyy");
    Date trimmed = null;
    try {
        trimmed = format.parse(format.format(date));
    } catch (ParseException e) {} // will never happen
    return trimmed;
}
MMascarin
fonte
0

Você pode fazer isso com o seguinte:

Calendar cal = Calendar.getInstance();
cal.set(year, month, dayOfMonth, 0, 0, 0);
Date date = cal.getTime();
Sagar Patel
fonte
0

Como Java8 adiciona novas funções de data, podemos fazer isso facilmente.


    // If you have instant, then:
    Instant instant1 = Instant.now();
    Instant day1 = instant1.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day1); //2019-01-14T00:00:00Z

    // If you have Date, then:
    Date date = new Date();
    Instant instant2 = date.toInstant();
    Instant day2 = instant2.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day2); //2019-01-14T00:00:00Z

    // If you have LocalDateTime, then:
    LocalDateTime dateTime = LocalDateTime.now();
    LocalDateTime day3 = dateTime.truncatedTo(ChronoUnit.DAYS);
    System.out.println(day3); //2019-01-14T00:00
    String format = day3.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    System.out.println(format);//2019-01-14T00:00:00

Chao Jiang
fonte
LocalDateTimenão pode representar um momento, pois carece de qualquer conceito de fuso horário ou deslocamento do UTC. Ligar LocalDateTime.nowquase nunca faz sentido. Você deveria estar usando ZonedDateTime.
Basil Bourque