¿Cómo obtengo una fecha sin tiempo en Java?

235

Continuando con el programa Java Stack Overflow question para obtener la fecha actual sin marca de tiempo :

¿Cuál es la forma más eficiente de obtener un objeto Date sin la hora? ¿Hay alguna otra manera que estos dos?

// 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();

Actualización :

  1. Sabía sobre Joda-Time ; Solo estoy tratando de evitar una biblioteca adicional para una tarea tan simple (creo). Pero según las respuestas hasta ahora, Joda-Time parece extremadamente popular, por lo que podría considerarlo.

  2. Por eficiente , quiero decir que quiero evitar la Stringcreación de objetos temporales como los usa method 1, mientras tanto method 2parece un truco en lugar de una solución.

Rosdi Kasim
fuente
1
¿Eficiente? ¿Necesita más eficiencia de lo que se proporciona, por ejemplo, por método1?
Johan Sjöberg
2
¿Qué quieres decir con "eficiente"? Una fecha es básicamente una larga mecanografiada, realmente no puedes hacer esto en menos memoria que eso. Si quiere decir "conveniente", el tiempo de JODA es el camino a seguir.
millimoose
3
+1 Exactamente la pregunta que tenía.
Alba Mendez
1
Me gusta el método 2. Cree un método estático en una clase de utilidad y simplemente utilícelo. He sido este enfoque durante años.
Wilson Freitas
1
Nitpicking en su "actualización 1": si fuera "una tarea tan simple", supongo que Sun no habría llegado a una API tan horrenda e ineficiente, y usted (y muchas otras personas) no estaría haciendo esa pregunta en absoluto ;-)
Flávio Etrusco

Respuestas:

108

¿Usted absolutamente tiene a su uso java.util.Date? Yo a fondo recomendamos que utilice Tiempo Joda o el java.timepaquete de Java 8 en su lugar. En particular, aunque la fecha y calendario siempre representan un momento determinado en el tiempo, sin concepto como "sólo una fecha", Joda Time no tiene un tipo que representa este ( LocalDate). Su código será mucho más claro si puede usar tipos que representan lo que realmente está tratando de hacer.

Hay muchas, muchas otras razones para usar Joda Time o en java.timelugar de los java.utiltipos incorporados : generalmente son API mucho mejores. Siempre puede convertir a / desde a java.util.Dateen los límites de su propio código si es necesario, por ejemplo, para la interacción de la base de datos.

Jon Skeet
fuente
75
En aplicaciones empresariales no siempre tenemos la opción de agregar / usar otras bibliotecas. Aprecio el puntero a Joda Time, pero realmente no es una respuesta al problema original de obtener la parte de la fecha usando el Java estándar. Gracias. Votando la respuesta de Chathuranga.
noogrub
3
@noogrub: la respuesta de Chathugranga no responde a la pregunta original, que es sobre cómo obtener un Dateobjeto; esa respuesta formatea una fecha en una cadena, que no es lo mismo. Fundamentalmente, preguntar en qué fecha Datees una pregunta sin sentido sin más información: la zona horaria y el sistema de calendario que está utilizando.
Jon Skeet
77
"En las aplicaciones empresariales no siempre tenemos la opción de agregar / usar otras bibliotecas". De Verdad ? ¿Estás sugiriendo que no puedes usar libs de terceros?
Brian Agnew
3
El comentario de @BrianAgnew noogrub parece estar relacionado con restricciones no tecnológicas, creo
Jose_GD
3
Desde la perspectiva actual: " Joda-Time es la biblioteca de fecha y hora estándar de facto para Java anterior a Java SE 8. Ahora se solicita a los usuarios que migren a java.time (JSR-310)".
Drux
66

Esto es lo que solía obtener la fecha de hoy con la hora establecida en 00:00:00:

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

Date today = new Date();

Date todayWithZeroTime = formatter.parse(formatter.format(today));
Shobbi
fuente
28
¿En qué se diferencia esto del "método 1" ya propuesto en la pregunta original?
Chris
No aborda en qué zona horaria ocurre esto (se deja a la zona horaria predeterminada arbitraria de JVM).
Darrell Teague el
58

Puede usar DateUtils.truncate de la biblioteca Apache Commons.

Ejemplo:

DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)
JoGo
fuente
3
Si va a agregar una nueva biblioteca, deje que sea Joda en lugar de Apache Commons.
Dibbeke
66
+1 @Dibbeke La diferencia no es solo que estaría agregando una biblioteca en lugar de otra. A veces, uno no quiere aprender una biblioteca completamente nueva solo por la tarea trivial de truncar el tiempo de una fecha. O no quiere tener un código que mezcle Fecha / Calendario con fechas de Joda usando a veces lo primero y a veces lo último. O no puede permitirse / justificar la sustitución de todo el código basado en fecha / calendario que funciona bien con otra biblioteca para un propósito tan trivial. Mientras que sugiere Joda es ciertamente buena, ya que es claramente superior y simplemente lo correcto, a veces patadas en la vida real.
SantiBailors
¡Genio! Me ayudó mucho
Thiesen
37

¿Hay alguna otra manera que estos dos?

Sí hay.

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

java.time

Java 8 y posterior viene con el nuevo paquete java.time incorporado. Ver tutorial . Gran parte de la funcionalidad java.time se transfiere a Java 6 y 7 en ThreeTen-Backport y se adapta aún más a Android en ThreeTenABP .

Similar a Joda-Time , java.time ofrece una LocalDateclase para representar un valor de solo fecha sin hora del día y sin zona horaria.

Tenga en cuenta que la zona horaria es crítica para determinar una fecha en particular. A la medianoche en París, por ejemplo, la fecha todavía es "ayer" en Montreal.

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

De forma predeterminada, java.time utiliza el estándar ISO 8601 para generar una representación de cadena de una fecha o valor de fecha y hora. (Otra similitud con Joda-Time.) Simplemente llame toString()para generar texto como 2015-05-21.

String output = today.toString() ; 

Sobre java.time

El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como java.util.Date, Calendar, y SimpleDateFormat.

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .

¿Dónde obtener las clases java.time?

  • Java SE 8 , Java SE 9 y posterior
    • Incorporado.
    • Parte de la API Java estándar con una implementación integrada.
    • Java 9 agrega algunas características menores y correcciones.
  • Java SE 6 y Java SE 7
    • Gran parte de la funcionalidad java.time se transfiere a Java 6 y 7 en ThreeTen-Backport .
  • Androide
    • Versiones posteriores de las implementaciones de paquetes de Android de las clases java.time.
    • Para principios de Android, el ThreeTenABP proyecto se adapta ThreeTen-Backport (mencionado anteriormente). Ver Cómo utilizar ThreeTenABP ... .

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time. Usted puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter, y más .

Albahaca Bourque
fuente
1
Gracias por mencionar la zona horaria . No se me había ocurrido que "qué día es" no es un concepto absoluto.
ToolmakerSteve
@ToolmakerSteve Obtener la fecha siempre implica una zona horaria. Pero el truco es que si no especifica una zona horaria, la zona horaria predeterminada actual de su JVM se aplica automáticamente para determinar la fecha. Además de eso, la zona horaria predeterminada actual de la JVM puede cambiar en cualquier momento . Cualquier código en cualquier subproceso de cualquier aplicación dentro de la JVM puede llamar TimeZone.setDefaultdurante el tiempo de ejecución y afectar inmediatamente a todos los demás códigos que se ejecutan en esa JVM. Moraleja de la historia: siempre especifique una zona horaria.
Basil Bourque
22

La forma más directa:

long millisInDay = 60 * 60 * 24 * 1000;
long currentTime = new Date().getTime();
long dateOnly = (currentTime / millisInDay) * millisInDay;
Date clearDate = new Date(dateOnly);
romano
fuente
55
Para mí, esto es actualmente: "Sáb 19 de febrero 01 : 00: 00 CET 2011". Si quieres usar eso, solo con UTC.
Chris Lercher
44
¿No es la línea 3 long dateOnly = (currentTime / millisInDay) * millisInDay;lo mismo que escribir long dateOnly = currentTime;?
Chris
55
No lo es, debido a la matemática entera. Piénselo más como Math.floor (currentTime / millisInDay) * millisInDay. Está configurando efectivamente la hora a las 00:00:00 de esa manera.
Nicholas Flynt
2
Esta solución probablemente sea adecuada para la mayoría de las aplicaciones, pero tenga en cuenta que un día tiene 60 * 60 * 24 * 1000 no siempre es cierto. Por ejemplo, puede tener segundos bisiestos en algunos días.
Pierre-Antoine
1
Esta es posiblemente la forma más obtusa y no recomendada sobre otros métodos claros y concisos de 1 y 2 líneas.
Darrell Teague el
22

La respuesta estándar a estas preguntas es usar Joda Time . La API es mejor y si está utilizando formateadores y analizadores puede evitar la falta no intuitiva de seguridad de subprocesos SimpleDateFormat.

Usar Joda significa que simplemente puedes hacer:

LocalDate d = new LocalDate();

Actualización :: Usando java 8 esto se puede lograr usando

LocalDate date = LocalDate.now();
Brian Agnew
fuente
El nuevo paquete java.time en Java 8 también ofrece una LocalDateclase similar a Joda-Time.
Basil Bourque
1
Lo ideal sería pasar un DateTimeZoneconstructor de LocalDate. La determinación de la fecha actual depende de la zona horaria, ya que París comienza una nueva fecha anterior a Montreal. Si omite la zona horaria, se aplica la zona horaria predeterminada de su JVM. Por lo general, es mejor especificar que confiar en el valor predeterminado.
Basil Bourque
8

Esta es una manera simple de hacerlo:

Calendar cal = Calendar.getInstance();
SimpleDateFormat dateOnly = new SimpleDateFormat("MM/dd/yyyy");
System.out.println(dateOnly.format(cal.getTime()));
Cañada
fuente
44
Esta respuesta no responde a la pregunta. Obtener una cadena formateada no era el objetivo.
Basil Bourque
7

No tiene sentido hablar de una fecha sin una marca de tiempo con respecto a las rutinas de fecha en el tiempo de ejecución estándar de Java, ya que esencialmente se asigna a un milisegundo específico y no a una fecha. Dicho milisegundo tiene intrínsecamente una hora del día que lo hace vulnerable a problemas de zona horaria como el horario de verano y otros ajustes de calendario. Ver ¿Por qué restar estas dos veces (en 1927) está dando un resultado extraño? Por un ejemplo interesante.

Si desea trabajar con fechas en lugar de milisegundos, debe usar otra cosa. Para Java 8 hay un nuevo conjunto de métodos que proporcionan exactamente lo que solicita. Para Java 7 y versiones anteriores, use http://www.joda.org/joda-time/

Thorbjørn Ravn Andersen
fuente
3
Nota: Los enfoques que dicen "la fecha a la medianoche" no manejan bien el horario de verano y las zonas horarias múltiples.
Thorbjørn Ravn Andersen
Lo confirmo, estaba incrementando las fechas en un día en mi aplicación, y aprendí sobre esto con un informe de error de los usuarios en una zona horaria con DST (mi país no usa DST). En el día en que comienza el horario de verano, mi aplicación agrega 11 horas en lugar de 12. ¿Quizás sea mejor usar el mediodía como la hora para una fecha "sin hora"?
Jose_GD
1
@Jose_GD En el mejor de los casos, sigue siendo un hack. Puede encontrar youtube.com/watch?v=-5wpm-gesOY entretenido.
Thorbjørn Ravn Andersen
@ Thorbjorn, tienes razón, solo quería evitar JodaTime porque agregar una biblioteca para una sola característica me parece excesivo. Sabía sobre ese video, realmente divertido.
Jose_GD
1
@Jose_GD El punto era que hay un caso de uso real en el que su enfoque se consideraría un error. Si encontraste uno, podría haber más ... No sé cómo Joda maneja esto, pero podrías echar un vistazo. También tenga en cuenta que Java 8 trae una nueva biblioteca de fecha y hora (basada en las experiencias con Joda) que es posible que desee examinar.
Thorbjørn Ravn Andersen
4

Definitivamente no es la forma más correcta, pero si solo necesita una solución rápida para obtener la fecha sin la hora y no desea utilizar una biblioteca de terceros, esto debería hacerlo

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

Solo necesitaba la fecha para fines visuales y no podía Joda, así que me limité.

Bamz
fuente
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
fuente
3

Bueno, hasta donde sé, no hay una manera más fácil de lograr esto si solo usa el JDK estándar.

Por supuesto, puede poner esa lógica en el método 2 en una función estática en una clase auxiliar, como se hace aquí en el método toBeginningOfTheDay

Entonces puedes acortar el segundo método para:

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

O bien, si realmente necesita el día actual en este formato con tanta frecuencia, puede envolverlo en otro método auxiliar estático, lo que lo convierte en una línea.

Enduriel
fuente
3

Si todo lo que quiere es ver la fecha así "AAAA-MM-DD" sin todo el desorden, por ejemplo, "jue 21 de mayo 12:08:18 EDT 2015", entonces simplemente use java.sql.Date. Este ejemplo obtiene la fecha actual:

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

También java.sql.Datees una subclase de java.util.Date.

BigMac66
fuente
3

Si solo necesita la fecha actual, sin hora, otra opción es:

DateTime.now().withTimeAtStartOfDay()
usuario3037726
fuente
1
La pregunta no pedía ninguna hora del día. Su resultado es un objeto de fecha y hora que sí tiene una hora del día, por lo 00:00:00general , ese tiempo (puede variar según la zona horaria para anomalías como el horario de verano) ). Entonces, como señalan otras Respuestas, la LocalDateclase es más apropiada, desde Joda-Time (suponiendo que hace referencia a Joda-Time, que debe tener en cuenta explícitamente al citar clases no incluidas en Java).
Basil Bourque
3

Use LocalDate.now()y convierta en lo Datesiguiente:

Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
Sahil Chhabra
fuente
1
La zona horaria predeterminada actual de la JVM puede cambiar en cualquier momento durante el tiempo de ejecución. Cualquier código en cualquier subproceso de cualquier aplicación dentro de la JVM puede llamar TimeZone.setDefault. Su código está llamando ZoneId.systemDefaultdos veces, el primero está implícito LocalDate.now()y el segundo es explícito con atStartOfDay. Entre esos dos momentos en tiempo de ejecución, la zona predeterminada actual podría cambiar. Sugiero capturar la zona en una variable y pasar a ambos métodos.
Basil Bourque
2

Si necesita la parte de fecha solo para hacer eco, entonces

Date d = new Date(); 
String dateWithoutTime = d.toString().substring(0, 10);
manish_s
fuente
1
No creo que esto sea amigable
Mark Lapasa
2

¿Qué hay de esto?

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
fuente
1

Echa un vistazo a Veyder-time . Es una alternativa simple y eficiente tanto para java.util como para Joda-time. Tiene una API intuitiva y clases que representan fechas solas, sin marcas de tiempo.

lonerook
fuente
1

La forma más directa que hace uso completo de la enorme base de datos TimeZone de Java y es correcta:

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

Aquí hay una solución limpia sin conversión a cadena y viceversa, y tampoco vuelve a calcular el tiempo varias veces a medida que restablece cada componente del tiempo a cero. También usa% (módulo) en lugar de dividir seguido de multiplicar para evitar la doble operación.

No requiere dependencias de terceros, y RESPETE EL TIMEZONE OF the Calender que se pasó. Esta función devuelve el momento en el tiempo a las 12 AM en la zona horaria de la fecha (Calendario) que pasa.

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
fuente
No estoy muy convencido de que respetará el horario de verano (DST).
Ole VV
0

Prefiero no usar bibliotecas de terceros tanto como sea posible. Sé que esta manera se menciona antes, pero aquí hay una manera limpia y agradable:

  /*
    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;
}

Bueno, ¡no usar GregorianCalendar es quizás una opción!

jeje
fuente
0

Acabo de hacer esto para mi aplicación:

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)
    );
}

Android API nivel 1, sin biblioteca externa. Respeta la luz del día y la zona horaria predeterminada. Sin manipulación de cadenas, así que creo que de esta manera es más eficiente la CPU que la suya, pero no he realizado ninguna prueba.

Elloco
fuente
0

Puedes usar el tiempo joda.

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

y llamas con:

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