En Ruby on Rails, hay una función que le permite tomar cualquier Fecha e imprimir cuánto tiempo hace.
Por ejemplo:
8 minutes ago
8 hours ago
8 days ago
8 months ago
8 years ago
¿Hay una manera fácil de hacer esto en Java?
En Ruby on Rails, hay una función que le permite tomar cualquier Fecha e imprimir cuánto tiempo hace.
Por ejemplo:
8 minutes ago
8 hours ago
8 days ago
8 months ago
8 years ago
¿Hay una manera fácil de hacer esto en Java?
Respuestas:
Echa un vistazo a la biblioteca PrettyTime .
Es bastante simple de usar:
import org.ocpsoft.prettytime.PrettyTime;
PrettyTime p = new PrettyTime();
System.out.println(p.format(new Date()));
// prints "moments ago"
También puede pasar una configuración regional para mensajes internacionalizados:
PrettyTime p = new PrettyTime(new Locale("fr"));
System.out.println(p.format(new Date()));
// prints "à l'instant"
Como se señaló en los comentarios, Android tiene esta funcionalidad integrada en la android.text.format.DateUtils
clase.
¿Has considerado la enumeración de TimeUnit ? Puede ser bastante útil para este tipo de cosas.
try {
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
Date past = format.parse("01/10/2010");
Date now = new Date();
System.out.println(TimeUnit.MILLISECONDS.toMillis(now.getTime() - past.getTime()) + " milliseconds ago");
System.out.println(TimeUnit.MILLISECONDS.toMinutes(now.getTime() - past.getTime()) + " minutes ago");
System.out.println(TimeUnit.MILLISECONDS.toHours(now.getTime() - past.getTime()) + " hours ago");
System.out.println(TimeUnit.MILLISECONDS.toDays(now.getTime() - past.getTime()) + " days ago");
}
catch (Exception j){
j.printStackTrace();
}
Tomo las respuestas de RealHowTo y Ben J y hago mi propia versión:
public class TimeAgo {
public static final List<Long> times = Arrays.asList(
TimeUnit.DAYS.toMillis(365),
TimeUnit.DAYS.toMillis(30),
TimeUnit.DAYS.toMillis(1),
TimeUnit.HOURS.toMillis(1),
TimeUnit.MINUTES.toMillis(1),
TimeUnit.SECONDS.toMillis(1) );
public static final List<String> timesString = Arrays.asList("year","month","day","hour","minute","second");
public static String toDuration(long duration) {
StringBuffer res = new StringBuffer();
for(int i=0;i< TimeAgo.times.size(); i++) {
Long current = TimeAgo.times.get(i);
long temp = duration/current;
if(temp>0) {
res.append(temp).append(" ").append( TimeAgo.timesString.get(i) ).append(temp != 1 ? "s" : "").append(" ago");
break;
}
}
if("".equals(res.toString()))
return "0 seconds ago";
else
return res.toString();
}
public static void main(String args[]) {
System.out.println(toDuration(123));
System.out.println(toDuration(1230));
System.out.println(toDuration(12300));
System.out.println(toDuration(123000));
System.out.println(toDuration(1230000));
System.out.println(toDuration(12300000));
System.out.println(toDuration(123000000));
System.out.println(toDuration(1230000000));
System.out.println(toDuration(12300000000L));
System.out.println(toDuration(123000000000L));
}}
que imprimirá lo siguiente
0 second ago
1 second ago
12 seconds ago
2 minutes ago
20 minutes ago
3 hours ago
1 day ago
14 days ago
4 months ago
3 years ago
.append(temp != 1 ? "s" : "")
lugar de .append(temp > 1 ? "s" : "")
porque 0 también debería tener s
sufijo
public class TimeUtils {
public final static long ONE_SECOND = 1000;
public final static long SECONDS = 60;
public final static long ONE_MINUTE = ONE_SECOND * 60;
public final static long MINUTES = 60;
public final static long ONE_HOUR = ONE_MINUTE * 60;
public final static long HOURS = 24;
public final static long ONE_DAY = ONE_HOUR * 24;
private TimeUtils() {
}
/**
* converts time (in milliseconds) to human-readable format
* "<w> days, <x> hours, <y> minutes and (z) seconds"
*/
public static String millisToLongDHMS(long duration) {
StringBuffer res = new StringBuffer();
long temp = 0;
if (duration >= ONE_SECOND) {
temp = duration / ONE_DAY;
if (temp > 0) {
duration -= temp * ONE_DAY;
res.append(temp).append(" day").append(temp > 1 ? "s" : "")
.append(duration >= ONE_MINUTE ? ", " : "");
}
temp = duration / ONE_HOUR;
if (temp > 0) {
duration -= temp * ONE_HOUR;
res.append(temp).append(" hour").append(temp > 1 ? "s" : "")
.append(duration >= ONE_MINUTE ? ", " : "");
}
temp = duration / ONE_MINUTE;
if (temp > 0) {
duration -= temp * ONE_MINUTE;
res.append(temp).append(" minute").append(temp > 1 ? "s" : "");
}
if (!res.toString().equals("") && duration >= ONE_SECOND) {
res.append(" and ");
}
temp = duration / ONE_SECOND;
if (temp > 0) {
res.append(temp).append(" second").append(temp > 1 ? "s" : "");
}
return res.toString();
} else {
return "0 second";
}
}
public static void main(String args[]) {
System.out.println(millisToLongDHMS(123));
System.out.println(millisToLongDHMS((5 * ONE_SECOND) + 123));
System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR));
System.out.println(millisToLongDHMS(ONE_DAY + 2 * ONE_SECOND));
System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR + (2 * ONE_MINUTE)));
System.out.println(millisToLongDHMS((4 * ONE_DAY) + (3 * ONE_HOUR)
+ (2 * ONE_MINUTE) + ONE_SECOND));
System.out.println(millisToLongDHMS((5 * ONE_DAY) + (4 * ONE_HOUR)
+ ONE_MINUTE + (23 * ONE_SECOND) + 123));
System.out.println(millisToLongDHMS(42 * ONE_DAY));
/*
output :
0 second
5 seconds
1 day, 1 hour
1 day and 2 seconds
1 day, 1 hour, 2 minutes
4 days, 3 hours, 2 minutes and 1 second
5 days, 4 hours, 1 minute and 23 seconds
42 days
*/
}
}
more @ Formatee una duración en milisegundos en un formato legible para humanos
Esto se basa en la respuesta de RealHowTo, así que si te gusta, dale un poco de amor también.
Esta versión limpia le permite especificar el rango de tiempo que le puede interesar.
También maneja la parte "y" un poco diferente. A menudo encuentro que al unir cadenas con un delimitador es más fácil omitir la lógica complicada y simplemente borrar el último delimitador cuando haya terminado.
import java.util.concurrent.TimeUnit;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
public class TimeUtils {
/**
* Converts time to a human readable format within the specified range
*
* @param duration the time in milliseconds to be converted
* @param max the highest time unit of interest
* @param min the lowest time unit of interest
*/
public static String formatMillis(long duration, TimeUnit max, TimeUnit min) {
StringBuilder res = new StringBuilder();
TimeUnit current = max;
while (duration > 0) {
long temp = current.convert(duration, MILLISECONDS);
if (temp > 0) {
duration -= current.toMillis(temp);
res.append(temp).append(" ").append(current.name().toLowerCase());
if (temp < 2) res.deleteCharAt(res.length() - 1);
res.append(", ");
}
if (current == min) break;
current = TimeUnit.values()[current.ordinal() - 1];
}
// clean up our formatting....
// we never got a hit, the time is lower than we care about
if (res.lastIndexOf(", ") < 0) return "0 " + min.name().toLowerCase();
// yank trailing ", "
res.deleteCharAt(res.length() - 2);
// convert last ", " to " and"
int i = res.lastIndexOf(", ");
if (i > 0) {
res.deleteCharAt(i);
res.insert(i, " and");
}
return res.toString();
}
}
Pequeño código para darle un giro:
import static java.util.concurrent.TimeUnit.*;
public class Main {
public static void main(String args[]) {
long[] durations = new long[]{
123,
SECONDS.toMillis(5) + 123,
DAYS.toMillis(1) + HOURS.toMillis(1),
DAYS.toMillis(1) + SECONDS.toMillis(2),
DAYS.toMillis(1) + HOURS.toMillis(1) + MINUTES.toMillis(2),
DAYS.toMillis(4) + HOURS.toMillis(3) + MINUTES.toMillis(2) + SECONDS.toMillis(1),
DAYS.toMillis(5) + HOURS.toMillis(4) + MINUTES.toMillis(1) + SECONDS.toMillis(23) + 123,
DAYS.toMillis(42)
};
for (long duration : durations) {
System.out.println(TimeUtils.formatMillis(duration, DAYS, SECONDS));
}
System.out.println("\nAgain in only hours and minutes\n");
for (long duration : durations) {
System.out.println(TimeUtils.formatMillis(duration, HOURS, MINUTES));
}
}
}
Lo que generará lo siguiente:
0 seconds
5 seconds
1 day and 1 hour
1 day and 2 seconds
1 day, 1 hour and 2 minutes
4 days, 3 hours, 2 minutes and 1 second
5 days, 4 hours, 1 minute and 23 seconds
42 days
Again in only hours and minutes
0 minutes
0 minutes
25 hours
24 hours
25 hours and 2 minutes
99 hours and 2 minutes
124 hours and 1 minute
1008 hours
Y en caso de que alguien lo necesite, aquí hay una clase que convertirá cualquier cadena como la anterior nuevamente en milisegundos . Es bastante útil para permitir que las personas especifiquen tiempos de espera de varias cosas en texto legible.
Hay una manera simple de hacer esto:
Digamos que quieres el tiempo hace 20 minutos:
Long minutesAgo = new Long(20);
Date date = new Date();
Date dateIn_X_MinAgo = new Date (date.getTime() - minutesAgo*60*1000);
Eso es..
Sobre soluciones integradas :
Java no tiene soporte incorporado para formatear tiempos relativos, tampoco Java-8 y su nuevo paquete java.time
. Si solo necesita inglés y nada más y solo entonces una solución hecha a mano podría ser aceptable, vea la respuesta de @RealHowTo (aunque tiene la gran desventaja de no tener en cuenta la zona horaria para la traducción de deltas instantáneos a la hora local) ¡unidades!). De todos modos, si desea evitar soluciones alternativas complejas, especialmente para otras configuraciones regionales, necesita una biblioteca externa.
En este último caso, recomiendo usar mi biblioteca Time4J (o Time4A en Android). Ofrece la mayor flexibilidad y la mayor potencia i18n . La clase net.time4j.PrettyTime tiene siete métodos printRelativeTime...(...)
para este propósito. Ejemplo usando un reloj de prueba como fuente de tiempo:
TimeSource<?> clock = () -> PlainTimestamp.of(2015, 8, 1, 10, 24, 5).atUTC();
Moment moment = PlainTimestamp.of(2015, 8, 1, 17, 0).atUTC(); // our input
String durationInDays =
PrettyTime.of(Locale.GERMAN).withReferenceClock(clock).printRelative(
moment,
Timezone.of(EUROPE.BERLIN),
TimeUnit.DAYS); // controlling the precision
System.out.println(durationInDays); // heute (german word for today)
Otro ejemplo usando java.time.Instant
como entrada:
String relativeTime =
PrettyTime.of(Locale.ENGLISH)
.printRelativeInStdTimezone(Moment.from(Instant.EPOCH));
System.out.println(relativeTime); // 45 years ago
Esta biblioteca admite a través de su última versión (v4.17) 80 idiomas y también algunas configuraciones regionales específicas del país (especialmente para español, inglés, árabe, francés). Los datos i18n se basan principalmente en la versión más reciente de CLDR v29 . Otras razones importantes por las que usar esta biblioteca son un buen soporte para reglas plurales (que a menudo son diferentes del inglés en otros idiomas), un estilo de formato abreviado (por ejemplo: "Hace 1 segundo") y formas expresivas para tener en cuenta las zonas horarias . Time4J incluso es consciente de detalles tan exóticos como segundos intercalares en los cálculos de tiempos relativos (no es realmente importante, pero forma un mensaje relacionado con el horizonte de expectativas). La compatibilidad con Java-8existe debido a los métodos de conversión fácilmente disponibles para tipos como java.time.Instant
o java.time.Period
.
¿Hay algún inconveniente? Sólo dos.
Alternativas (compactas):
Si busca una solución más pequeña y no necesita tantas funciones y está dispuesto a tolerar posibles problemas de calidad relacionados con i18n-data, entonces:
Recomendaría ocpsoft / PrettyTime (soporte para actualmente 32 idiomas (¿pronto 34?) Adecuados para trabajar java.util.Date
solo; vea la respuesta de @ataylor). Desafortunadamente, el CLDR estándar de la industria (del consorcio Unicode) con su gran experiencia en la comunidad no es una base de los datos i18n, por lo que otras mejoras o mejoras de datos pueden tomar un tiempo ...
Si está en Android, entonces la clase auxiliar android.text.format.DateUtils es una alternativa incorporada delgada (vea otros comentarios y respuestas aquí, con la desventaja de que no tiene soporte durante años y meses. Y estoy seguro de que solo A muy pocas personas les gusta el estilo API de esta clase auxiliar.
Si eres fanático de Joda-Time, entonces puedes ver su clase PeriodFormat (soporte para 14 idiomas en la versión v2.9.4, por otro lado: Joda-Time seguramente tampoco es compacto, así que lo menciono aquí solo por lo completo). Esta biblioteca no es una respuesta real porque los tiempos relativos no son compatibles en absoluto. Necesitará agregar el literal "ago" al menos (y eliminar manualmente todas las unidades inferiores de los formatos de lista generados, incómodo). A diferencia de Time4J o Android-DateUtils, no tiene soporte especial para abreviaturas o cambio automático de tiempos relativos a representaciones de tiempo absoluto. Al igual que PrettyTime, depende totalmente de las contribuciones no confirmadas de los miembros privados de la comunidad Java a sus datos i18n.
Usando el framework java.time integrado en Java 8 y posterior.
LocalDateTime t1 = LocalDateTime.of(2015, 1, 1, 0, 0, 0);
LocalDateTime t2 = LocalDateTime.now();
Period period = Period.between(t1.toLocalDate(), t2.toLocalDate());
Duration duration = Duration.between(t1, t2);
System.out.println("First January 2015 is " + period.getYears() + " years ago");
System.out.println("First January 2015 is " + period.getMonths() + " months ago");
System.out.println("First January 2015 is " + period.getDays() + " days ago");
System.out.println("First January 2015 is " + duration.toHours() + " hours ago");
System.out.println("First January 2015 is " + duration.toMinutes() + " minutes ago");
Duration
métodos informan la duración completa como un número total de horas y como un número total de minutos. En Java 8, la clase extrañamente carecía de métodos para obtener cada parte de hora, minutos y segundos. Java 9 trae esos métodos, to…Part
.
Creé un puerto Java timeago simple del complemento jquery-timeago que hace lo que está pidiendo.
TimeAgo time = new TimeAgo();
String minutes = time.timeAgo(System.currentTimeMillis() - (15*60*1000)); // returns "15 minutes ago"
En caso de que esté desarrollando una aplicación para Android, proporciona la clase de utilidad DateUtils para todos esos requisitos. Eche un vistazo al método de utilidad DateUtils # getRelativeTimeSpanString () .
De los documentos para
CharSequence getRelativeTimeSpanString (mucho tiempo, mucho tiempo, mucho tiempo minResolution)
Devuelve una cadena que describe 'tiempo' como un tiempo relativo a 'ahora'. Los períodos de tiempo en el pasado están formateados como "hace 42 minutos". Los períodos de tiempo en el futuro están formateados como "En 42 minutos".
Se le pasa en tu timestamp
como el tiempo y System.currentTimeMillis()
como ahora . Le minResolution
permite especificar el intervalo de tiempo mínimo para informar.
Por ejemplo, un tiempo de 3 segundos en el pasado se informará como "hace 0 minutos" si se establece en MINUTE_IN_MILLIS. Pase uno de 0, MINUTE_IN_MILLIS, HOUR_IN_MILLIS, DAY_IN_MILLIS, WEEK_IN_MILLIS, etc.
Puede usar esta función para calcular hace tiempo
private String timeAgo(long time_ago) {
long cur_time = (Calendar.getInstance().getTimeInMillis()) / 1000;
long time_elapsed = cur_time - time_ago;
long seconds = time_elapsed;
int minutes = Math.round(time_elapsed / 60);
int hours = Math.round(time_elapsed / 3600);
int days = Math.round(time_elapsed / 86400);
int weeks = Math.round(time_elapsed / 604800);
int months = Math.round(time_elapsed / 2600640);
int years = Math.round(time_elapsed / 31207680);
// Seconds
if (seconds <= 60) {
return "just now";
}
//Minutes
else if (minutes <= 60) {
if (minutes == 1) {
return "one minute ago";
} else {
return minutes + " minutes ago";
}
}
//Hours
else if (hours <= 24) {
if (hours == 1) {
return "an hour ago";
} else {
return hours + " hrs ago";
}
}
//Days
else if (days <= 7) {
if (days == 1) {
return "yesterday";
} else {
return days + " days ago";
}
}
//Weeks
else if (weeks <= 4.3) {
if (weeks == 1) {
return "a week ago";
} else {
return weeks + " weeks ago";
}
}
//Months
else if (months <= 12) {
if (months == 1) {
return "a month ago";
} else {
return months + " months ago";
}
}
//Years
else {
if (years == 1) {
return "one year ago";
} else {
return years + " years ago";
}
}
}
1) Aquí time_ago está en microsegundo
Basado en un montón de respuestas aquí, creé lo siguiente para mi caso de uso.
Ejemplo de uso:
String relativeDate = String.valueOf(
TimeUtils.getRelativeTime( 1000L * myTimeInMillis() ));
import java.util.Arrays;
import java.util.List;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* Utilities for dealing with dates and times
*/
public class TimeUtils {
public static final List<Long> times = Arrays.asList(
DAYS.toMillis(365),
DAYS.toMillis(30),
DAYS.toMillis(7),
DAYS.toMillis(1),
HOURS.toMillis(1),
MINUTES.toMillis(1),
SECONDS.toMillis(1)
);
public static final List<String> timesString = Arrays.asList(
"yr", "mo", "wk", "day", "hr", "min", "sec"
);
/**
* Get relative time ago for date
*
* NOTE:
* if (duration > WEEK_IN_MILLIS) getRelativeTimeSpanString prints the date.
*
* ALT:
* return getRelativeTimeSpanString(date, now, SECOND_IN_MILLIS, FORMAT_ABBREV_RELATIVE);
*
* @param date String.valueOf(TimeUtils.getRelativeTime(1000L * Date/Time in Millis)
* @return relative time
*/
public static CharSequence getRelativeTime(final long date) {
return toDuration( Math.abs(System.currentTimeMillis() - date) );
}
private static String toDuration(long duration) {
StringBuilder sb = new StringBuilder();
for(int i=0;i< times.size(); i++) {
Long current = times.get(i);
long temp = duration / current;
if (temp > 0) {
sb.append(temp)
.append(" ")
.append(timesString.get(i))
.append(temp > 1 ? "s" : "")
.append(" ago");
break;
}
}
return sb.toString().isEmpty() ? "now" : sb.toString();
}
}
El paquete joda-time , tiene la noción de períodos . Puedes hacer aritmética con Periodos y DateTimes.
De los documentos :
public boolean isRentalOverdue(DateTime datetimeRented) {
Period rentalPeriod = new Period().withDays(2).withHours(12);
return datetimeRented.plus(rentalPeriod).isBeforeNow();
}
No es bonito ... pero lo más parecido que puedo pensar es usar Joda-Time (como se describe en esta publicación: ¿Cómo calcular el tiempo transcurrido desde ahora con Joda Time?
Este es un código mejor si consideramos el rendimiento. Reduce la cantidad de cálculos. Motivo Los minutos se calculan solo si el número de segundos es mayor que 60 y las Horas se calculan solo si el número de minutos es mayor que 60 y así sucesivamente ...
class timeAgo {
static String getTimeAgo(long time_ago) {
time_ago=time_ago/1000;
long cur_time = (Calendar.getInstance().getTimeInMillis())/1000 ;
long time_elapsed = cur_time - time_ago;
long seconds = time_elapsed;
// Seconds
if (seconds <= 60) {
return "Just now";
}
//Minutes
else{
int minutes = Math.round(time_elapsed / 60);
if (minutes <= 60) {
if (minutes == 1) {
return "a minute ago";
} else {
return minutes + " minutes ago";
}
}
//Hours
else {
int hours = Math.round(time_elapsed / 3600);
if (hours <= 24) {
if (hours == 1) {
return "An hour ago";
} else {
return hours + " hrs ago";
}
}
//Days
else {
int days = Math.round(time_elapsed / 86400);
if (days <= 7) {
if (days == 1) {
return "Yesterday";
} else {
return days + " days ago";
}
}
//Weeks
else {
int weeks = Math.round(time_elapsed / 604800);
if (weeks <= 4.3) {
if (weeks == 1) {
return "A week ago";
} else {
return weeks + " weeks ago";
}
}
//Months
else {
int months = Math.round(time_elapsed / 2600640);
if (months <= 12) {
if (months == 1) {
return "A month ago";
} else {
return months + " months ago";
}
}
//Years
else {
int years = Math.round(time_elapsed / 31207680);
if (years == 1) {
return "One year ago";
} else {
return years + " years ago";
}
}
}
}
}
}
}
}
}
La respuesta de Habsq tiene la idea correcta pero los métodos incorrectos.
Para un período de tiempo no conectado a la línea de tiempo en la escala de años-meses-días, use Period
. Para los días que significan fragmentos de tiempo de 24 horas no relacionados con el calendario y las horas-minutos-segundos, use Duration
. Mezclar las dos escalas rara vez tiene sentido.
Duration
Comience buscando el momento actual como se ve en UTC , utilizando la Instant
clase.
Instant now = Instant.now(); // Capture the current moment as seen in UTC.
Instant then = now.minus( 8L , ChronoUnit.HOURS ).minus( 8L , ChronoUnit.MINUTES ).minus( 8L , ChronoUnit.SECONDS );
Duration d = Duration.between( then , now );
Genera texto por horas, minutos y segundos.
// Generate text by calling `to…Part` methods.
String output = d.toHoursPart() + " hours ago\n" + d.toMinutesPart() + " minutes ago\n" + d.toSecondsPart() + " seconds ago";
Volcado a la consola.
System.out.println( "From: " + then + " to: " + now );
System.out.println( output );
Desde: 2019-06-04T11: 53: 55.714965Z hasta: 2019-06-04T20: 02: 03.714965Z
Hace 8 horas
Hace 8 minutos
Hace 8 segundos
Period
Comience por obtener la fecha actual.
Una zona horaria es crucial para determinar una fecha. Para cualquier momento dado, la fecha varía en todo el mundo por zona. Por ejemplo, unos minutos después de la medianoche en París, Francia es un nuevo día mientras todavía "ayer" en Montreal Québec .
Si no se especifica una zona horaria, la JVM aplica implícitamente su zona horaria predeterminada actual. Ese valor predeterminado puede cambiar en cualquier momento durante el tiempo de ejecución (!), Por lo que sus resultados pueden variar. Es mejor especificar su zona horaria deseada / esperada explícitamente como argumento. Si es crítico, confirme la zona con su usuario.
Especificar un nombre de zona horaria correcta en el formato de Continent/Region
, por ejemplo America/Montreal
, Africa/Casablanca
o Pacific/Auckland
. Nunca use el 2-4 abreviatura de letras tales como EST
o IST
, ya que son no verdaderas zonas de tiempo, no estandarizados, y ni siquiera único (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Recrea una fecha hace ocho días, meses y años.
LocalDate then = today.minusYears( 8 ).minusMonths( 8 ).minusDays( 7 ); // Notice the 7 days, not 8, because of granularity of months.
Calcular el tiempo transcurrido.
Period p = Period.between( then , today );
Construye la cadena de piezas de "tiempo atrás".
String output = p.getDays() + " days ago\n" + p.getMonths() + " months ago\n" + p.getYears() + " years ago";
Volcado a la consola.
System.out.println( "From: " + then + " to: " + today );
System.out.println( output );
Desde: 2010-09-27 hasta: 2019-06-04
hace 8 días
hace 8 meses
Hace 8 años
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
.
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 .
El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .
Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No hay necesidad de cadenas, no hay necesidad de java.sql.*
clases.
¿Dónde obtener las clases java.time?
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 .
Después de una larga investigación, encontré esto.
public class GetTimeLapse {
public static String getlongtoago(long createdAt) {
DateFormat userDateFormat = new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy");
DateFormat dateFormatNeeded = new SimpleDateFormat("MM/dd/yyyy HH:MM:SS");
Date date = null;
date = new Date(createdAt);
String crdate1 = dateFormatNeeded.format(date);
// Date Calculation
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
crdate1 = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(date);
// get current date time with Calendar()
Calendar cal = Calendar.getInstance();
String currenttime = dateFormat.format(cal.getTime());
Date CreatedAt = null;
Date current = null;
try {
CreatedAt = dateFormat.parse(crdate1);
current = dateFormat.parse(currenttime);
} catch (java.text.ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Get msec from each, and subtract.
long diff = current.getTime() - CreatedAt.getTime();
long diffSeconds = diff / 1000;
long diffMinutes = diff / (60 * 1000) % 60;
long diffHours = diff / (60 * 60 * 1000) % 24;
long diffDays = diff / (24 * 60 * 60 * 1000);
String time = null;
if (diffDays > 0) {
if (diffDays == 1) {
time = diffDays + "day ago ";
} else {
time = diffDays + "days ago ";
}
} else {
if (diffHours > 0) {
if (diffHours == 1) {
time = diffHours + "hr ago";
} else {
time = diffHours + "hrs ago";
}
} else {
if (diffMinutes > 0) {
if (diffMinutes == 1) {
time = diffMinutes + "min ago";
} else {
time = diffMinutes + "mins ago";
}
} else {
if (diffSeconds > 0) {
time = diffSeconds + "secs ago";
}
}
}
}
return time;
}
}
Para Android Exactamente como dijo Ravi, pero dado que muchas personas solo quieren copiar y pegar la cosa aquí está.
try {
SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
Date dt = formatter.parse(date_from_server);
CharSequence output = DateUtils.getRelativeTimeSpanString (dt.getTime());
your_textview.setText(output.toString());
} catch (Exception ex) {
ex.printStackTrace();
your_textview.setText("");
}
Explicación para las personas que tienen más tiempo.
Ex. Recibo los datos de un servidor en el formato Mié, 27 de enero de 2016 09:32:35 GMT [este probablemente NO sea su caso]
esto se traduce en
SimpleDateFormat formatter = new SimpleDateFormat ("EEE, dd MMM aaaa HH: mm: ss Z");
como lo se Lea la documentación aquí.
Luego, después de analizarlo, tengo una cita. esa fecha la puse en getRelativeTimeSpanString (sin ningún parámetro adicional, estoy bien, por defecto a minutos)
Obtendrá una excepción si no descubrió la cadena de análisis correcta , algo como: excepción en el carácter 5 . Mira el carácter 5 y corrige tu cadena de análisis inicial. . Es posible que obtenga otra excepción, repita estos pasos hasta que tenga la fórmula correcta.
private const val SECOND_MILLIS = 1
private const val MINUTE_MILLIS = 60 * SECOND_MILLIS
private const val HOUR_MILLIS = 60 * MINUTE_MILLIS
private const val DAY_MILLIS = 24 * HOUR_MILLIS
object TimeAgo {
fun timeAgo(time: Int): String {
val now = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
if (time > now || time <= 0) {
return "in the future"
}
val diff = now - time
return when {
diff < MINUTE_MILLIS -> "Just now"
diff < 2 * MINUTE_MILLIS -> "a minute ago"
diff < 60 * MINUTE_MILLIS -> "${diff / MINUTE_MILLIS} minutes ago"
diff < 2 * HOUR_MILLIS -> "an hour ago"
diff < 24 * HOUR_MILLIS -> "${diff / HOUR_MILLIS} hours ago"
diff < 48 * HOUR_MILLIS -> "yesterday"
else -> "${diff / DAY_MILLIS} days ago"
}
}
}
Llamada
val String = timeAgo (unixTimeStamp)
aprovechar el tiempo en Kotlin
Aquí está mi implementación Java de esto
public static String relativeDate(Date date){
Date now=new Date();
if(date.before(now)){
int days_passed=(int) TimeUnit.MILLISECONDS.toDays(now.getTime() - date.getTime());
if(days_passed>1)return days_passed+" days ago";
else{
int hours_passed=(int) TimeUnit.MILLISECONDS.toHours(now.getTime() - date.getTime());
if(hours_passed>1)return days_passed+" hours ago";
else{
int minutes_passed=(int) TimeUnit.MILLISECONDS.toMinutes(now.getTime() - date.getTime());
if(minutes_passed>1)return minutes_passed+" minutes ago";
else{
int seconds_passed=(int) TimeUnit.MILLISECONDS.toSeconds(now.getTime() - date.getTime());
return seconds_passed +" seconds ago";
}
}
}
}
else
{
return new SimpleDateFormat("HH:mm:ss MM/dd/yyyy").format(date).toString();
}
}
esto funciona para mi
public class TimeDifference {
int years;
int months;
int days;
int hours;
int minutes;
int seconds;
String differenceString;
public TimeDifference(@NonNull Date curdate, @NonNull Date olddate) {
float diff = curdate.getTime() - olddate.getTime();
if (diff >= 0) {
int yearDiff = Math.round((diff / (AppConstant.aLong * AppConstant.aFloat)) >= 1 ? (diff / (AppConstant.aLong * AppConstant.aFloat)) : 0);
if (yearDiff > 0) {
years = yearDiff;
setDifferenceString(years + (years == 1 ? " year" : " years") + " ago");
} else {
int monthDiff = Math.round((diff / AppConstant.aFloat) >= 1 ? (diff / AppConstant.aFloat) : 0);
if (monthDiff > 0) {
if (monthDiff > AppConstant.ELEVEN) {
monthDiff = AppConstant.ELEVEN;
}
months = monthDiff;
setDifferenceString(months + (months == 1 ? " month" : " months") + " ago");
} else {
int dayDiff = Math.round((diff / (AppConstant.bFloat)) >= 1 ? (diff / (AppConstant.bFloat)) : 0);
if (dayDiff > 0) {
days = dayDiff;
if (days == AppConstant.THIRTY) {
days = AppConstant.TWENTYNINE;
}
setDifferenceString(days + (days == 1 ? " day" : " days") + " ago");
} else {
int hourDiff = Math.round((diff / (AppConstant.cFloat)) >= 1 ? (diff / (AppConstant.cFloat)) : 0);
if (hourDiff > 0) {
hours = hourDiff;
setDifferenceString(hours + (hours == 1 ? " hour" : " hours") + " ago");
} else {
int minuteDiff = Math.round((diff / (AppConstant.dFloat)) >= 1 ? (diff / (AppConstant.dFloat)) : 0);
if (minuteDiff > 0) {
minutes = minuteDiff;
setDifferenceString(minutes + (minutes == 1 ? " minute" : " minutes") + " ago");
} else {
int secondDiff = Math.round((diff / (AppConstant.eFloat)) >= 1 ? (diff / (AppConstant.eFloat)) : 0);
if (secondDiff > 0) {
seconds = secondDiff;
} else {
seconds = 1;
}
setDifferenceString(seconds + (seconds == 1 ? " second" : " seconds") + " ago");
}
}
}
}
}
} else {
setDifferenceString("Just now");
}
}
public String getDifferenceString() {
return differenceString;
}
public void setDifferenceString(String differenceString) {
this.differenceString = differenceString;
}
public int getYears() {
return years;
}
public void setYears(int years) {
this.years = years;
}
public int getMonths() {
return months;
}
public void setMonths(int months) {
this.months = months;
}
public int getDays() {
return days;
}
public void setDays(int days) {
this.days = days;
}
public int getHours() {
return hours;
}
public void setHours(int hours) {
this.hours = hours;
}
public int getMinutes() {
return minutes;
}
public void setMinutes(int minutes) {
this.minutes = minutes;
}
public int getSeconds() {
return seconds;
}
public void setSeconds(int seconds) {
this.seconds = seconds;
} }
Este es el guión muy básico. Es fácil de improvisar.
Resultado: (Hace XXX horas) o (Hace XX días / Ayer / Hoy)
<span id='hourpost'></span>
,or
<span id='daypost'></span>
<script>
var postTime = new Date('2017/6/9 00:01');
var now = new Date();
var difference = now.getTime() - postTime.getTime();
var minutes = Math.round(difference/60000);
var hours = Math.round(minutes/60);
var days = Math.round(hours/24);
var result;
if (days < 1) {
result = "Today";
} else if (days < 2) {
result = "Yesterday";
} else {
result = days + " Days ago";
}
document.getElementById("hourpost").innerHTML = hours + "Hours Ago" ;
document.getElementById("daypost").innerHTML = result ;
</script>
para esto que he hecho Just Now, seconds ago, min ago, hrs ago, days ago, weeks ago, months ago, years ago
en este ejemplo, puede analizar la fecha como 2018-09-05T06:40:46.183Z
esta o cualquier otra como a continuación
agregue debajo del valor en string.xml
<string name="lbl_justnow">Just Now</string>
<string name="lbl_seconds_ago">seconds ago</string>
<string name="lbl_min_ago">min ago</string>
<string name="lbl_mins_ago">mins ago</string>
<string name="lbl_hr_ago">hr ago</string>
<string name="lbl_hrs_ago">hrs ago</string>
<string name="lbl_day_ago">day ago</string>
<string name="lbl_days_ago">days ago</string>
<string name="lbl_lstweek_ago">last week</string>
<string name="lbl_week_ago">weeks ago</string>
<string name="lbl_onemonth_ago">1 month ago</string>
<string name="lbl_month_ago">months ago</string>
<string name="lbl_oneyear_ago" >last year</string>
<string name="lbl_year_ago" >years ago</string>
código java intente a continuación
public String getFormatDate(String postTime1) {
Calendar cal=Calendar.getInstance();
Date now=cal.getTime();
String disTime="";
try {
Date postTime;
//2018-09-05T06:40:46.183Z
postTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").parse(postTime1);
long diff=(now.getTime()-postTime.getTime()+18000)/1000;
//for months
Calendar calObj = Calendar.getInstance();
calObj.setTime(postTime);
int m=calObj.get(Calendar.MONTH);
calObj.setTime(now);
SimpleDateFormat monthFormatter = new SimpleDateFormat("MM"); // output month
int mNow = Integer.parseInt(monthFormatter.format(postTime));
diff = diff-19800;
if(diff<15) { //below 15 sec
disTime = getResources().getString(R.string.lbl_justnow);
} else if(diff<60) {
//below 1 min
disTime= diff+" "+getResources().getString(R.string.lbl_seconds_ago);
} else if(diff<3600) {//below 1 hr
// convert min
long temp=diff/60;
if(temp==1) {
disTime= temp + " " +getResources().getString(R.string.lbl_min_ago);
} else {
disTime = temp + " " +getResources().getString(R.string.lbl_mins_ago);
}
} else if(diff<(24*3600)) {// below 1 day
// convert hr
long temp= diff/3600;
System.out.println("hey temp3:"+temp);
if(temp==1) {
disTime = temp + " " +getResources().getString(R.string.lbl_hr_ago);
} else {
disTime = temp + " " +getResources().getString(R.string.lbl_hrs_ago);
}
} else if(diff<(24*3600*7)) {// below week
// convert days
long temp=diff/(3600*24);
if (temp==1) {
// disTime = "\nyesterday";
disTime = temp + " " +getResources().getString(R.string.lbl_day_ago);
} else {
disTime = temp + " " +getResources().getString(R.string.lbl_days_ago);
}
} else if(diff<((24*3600*28))) {// below month
// convert week
long temp=diff/(3600*24*7);
if (temp <= 4) {
if (temp < 1) {
disTime = getResources().getString(R.string.lbl_lstweek_ago);
}else{
disTime = temp + " " + getResources().getString(R.string.lbl_week_ago);
}
} else {
int diffMonth = mNow - m;
Log.e("count : ", String.valueOf(diffMonth));
disTime = diffMonth + " " + getResources().getString(R.string.lbl_month_ago);
}
}else if(diff<((24*3600*365))) {// below year
// convert month
long temp=diff/(3600*24*30);
System.out.println("hey temp2:"+temp);
if (temp <= 12) {
if (temp == 1) {
disTime = getResources().getString(R.string.lbl_onemonth_ago);
}else{
disTime = temp + " " + getResources().getString(R.string.lbl_month_ago);
}
}
}else if(diff>((24*3600*365))) { // above year
// convert year
long temp=diff/(3600*24*30*12);
System.out.println("hey temp8:"+temp);
if (temp == 1) {
disTime = getResources().getString(R.string.lbl_oneyear_ago);
}else{
disTime = temp + " " + getResources().getString(R.string.lbl_year_ago);
}
}
} catch(Exception e) {
e.printStackTrace();
}
return disTime;
}
Puede usar la Biblioteca RelativeDateTimeFormatter de Java , hace exactamente eso:
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance();
fmt.format(1, Direction.NEXT, RelativeUnit.DAYS); // "in 1 day"
fmt.format(3, Direction.NEXT, RelativeUnit.DAYS); // "in 3 days"
fmt.format(3.2, Direction.LAST, RelativeUnit.YEARS); // "3.2 years ago"
fmt.format(Direction.LAST, AbsoluteUnit.SUNDAY); // "last Sunday"
fmt.format(Direction.THIS, AbsoluteUnit.SUNDAY); // "this Sunday"
fmt.format(Direction.NEXT, AbsoluteUnit.SUNDAY); // "next Sunday"
fmt.format(Direction.PLAIN, AbsoluteUnit.SUNDAY); // "Sunday"
fmt.format(Direction.LAST, AbsoluteUnit.DAY); // "yesterday"
fmt.format(Direction.THIS, AbsoluteUnit.DAY); // "today"
fmt.format(Direction.NEXT, AbsoluteUnit.DAY); // "tomorrow"
fmt.format(Direction.PLAIN, AbsoluteUnit.NOW); // "now"
Estoy usando Instant, Date y DateTimeUtils. Los datos (fecha) que se almacenan en la base de datos en tipo de cadena y luego se convierten en instantáneos.
/*
This method is to display ago.
Example: 3 minutes ago.
I already implement the latest which is including the Instant.
Convert from String to Instant and then parse to Date.
*/
public String convertTimeToAgo(String dataDate) {
//Initialize
String conversionTime = null;
String suffix = "Yang Lalu";
Date pastTime;
//Parse from String (which is stored as Instant.now().toString()
//And then convert to become Date
Instant instant = Instant.parse(dataDate);
pastTime = DateTimeUtils.toDate(instant);
//Today date
Date nowTime = new Date();
long dateDiff = nowTime.getTime() - pastTime.getTime();
long second = TimeUnit.MILLISECONDS.toSeconds(dateDiff);
long minute = TimeUnit.MILLISECONDS.toMinutes(dateDiff);
long hour = TimeUnit.MILLISECONDS.toHours(dateDiff);
long day = TimeUnit.MILLISECONDS.toDays(dateDiff);
if (second < 60) {
conversionTime = second + " Saat " + suffix;
} else if (minute < 60) {
conversionTime = minute + " Minit " + suffix;
} else if (hour < 24) {
conversionTime = hour + " Jam " + suffix;
} else if (day >= 7) {
if (day > 30) {
conversionTime = (day / 30) + " Bulan " + suffix;
} else if (day > 360) {
conversionTime = (day / 360) + " Tahun " + suffix;
} else {
conversionTime = (day / 7) + " Minggu " + suffix;
}
} else if (day < 7) {
conversionTime = day + " Hari " + suffix;
}
return conversionTime;
}
Las siguientes soluciones están todas en Java puro:
La siguiente función solo mostrará el contenedor de tiempo más grande, por ejemplo, si el tiempo transcurrido verdadero es "1 month 14 days ago"
, esta función solo se mostrará "1 month ago"
. Esta función también siempre se redondeará hacia abajo, por lo que "50 days ago"
se mostrará un tiempo equivalente a"1 month"
public String formatTimeAgo(long millis) {
String[] ids = new String[]{"second","minute","hour","day","month","year"};
long seconds = millis / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
long months = days / 30;
long years = months / 12;
ArrayList<Long> times = new ArrayList<>(Arrays.asList(years, months, days, hours, minutes, seconds));
for(int i = 0; i < times.size(); i++) {
if(times.get(i) != 0) {
long value = times.get(i).intValue();
return value + " " + ids[ids.length - 1 - i] + (value == 1 ? "" : "s") + " ago";
}
}
return "0 seconds ago";
}
Simplemente envuelva el contenedor de tiempo que desea redondear con una instrucción Math.round (...), por lo que si desea redondear 50 days
a 2 months
, modifique long months = days / 30
along months = Math.round(days / 30.0)
Aquí está mi caso de prueba, espero que ayude:
val currentCalendar = Calendar.getInstance()
currentCalendar.set(2019, 6, 2, 5, 31, 0)
val targetCalendar = Calendar.getInstance()
targetCalendar.set(2019, 6, 2, 5, 30, 0)
val diffTs = currentCalendar.timeInMillis - targetCalendar.timeInMillis
val diffMins = TimeUnit.MILLISECONDS.toMinutes(diffTs)
val diffHours = TimeUnit.MILLISECONDS.toHours(diffTs)
val diffDays = TimeUnit.MILLISECONDS.toDays(diffTs)
val diffWeeks = TimeUnit.MILLISECONDS.toDays(diffTs) / 7
val diffMonths = TimeUnit.MILLISECONDS.toDays(diffTs) / 30
val diffYears = TimeUnit.MILLISECONDS.toDays(diffTs) / 365
val newTs = when {
diffYears >= 1 -> "Years $diffYears"
diffMonths >= 1 -> "Months $diffMonths"
diffWeeks >= 1 -> "Weeks $diffWeeks"
diffDays >= 1 -> "Days $diffDays"
diffHours >= 1 -> "Hours $diffHours"
diffMins >= 1 -> "Mins $diffMins"
else -> "now"
}
Calendar
clase terrible fue suplantada hace años por las modernas clases java.time con la adopción de JSR 310 . Mal consejo en 2019.
var
, no val
.
La función getrelativeDateTime le dará la fecha y hora como ve en la notificación de Whatsapp.
Para obtener futuras fechas y horas relativas, agréguele condiciones. Esto se crea específicamente para obtener la fecha y hora como la notificación de Whatsapp.
private static String getRelativeDateTime(long date) {
SimpleDateFormat DateFormat = new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault());
SimpleDateFormat TimeFormat = new SimpleDateFormat(" hh:mm a", Locale.getDefault());
long now = Calendar.getInstance().getTimeInMillis();
long startOfDay = StartOfDay(Calendar.getInstance().getTime());
String Day = "";
String Time = "";
long millSecInADay = 86400000;
long oneHour = millSecInADay / 24;
long differenceFromNow = now - date;
if (date > startOfDay) {
if (differenceFromNow < (oneHour)) {
int minute = (int) (differenceFromNow / (60000));
if (minute == 0) {
int sec = (int) differenceFromNow / 1000;
if (sec == 0) {
Time = "Just Now";
} else if (sec == 1) {
Time = sec + " second ago";
} else {
Time = sec + " seconds ago";
}
} else if (minute == 1) {
Time = minute + " minute ago";
} else if (minute < 60) {
Time = minute + " minutes ago";
}
} else {
Day = "Today, ";
}
} else if (date > (startOfDay - millSecInADay)) {
Day = "Yesterday, ";
} else if (date > (startOfDay - millSecInADay * 7)) {
int days = (int) (differenceFromNow / millSecInADay);
Day = days + " Days ago, ";
} else {
Day = DateFormat.format(date);
}
if (Time.isEmpty()) {
Time = TimeFormat.format(date);
}
return Day + Time;
}
public static long StartOfDay(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTimeInMillis();
}
SimpleDateFormat
y Calendar
, sin embargo. Esas clases están mal diseñadas y anticuadas. En su lugar, lea las respuestas que emplean java.time, la API moderna de fecha y hora de Java.
Por falta de simplicidad y respuesta actualizada, sigue la versión más reciente de Java 8 y posterior
import java.time.*;
import java.time.temporal.*;
public class Time {
public static void main(String[] args) {
System.out.println(LocalTime.now().minus(8, ChronoUnit.MINUTES));
System.out.println(LocalTime.now().minus(8, ChronoUnit.HOURS));
System.out.println(LocalDateTime.now().minus(8, ChronoUnit.DAYS));
System.out.println(LocalDateTime.now().minus(8, ChronoUnit.MONTHS));
}
}
Esta es la versión que utiliza la API de Java Time que intenta resolver problemas del pasado para tratar con Fecha y Hora.
Javadoc
versión 8 https://docs.oracle.com/javase/8/docs/api/index.html?java/time/package-summary.html
versión 11 https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/package-summary.html
Tutorial de W3Schools - https://www.w3schools.com/java/java_date.asp
Artículo de DZone: https://dzone.com/articles/java-8-date-and-time