Como faço para obter uma data sem tempo em Java?

235

Continuando do Stack Overflow, pergunte ao programa Java para obter a data atual sem registro de data e hora :

Qual é a maneira mais eficiente de obter um objeto Date sem o horário? Existe alguma outra maneira além dessas duas?

// Method 1
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dateWithoutTime = sdf.parse(sdf.format(new Date()));

// Method 2
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
dateWithoutTime = cal.getTime();

Atualização :

  1. Eu sabia sobre Joda-Time ; Estou apenas tentando evitar uma biblioteca adicional para uma tarefa tão simples (eu acho). Mas, com base nas respostas até agora, o Joda-Time parece extremamente popular, então eu posso considerar isso.

  2. Por eficiente , quero dizer que quero evitar a Stringcriação temporária de objetos conforme usada method 1, enquanto isso method 2parece um hack em vez de uma solução.

Rosdi Kasim
fonte
1
Eficiente? Você precisa de mais eficiência do que o fornecido, por exemplo, pelo método1?
Johan Sjöberg
2
O que você quer dizer com "eficiente"? Uma data é basicamente um tempo digitado, você realmente não pode fazer isso com menos memória que isso. Se você quer dizer "conveniente", o tempo JODA é o caminho a percorrer.
21411 millimoose
3
+1 Exatamente a pergunta que eu tinha.
Alba Mendez
1
Eu gosto do método 2. Crie um método estático em uma classe de utilitário e apenas use-o. Eu tenho essa abordagem há anos.
Wilson Freitas
1
Nitpicking em sua "atualização 1": se fosse "uma tarefa tão simples", acho que a Sun não teria chegado a uma API tão horrenda e ineficiente, e você (e muitas outras pessoas) não faria essa pergunta
Flávio Etrusco 04/04

Respostas:

108

Você absolutamente tem que usar java.util.Date? Eu recomendaria completamente que você usasse o Joda Time ou o java.timepacote do Java 8. Em particular, enquanto Data e Calendário sempre representam um instante específico no tempo, sem nenhum conceito como "apenas uma data", o Tempo de Joda não ter um tipo que representa este ( LocalDate). Seu código será muito mais claro se você puder usar tipos que representam o que você realmente está tentando fazer.

Existem muitos outros motivos para usar o Joda Time ou em java.timevez dos java.utiltipos internos - eles geralmente são APIs muito melhores. Você sempre pode converter de / para a java.util.Datenos limites do seu próprio código, se necessário, por exemplo, para interação com o banco de dados.

Jon Skeet
fonte
75
Em aplicativos corporativos, nem sempre temos a opção de adicionar / usar outras bibliotecas. Agradeço o ponteiro para o Joda Time, mas não é realmente uma resposta para a questão original de obter a parte da data usando o Java padrão. Obrigado. Promovendo a resposta de Chathuranga.
noogrub 17/09/2013
3
@noogrub: A resposta de Chathugranga não responde à pergunta original, que é perguntar como obter um Dateobjeto - essa resposta formata uma data em uma string, o que não é a mesma coisa. Fundamentalmente, perguntar em que data Dateé uma pergunta sem sentido sem mais informações: o fuso horário e o sistema de calendário que você está usando.
Jon Skeet
7
"Nos aplicativos corporativos, nem sempre temos a opção de adicionar / usar outras bibliotecas". Sério ? Você está sugerindo que não pode usar bibliotecas de terceiros?
Brian Agnew
3
@BrianAgnew comentário de noogrub parece estar relacionado a restrições não-tech, eu acho
Jose_GD
3
Da perspectiva de hoje: " Joda-Time é a biblioteca de data e hora padrão de fato para Java anterior ao Java SE 8. Agora, os usuários são solicitados a migrar para java.time (JSR-310)."
Drux
66

Aqui está o que eu usei para obter a data de hoje com o horário definido para 00:00:00:

DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");

Date today = new Date();

Date todayWithZeroTime = formatter.parse(formatter.format(today));
Shobbi
fonte
28
De que maneira isso é diferente do "método 1" já proposto na pergunta original?
22413 Chris
Não aborda em que fuso horário isso ocorre (da esquerda para o fuso horário padrão arbitrário da JVM).
Darrell Teague
58

Você pode usar o DateUtils.truncate da biblioteca Apache Commons.

Exemplo:

DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)
JoGo
fonte
3
Se você deseja adicionar uma nova biblioteca, seja Joda em vez de Apache Commons.
Dibbeke
6
+1 @Dibbeke A diferença não é apenas o fato de você estar adicionando uma biblioteca em vez de outra. Às vezes, não se quer aprender uma biblioteca totalmente nova apenas para a tarefa trivial de interromper a hora de uma data. Ou não deseja ter um código que combine Data / Calendário com datas Joda usando algumas vezes a primeira e outras a segunda. Ou não pode se dar ao luxo de justificar a substituição de todo o código baseado em Data / Calendário que funcione bem por outra biblioteca para uma finalidade tão trivial. Enquanto sugerindo Joda é certamente bom, pois é claramente superior e simplesmente a coisa certa, às vezes chutes vida real em.
SantiBailors
Gênio! Me ajudou muito
Thiesen
37

Existe alguma outra maneira além dessas duas?

Sim existe.

LocalDate.now( 
    ZoneId.of( "Pacific/Auckland" ) 
)

java.time

O Java 8 e posterior vem com o novo pacote java.time embutido. Veja o tutorial . Grande parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen-Backport e adaptada ainda mais ao Android no ThreeTenABP .

Semelhante ao Joda-Time , o java.time oferece uma LocalDateclasse para representar um valor somente de data, sem hora do dia e sem fuso horário.

Observe que o fuso horário é crítico para determinar uma data específica. No início da meia-noite em Paris, por exemplo, a data ainda é "ontem" em Montreal.

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;

Por padrão, java.time usa o padrão ISO 8601 na geração de uma representação de string de um valor de data ou data / hora. (Outra semelhança com Joda-Time.) Então, basta ligar toString()para gerar texto como 2015-05-21.

String output = today.toString() ; 

Sobre java.time

A estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, como java.util.Date, Calendar, e SimpleDateFormat.

O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .

Para saber mais, consulte o Tutorial do Oracle . E procure Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Onde obter as classes java.time?

  • Java SE 8 , Java SE 9 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação em pacote configurável.
    • O Java 9 adiciona alguns recursos e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores das implementações de pacote configurável do Android das classes java.time.
    • Para anteriormente Android, o ThreeTenABP projeto adapta ThreeTen-Backport (mencionados acima). Consulte Como usar o ThreeTenABP… .

O projeto ThreeTen-Extra estende o java.time com classes adicionais. Este projeto é um campo de prova para possíveis adições futuras ao java.time. Você pode encontrar algumas classes úteis aqui, como Interval, YearWeek, YearQuarter, e mais .

Basil Bourque
fonte
1
Obrigado por mencionar o fuso horário . Não me ocorreu que "que dia é hoje" não é um conceito absoluto.
Página
@ToolmakerSteve A obtenção da data sempre envolve um fuso horário. Mas o truque é que, se você não especificar um fuso horário, o fuso horário padrão atual da sua JVM será automaticamente aplicado na determinação da data. Além disso, o fuso horário atual da JVM pode mudar a qualquer momento ! Qualquer código em qualquer encadeamento de qualquer aplicativo na JVM pode chamar TimeZone.setDefaultdurante o tempo de execução e afetar imediatamente todos os outros códigos em execução nessa JVM. Moral da história: sempre especifique um fuso horário.
Basil Bourque
22

A maneira mais direta:

long millisInDay = 60 * 60 * 24 * 1000;
long currentTime = new Date().getTime();
long dateOnly = (currentTime / millisInDay) * millisInDay;
Date clearDate = new Date(dateOnly);
romano
fonte
5
Para mim, atualmente é: "Sáb 19 de fevereiro 01 : 00: 00 CET 2011". Se você quiser usar isso, somente com UTC.
19711 Chris Lercher
4
A linha 3 não é long dateOnly = (currentTime / millisInDay) * millisInDay;a mesma coisa que escrever long dateOnly = currentTime;?
31413 Chris
5
Não é, por causa da matemática inteira. Pense nisso mais como Math.floor (currentTime / millisInDay) * millisInDay. Ele está efetivamente ajustando o horário para 00:00:00 dessa maneira.
Nicholas Flynt
2
Essa solução provavelmente é boa para a maioria das aplicações, mas lembre-se de que a suposição de que um dia tem 60 * 60 * 24 * 1000 nem sempre é verdadeira. Você pode, por exemplo, ter segundos bissextos em alguns dias.
Pierre-Antoine
1
Esta é sem dúvida a maneira mais obtusa e não recomendada sobre outros métodos claros e concisos de 1 e 2 linhas.
Darrell Teague
22

A resposta padrão para essas perguntas é usar o Joda Time . A API é melhor e, se você estiver usando os formatadores e analisadores, poderá evitar a falta não intuitiva de segurança de threads SimpleDateFormat.

Usar o Joda significa que você pode simplesmente:

LocalDate d = new LocalDate();

Update :: Usando o java 8, isso pode ser obtido usando

LocalDate date = LocalDate.now();
Brian Agnew
fonte
O novo pacote java.time no Java 8 também oferece uma LocalDateclasse semelhante ao Joda-Time.
Basil Bourque
1
Idealmente, você passaria um DateTimeZonepara esse construtor LocalDate. A determinação da data atual depende do fuso horário, pois Paris inicia uma nova data antes de Montreal. Se você omitir o fuso horário, o fuso horário padrão da sua JVM será aplicado. Geralmente é melhor especificar do que confiar no padrão.
Basil Bourque
8

Esta é uma maneira simples de fazer isso:

Calendar cal = Calendar.getInstance();
SimpleDateFormat dateOnly = new SimpleDateFormat("MM/dd/yyyy");
System.out.println(dateOnly.format(cal.getTime()));
Glen
fonte
4
Esta resposta falha ao abordar a questão. Obter uma sequência formatada não era o objetivo.
Basil Bourque
7

Não faz sentido falar sobre uma data sem um carimbo de data / hora no que diz respeito às rotinas de Data no tempo de execução java padrão, pois ele é essencialmente mapeado para um milissegundo específico e não para uma data. Esse milissegundo intrinsecamente possui uma hora do dia anexada, o que a torna vulnerável a problemas de fuso horário, como o horário de verão e outros ajustes do calendário. Veja Por que subtrair essas duas vezes (em 1927) está dando um resultado estranho? para um exemplo interessante.

Se você quiser trabalhar com datas em vez de milissegundos, precisará usar outra coisa. Para o Java 8, há um novo conjunto de métodos que fornece exatamente o que você solicita. Para Java 7 e versões anteriores, use http://www.joda.org/joda-time/

Thorbjørn Ravn Andersen
fonte
3
Nota: Essas abordagens que dizem "a data à meia-noite" não lidam bem com o horário de verão e com vários fusos horários.
Thorbjørn Ravn Andersen
Confirmo que estava incrementando as datas em um dia no meu aplicativo e aprendi sobre isso com um relatório de erros de usuários em um fuso horário com horário de verão (meu país não usa horário de verão). No dia em que o horário de verão começa, meu aplicativo adiciona 11 horas em vez de 12. Talvez usar o meio-dia como a hora para uma data "sem horário" seja melhor?
Jose_GD
1
@Jose_GD Ainda é, na melhor das hipóteses, um hack. Você pode achar youtube.com/watch?v=-5wpm-gesOY divertido.
Thorbjørn Ravn Andersen 08/09
@ Thorbjorn, você está certo, só queria evitar o JodaTime porque adicionar uma biblioteca para apenas um recurso em excesso de som para mim. Eu sabia sobre esse vídeo, engraçado mesmo.
Jose_GD 9/09/14
1
@Jose_GD O argumento era que existe um caso de uso real na vida real, no qual sua abordagem seria considerada um bug. Se você encontrou um, pode haver mais ... Eu não sei como Joda lida com isso, mas você pode dar uma olhada. Observe também que o Java 8 traz uma nova biblioteca de data e hora (com base nas experiências com o Joda) nas quais você pode procurar.
Thorbjørn Ravn Andersen
4

Definitivamente, não é a maneira mais correta, mas se você precisar de uma solução rápida para obter a data sem o horário e não desejar usar uma biblioteca de terceiros, isso deve fazer

    Date db = db.substring(0, 10) + db.substring(23,28);

Eu só precisava da data para fins visuais e não podia Joda, então fiz uma substring.

Bamz
fonte
4
// 09/28/2015
System.out.println(new SimpleDateFormat("MM/dd/yyyy").format(Calendar.getInstance().getTime()));

// Mon Sep 28
System.out.println( new Date().toString().substring(0, 10) );

// 2015-09-28
System.out.println(new java.sql.Date(System.currentTimeMillis()));

// 2015-09-28
// java 8
System.out.println( LocalDate.now(ZoneId.of("Europe/Paris")) ); // rest zones id in ZoneId class
blueberry0xff
fonte
3

Bem, até onde eu sei, não há maneira mais fácil de conseguir isso se você usar apenas o JDK padrão.

Obviamente, você pode colocar essa lógica no método2 em uma função estática em uma classe auxiliar, como feito aqui no método toBeginningOfTheDay

Em seguida, você pode reduzir o segundo método para:

Calendar cal = Calendar.getInstance();
Calendars.toBeginningOfTheDay(cal);
dateWithoutTime = cal.getTime();

Ou, se você realmente precisa do dia atual nesse formato com tanta frequência, basta envolvê-lo em outro método auxiliar estático, tornando-o uma linha única.

Enduriel
fonte
3

Se tudo o que você deseja é ver a data como "AAAA-MM-DD" sem toda a confusão, por exemplo "Qui 21 de maio às 12:08:18 EDT 2015", basta usar java.sql.Date. Este exemplo obtém a data atual:

new java.sql.Date(System.currentTimeMillis());

Também java.sql.Dateé uma subclasse de java.util.Date.

BigMac66
fonte
3

Se você só precisa da data atual, sem hora, outra opção é:

DateTime.now().withTimeAtStartOfDay()
user3037726
fonte
1
A questão não pedia hora do dia. Seu resultado é um objeto de data e hora que, de fato, possui uma hora do dia, 00:00:00normalmente essa hora (pode variar de fuso horário para anomalias como o horário de verão ). Portanto, como outras respostas observam, a LocalDateclasse é mais apropriada, do Joda-Time (supondo que você esteja fazendo referência ao Joda-Time - o que você deve observar explicitamente ao citar classes que não estão incluídas no Java).
Basil Bourque
3

Use LocalDate.now()e converta em Datecomo abaixo:

Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
Sahil Chhabra
fonte
1
O fuso horário padrão atual da JVM pode mudar a qualquer momento durante o tempo de execução. Qualquer código em qualquer encadeamento de qualquer aplicativo dentro da JVM pode chamar TimeZone.setDefault. Seu código está chamando ZoneId.systemDefaultduas vezes, o primeiro está implícito LocalDate.now()e o segundo é explícito com atStartOfDay. Entre esses dois momentos em tempo de execução, a zona padrão atual pode mudar. Sugiro capturar a zona em uma variável e passar para os dois métodos.
Basil Bourque 28/02
2

Se você precisar da parte da data apenas para fins de eco,

Date d = new Date(); 
String dateWithoutTime = d.toString().substring(0, 10);
manish_s
fonte
1
Eu não acho que este é i18n amigável
Mark Lapasa
2

Que tal isso?

public static Date formatStrictDate(int year, int month, int dayOfMonth) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, month, dayOfMonth, 0, 0, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTime();
}
vitiello.antonio
fonte
1

Confira Veyder-time . É uma alternativa simples e eficiente ao java.util e ao Joda-time. Possui uma API intuitiva e classes que representam datas sozinhas, sem registro de data e hora.

lonerook
fonte
1

A maneira mais direta e direta que faz uso total do enorme TimeZone Database of Java e está correta:

long currentTime = new Date().getTime();
long dateOnly = currentTime + TimeZone.getDefault().getOffset(currentTime);
TomWolk
fonte
1

Aqui está uma solução limpa, sem conversão para string e vice-versa, e também não recalcula o tempo várias vezes quando você redefine cada componente do tempo para zero. Também usa% (módulo) em vez de dividir seguido de multiplicar para evitar a operação dupla.

Ele não requer dependências de terceiros e respeita o fuso horário do objeto Calender transferido. Essa função retorna o momento às 12h no fuso horário da data (calendário) em que você passou.

public static Calendar date_only(Calendar datetime) {
    final long LENGTH_OF_DAY = 24*60*60*1000;
    long millis = datetime.getTimeInMillis();
    long offset = datetime.getTimeZone().getOffset(millis);
    millis = millis - ((millis + offset) % LENGTH_OF_DAY);
    datetime.setTimeInMillis(millis);
    return datetime;
}
Brent Larsen
fonte
Não estou muito convencido de que respeitará o horário de verão (DST)?
VV Ole Ole
0

Prefira não usar bibliotecas de terceiros o máximo possível. Eu sei que essa maneira é mencionada antes, mas aqui está uma boa maneira limpa:

  /*
    Return values:
    -1:    Date1 < Date2
     0:    Date1 == Date2
     1:    Date1 > Date2

    -2:    Error
*/
public int compareDates(Date date1, Date date2)
{
    SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");

    try
    {
        date1 = sdf.parse(sdf.format(date1));
        date2 = sdf.parse(sdf.format(date2));
    }
    catch (ParseException e) {
        e.printStackTrace();
        return -2;
    }

    Calendar cal1 = new GregorianCalendar();
    Calendar cal2 = new GregorianCalendar();

    cal1.setTime(date1);
    cal2.setTime(date2);

    if(cal1.equals(cal2))
    {
        return 0;
    }
    else if(cal1.after(cal2))
    {
        return 1;
    }
    else if(cal1.before(cal2))
    {
        return -1;
    }

    return -2;
}

Bem, não usar GregorianCalendar é talvez uma opção!

ele Ele
fonte
0

Acabei de fazer isso no meu aplicativo:

public static Date getDatePart(Date dateTime) {
    TimeZone tz = TimeZone.getDefault();
    long rawOffset=tz.getRawOffset();
    long dst=(tz.inDaylightTime(dateTime)?tz.getDSTSavings():0);
    long dt=dateTime.getTime()+rawOffset+dst; // add offseet and dst to dateTime
    long modDt=dt % (60*60*24*1000) ;

    return new Date( dt
                    - modDt // substract the rest of the division by a day in milliseconds
                    - rawOffset // substract the time offset (Paris = GMT +1h for example)
                    - dst // If dayLight, substract hours (Paris = +1h in dayLight)
    );
}

API Android nível 1, sem biblioteca externa. Ele respeita a luz do dia e o fuso horário padrão. Sem manipulação de String, então acho que dessa maneira é mais eficiente da CPU que o seu, mas não fiz nenhum teste.

Elloco
fonte
0

Você pode usar o tempo de joda.

private Date dateWitoutTime(Date date){
 return new LocalDate(date).toDate()
}

e você liga com:

Date date = new Date();
System.out.println("Without Time = " + dateWitoutTime(date) + "/n  With time = " + date);
Jesús Sánchez
fonte