Как рассчитать временной интервал в Java и форматировать вывод?
Я хочу взять два раза (в секундах с эпохи) и показать разницу между ними в таких форматах, как:
- 2 минуты
- 1 час, 15 минут
- 3 часа, 9 минут
- 1 минута назад
- 1 час, 2 мин. назад
Как я могу выполнить это?
Ответы
Ответ 1
Так как все кричат "YOODAA!!!" но никто не публикует конкретный пример, здесь мой вклад.
Вы также можете сделать это с помощью Joda-Time. Используйте Period
для представления периода. Чтобы отформатировать период в желаемом представлении человека, используйте PeriodFormatter
, который вы можете создать с помощью PeriodFormatterBuilder
.
Вот пример запуска:
DateTime myBirthDate = new DateTime(1978, 3, 26, 12, 35, 0, 0);
DateTime now = new DateTime();
Period period = new Period(myBirthDate, now);
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendYears().appendSuffix(" year, ", " years, ")
.appendMonths().appendSuffix(" month, ", " months, ")
.appendWeeks().appendSuffix(" week, ", " weeks, ")
.appendDays().appendSuffix(" day, ", " days, ")
.appendHours().appendSuffix(" hour, ", " hours, ")
.appendMinutes().appendSuffix(" minute, ", " minutes, ")
.appendSeconds().appendSuffix(" second", " seconds")
.printZeroNever()
.toFormatter();
String elapsed = formatter.print(period);
System.out.println(elapsed + " ago");
Гораздо понятнее и лаконичнее, не так ли?
Теперь это отпечаток
32 years, 1 month, 1 week, 5 days, 6 hours, 56 minutes, 24 seconds ago
(Кашель, старый, кашель)
Ответ 2
Date start = new Date(1167627600000L); // JANUARY_1_2007
Date end = new Date(1175400000000L); // APRIL_1_2007
long diffInSeconds = (end.getTime() - start.getTime()) / 1000;
long diff[] = new long[] { 0, 0, 0, 0 };
/* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
/* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
/* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
/* days */diff[0] = (diffInSeconds = (diffInSeconds / 24));
System.out.println(String.format(
"%d day%s, %d hour%s, %d minute%s, %d second%s ago",
diff[0],
diff[0] > 1 ? "s" : "",
diff[1],
diff[1] > 1 ? "s" : "",
diff[2],
diff[2] > 1 ? "s" : "",
diff[3],
diff[3] > 1 ? "s" : ""));
Ответ 3
Yup пробудил мертвых, которые у меня есть, но здесь моя улучшенная реализация основана на @mtim опубликованном коде, так как этот поток приходит почти на вершину поисков, поэтому я возился с сонной пустотой,
public static String getFriendlyTime(Date dateTime) {
StringBuffer sb = new StringBuffer();
Date current = Calendar.getInstance().getTime();
long diffInSeconds = (current.getTime() - dateTime.getTime()) / 1000;
/*long diff[] = new long[]{0, 0, 0, 0};
/* sec * diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
/* min * diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
/* hours * diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
/* days * diff[0] = (diffInSeconds = (diffInSeconds / 24));
*/
long sec = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
long min = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
long hrs = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
long days = (diffInSeconds = (diffInSeconds / 24)) >= 30 ? diffInSeconds % 30 : diffInSeconds;
long months = (diffInSeconds = (diffInSeconds / 30)) >= 12 ? diffInSeconds % 12 : diffInSeconds;
long years = (diffInSeconds = (diffInSeconds / 12));
if (years > 0) {
if (years == 1) {
sb.append("a year");
} else {
sb.append(years + " years");
}
if (years <= 6 && months > 0) {
if (months == 1) {
sb.append(" and a month");
} else {
sb.append(" and " + months + " months");
}
}
} else if (months > 0) {
if (months == 1) {
sb.append("a month");
} else {
sb.append(months + " months");
}
if (months <= 6 && days > 0) {
if (days == 1) {
sb.append(" and a day");
} else {
sb.append(" and " + days + " days");
}
}
} else if (days > 0) {
if (days == 1) {
sb.append("a day");
} else {
sb.append(days + " days");
}
if (days <= 3 && hrs > 0) {
if (hrs == 1) {
sb.append(" and an hour");
} else {
sb.append(" and " + hrs + " hours");
}
}
} else if (hrs > 0) {
if (hrs == 1) {
sb.append("an hour");
} else {
sb.append(hrs + " hours");
}
if (min > 1) {
sb.append(" and " + min + " minutes");
}
} else if (min > 0) {
if (min == 1) {
sb.append("a minute");
} else {
sb.append(min + " minutes");
}
if (sec > 1) {
sb.append(" and " + sec + " seconds");
}
} else {
if (sec <= 1) {
sb.append("about a second");
} else {
sb.append("about " + sec + " seconds");
}
}
sb.append(" ago");
/*String result = new String(String.format(
"%d day%s, %d hour%s, %d minute%s, %d second%s ago",
diff[0],
diff[0] > 1 ? "s" : "",
diff[1],
diff[1] > 1 ? "s" : "",
diff[2],
diff[2] > 1 ? "s" : "",
diff[3],
diff[3] > 1 ? "s" : ""));*/
return sb.toString();
}
Очевидно, это можно улучшить. в основном он пытается получить более продолжительный промежуток времени, есть несколько ограничений, хотя это будет вести себя странно, если время (параметр) будет в будущем, а его ограничение будет ограничено только днями, часами и секундами (месяцы и годы не обрабатывается, так что кто-то другой может; -).
выборки:
- примерно секунду назад
- 8 минут и 34 секунд назад
- час и 4 минуты назад
- день назад
- 29 дней назад
- год и 3 месяца назад
приветствия: D
EDIT: теперь поддерживает месяцы и годы: P
Ответ 4
Я бы порекомендовал вам взглянуть на HumanTime
Ответ 5
Избегайте устаревших классов времени
Другие ответы могут быть правильными, но устарели. Неудобные старые классы времени на Java в настоящее время являются устаревшими, вытесняются классами java.time.
Аналогично, проект Joda-Time, теперь в режиме обслуживания, советует перейти на классы java.time.
Использование java.time
Instant
два раза (в секундах с эпохи)
В java.time мы представляем моменты на временной шкале в UTC как Instant
. Я предполагаю, что ваша эпоха такая же, как у java.time, первого момента 1970 года в UTC (1970-01-01T00:00:00Z
). Обратите внимание, что Instant
имеет разрешение наносекунд. Метод удобной фабрики создает Instant
с целых секунд, как задано в Вопросе.
Instant start = Instant.ofEpochSecond( … );
Instant stop = Instant.ofEpochSecond( … );
Здесь мы используем текущий момент и несколько минут спустя.
Instant start = Instant.now() ;
Instant stop = start.plusSeconds( TimeUnit.MINUTES.toSeconds( 7L ) ) ; // Seven minutes as a number of seconds.
Duration
В java.time промежуток времени, не привязанный к временной шкале, представлен двумя способами. В течение месяцев-месяцев-дней у нас есть Period
. В течение часов-минут-секунд у нас есть Duration
.
Duration duration = Duration.between( start , stop );
Полуоткрытый
Истекшее время рассчитывается с использованием метода Half-Open. В этом подходе начало включено, в то время как окончание является исключительным. Этот подход обычно используется в работе с датой. Я считаю, что использование этого подхода последовательно в вашей базе кода поможет устранить ошибки и недоразумения из-за двусмысленностей и облегчит когнитивную нагрузку вашего программирования.
ISO 8601
Стандарт ISO 8601 определяет множество практических форматов для представления значений даты и времени в виде текста. Эти форматы предназначены для того, чтобы избежать двусмысленности, легко анализировать машину и быть интуитивно понятными для людей в разных культурах.
Классы java.time используют эти форматы по умолчанию при разборе и генерации строк.
В течение промежутка времени, не привязанного к временной шкале, стандарт определяет формат PnYnMnDTnHnMnS
где P
обозначает начало, а T
отделяет любые годы-месяцы-дни от любых часов-минут-секунд. Таким образом, полтора часа - PT1H30M
.
В нашем примере код используется семь минут:
String outputStandard = duration.toString();
PT7M
См. Приведенный выше пример кода, который работает в режиме реального времени на IdeOne.com.
Я предлагаю придерживаться этих форматов, когда это возможно, конечно, при обмене или сериализации данных даты и времени, но также подумайте над использованием в пользовательском интерфейсе, где это необходимо, и ваших пользователей можно обучить их использованию.
Я рекомендую никогда не использовать формат часового часа (например: 01:30 для полутора часов), поскольку этот формат полностью неоднозначен с временем суток.
Получение частей для создания строки
Если вы должны указать промежуток времени, как показано в Вопросе, вам нужно будет создать текст самостоятельно.
- Для
Period
вызовите getYears
, getMonths
и getDays
для извлечения каждой части. - Как ни странно, в классе
Duration
не было таких геттеров в Java 8, но они получили их в Java 9 и более поздних toDaysPart
: toDaysPart
, toHoursPart
, toMinutesPart
, toSecondsPart
и toNanosPart
.
Какой-то примерный код, простой и простой, чтобы вы начали.
int days = duration.toDaysPart() ;
int hours = duration.toHoursPart() ;
int minutes = duration.toMinutesPart() ;
int seconds = duration.toSecondsPart() ;
int nanos = duration.toNanosPart() ;
StringBuilder sb = new StringBuilder( 100 );
if( days != 0 ) {
sb.append( days + " days" ) ;
};
if( hours != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( hours + " hours" ) ;
};
if( minutes != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( minutes + " minutes" ) ;
};
if( seconds != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( seconds + " seconds" ) ;
};
if( nanos != 0 ) {
sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ; // Append comma if any existing text.
sb.append( nanos + " nanos" ) ;
};
String output = sb.toString();
Или, может быть, вы можете написать код с помощью DateTimeFormatterBuilder
способом, показанным с помощью Joda-Time в ответе от Balus C.
О java.time
Рамка java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют неприятные старые устаревшие классы времени, такие как java.util.Date
, Calendar
и SimpleDateFormat
.
Проект Joda-Time, теперь в режиме обслуживания, советует перейти на классы java.time.
Чтобы узнать больше, ознакомьтесь с учебным пособием Oracle. И поиск Qaru для многих примеров и объяснений. Спецификация - JSR 310.
Где можно получить классы java.time?
- Java SE 8 и SE 9 и более поздние версии
- Встроенный.
- Часть стандартного Java API с интегрированной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и SE 7
- Большая часть функциональных возможностей java.time включена обратно в Java 6 и 7 в ThreeTen-Backport.
- Android
Проект ThreeTen-Extra расширяет java.time с дополнительными классами. Этот проект является доказательством возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь, такие как Interval
, YearWeek
, YearQuarter
, andfz более.
Ответ 6
Я не эксперт в Java, но вы можете сделать t1-t2 = t3 (в секундах), а затем разделить это на 60, дать вам минуты, еще на 60 даст вам секунды. Тогда это просто вопрос выяснения, сколько дивизий вам нужно.
Надеюсь, что это поможет.
Ответ 7
Если ваши временные интервалы пересекают дневные (летние) границы, вы хотите сообщить количество дней?
Например, с 23:00 до 23:00 на следующий день всегда будет день, но может быть 23, 24 или 25 часов в зависимости от того, пересекаете ли вы переход на летнее время.
Если вам это интересно, убедитесь, что вы учитываете его в своем выборе.
Ответ 8
некоторый код, который играет с форматированием даты... и время назад.
SimpleDateFormat curFormater = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss");
try {
Date dateObj = curFormater.parse(pubDate);
SimpleDateFormat postFormater = new SimpleDateFormat("MMMM dd, yyyy ss:mm:hh");
String newDateStr = postFormater.format(dateObj);
Log.v("THE NEW DATE IS",newDateStr);
long pubdateinmilis = dateObj.getTime();
pubDate = (String) DateUtils.getRelativeTimeSpanString(pubdateinmilis, System.currentTimeMillis(),DateUtils.HOUR_IN_MILLIS,DateUtils.FORMAT_ABBREV_RELATIVE);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Ответ 9
Я всегда начинаю с Joda Time. Работа с датами и временем в Java всегда "веселая", но время Joda Time снимает напряжение.
У них есть классы Interval и Duration, которые выполняют половину того, что вы ищете. Не уверен, что у них есть функция для вывода в читаемом формате. Я буду продолжать искать.
НТН
Ответ 10
Calendar класс может обрабатывать большинство связанных с датой математики. Вам нужно будет получить результат compareTo и вывести формат самостоятельно. Существует не стандартная библиотека, которая делает именно то, что вы ищете, хотя может быть и сторонняя библиотека, которая делает.
Ответ 11
ОК, после краткого ознакомления с API кажется, что вы можете сделать следующее: -
- создать некоторые ReadableInstants, представляющие время начала и окончания времени.
- Использовать Hours.hoursBetween, чтобы получить количество часов
- используйте Minutes.minutesBetween, чтобы получить количество минут
- используйте протокол 60 в минутах, чтобы получить оставшиеся минуты.
- et voila!
НТН
Ответ 12
Решение "Abduliam Rehmanius" кажется довольно приятным, или вы можете использовать некоторую библиотеку выше или вы можете создавать новые простые вещи, обратитесь к решению JS здесь: http://www.datejs.com/. Не сложно преобразовать в Java lang: -)
Надеюсь, что моя ссылка полезна для вас!
Ответ 13
Время форматирования в java часто появляется для меня в ETL или DB pulls. Следующий фрагмент кода - это то, как я получаю импульс операции.
SimpleDateFormat ymdhms=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DecimalFormat formatter = new DecimalFormat("#,###"); /* ("#,###.00"); gives you the decimal fractions */
int counter=0;
Date beginTime0=new Date();
while (<some end condition>) {
<some time consuming operation>
/*// uncomment this section durring initial exploration of the time consumer
if(counter>100000){
System.out.println("debug exiting due to counter="+counter);
System.exit(0);
}
*/
if(0==counter%1000){
Date now = new Date();
long diffInSeconds = (now.getTime() - beginTime0.getTime()) / 1000;
long diff[] = new long[] { 0, 0, 0, 0 };
diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds); /* sec */
diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; /* min */
diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; /* hours */
diff[0] = (diffInSeconds = (diffInSeconds / 24)); /* days */
String delta = String.format(
"%s%s%s%s"
,(diff[0]>0?String.format("%d day%s " ,diff[0],(diff[0]!=1?"s":"")):"")
,(diff[1]>0?String.format("%2d hour%s " ,diff[1],(diff[1]!=1?"s":" ")):"")
,(diff[2]>0?String.format("%2d minute%s ",diff[2],(diff[2]!=1?"s":" ")):"")
, String.format("%2d second%s ",diff[3],(diff[3]!=1?"s":" "))
);
System.out.println(String.format(
"%12s %s delta= %s"
,formatter.format(counter)
,ymdhms.format(new Date())
,delta
)
);
}
counter++;
}
Ответ 14
Я думаю, что вы ищете что-то вроде PrettyTime
PrettyTime - это библиотека форматирования времени OpenSource. Полностью настраиваемый, он создает читаемые человеком относительные временные метки, подобные тем, которые видны на Digg, Twitter и Facebook. Доступны на более чем 30 языках!
ссылка:
https://github.com/ocpsoft/prettytime
Может использоваться и в android тоже
Например
System.out.println(p.format(new Date(System.currentTimeMillis() + 1000*60*10)));
//prints: "10 minutes from now"
Ответ 15
Недавно я получил то же требование, когда мне нужен базовый метод для печати. У меня не было возможности использовать стороннюю библиотеку. Поэтому я просто уточнил идею @mtim.
public static void main(String[] args) throws IOException, ParseException {
String since = "2017-02-24T04:44:05.601Z";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
TimeZone utc = TimeZone.getTimeZone("UTC");
dateFormat.setTimeZone(utc);
Date sinceDate = dateFormat.parse(since);
Date now = new Date();
long durationInSeconds = TimeUnit.MILLISECONDS.toSeconds(now.getTime() - sinceDate.getTime());
long SECONDS_IN_A_MINUTE = 60;
long MINUTES_IN_AN_HOUR = 60;
long HOURS_IN_A_DAY = 24;
long DAYS_IN_A_MONTH = 30;
long MONTHS_IN_A_YEAR = 12;
long sec = (durationInSeconds >= SECONDS_IN_A_MINUTE) ? durationInSeconds % SECONDS_IN_A_MINUTE : durationInSeconds;
long min = (durationInSeconds /= SECONDS_IN_A_MINUTE) >= MINUTES_IN_AN_HOUR ? durationInSeconds%MINUTES_IN_AN_HOUR : durationInSeconds;
long hrs = (durationInSeconds /= MINUTES_IN_AN_HOUR) >= HOURS_IN_A_DAY ? durationInSeconds % HOURS_IN_A_DAY : durationInSeconds;
long days = (durationInSeconds /= HOURS_IN_A_DAY) >= DAYS_IN_A_MONTH ? durationInSeconds % DAYS_IN_A_MONTH : durationInSeconds;
long months = (durationInSeconds /=DAYS_IN_A_MONTH) >= MONTHS_IN_A_YEAR ? durationInSeconds % MONTHS_IN_A_YEAR : durationInSeconds;
long years = (durationInSeconds /= MONTHS_IN_A_YEAR);
String duration = getDuration(sec,min,hrs,days,months,years);
System.out.println(duration);
}
private static String getDuration(long secs, long mins, long hrs, long days, long months, long years) {
StringBuffer sb = new StringBuffer();
String EMPTY_STRING = "";
sb.append(years > 0 ? years + (years > 1 ? " years " : " year "): EMPTY_STRING);
sb.append(months > 0 ? months + (months > 1 ? " months " : " month "): EMPTY_STRING);
sb.append(days > 0 ? days + (days > 1 ? " days " : " day "): EMPTY_STRING);
sb.append(hrs > 0 ? hrs + (hrs > 1 ? " hours " : " hour "): EMPTY_STRING);
sb.append(mins > 0 ? mins + (mins > 1 ? " mins " : " min "): EMPTY_STRING);
sb.append(secs > 0 ? secs + (secs > 1 ? " secs " : " secs "): EMPTY_STRING);
sb.append("ago");
return sb.toString();
}
На выходе будет временной интервал (длительность), напечатанный словами, например.
1 day 2 hours 51 mins 41 secs ago
Ответ 16
Этот вопрос старый и уже имеет ответ, но у меня есть лучшее решение.
Использовать relativeSpan из даты utils
dateHere.setText(DateUtils.getRelativeTimeSpanString(timeInMillis,
System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS));
он принимает аргументы: long/int time, текущее время и то, как вы хотите, _month, minute, second etc
Ответ 17
long time1, time2;
time1 = System.currentMillis();
.. drink coffee
time2 = System.currentMillis();
long difference = time2 - time1 // millies between time1 and time2
java.util.Date differneceDate = new Date(difference);
Чтобы создать строку типа "2 минуты", вы должны использовать DateFormatter/DateFormat. Более подробную информацию об этом вы можете найти в спецификации Java API (java.sun.com).