Ответ 1
Я только что нашел это быстрое решение Groovy:
import groovy.time.TimeCategory
import groovy.time.TimeDuration
TimeDuration td = TimeCategory.minus( stop, start )
println td
У меня есть...
Date start = new Date()
...
...
...
Date stop = new Date()
Я хотел бы получить эти годы, месяцы, дни, часы, минуты и секунды между этими двумя датами.
-
Я уточню вопрос.
Я просто хочу получить прошедшее время, как абсолютную меру, которая не учитывает високосные годы, дни каждого месяца и т.д.
Таким образом, я думаю, что невозможно пройти годы и месяцы, и все, что я могу получить, это дни, часы, минуты и секунды.
В частности, я хочу сказать, что определенная задача продолжалась, например.
20 sec
13 min, 4 sec
2 h, 10 min, 2 sec
4 d, 4 h, 2 min, 2 sec
Так что, пожалуйста, простите мою точность.
Я только что нашел это быстрое решение Groovy:
import groovy.time.TimeCategory
import groovy.time.TimeDuration
TimeDuration td = TimeCategory.minus( stop, start )
println td
Вы можете сделать все это с помощью деления и мод.
long l1 = start.getTime();
long l2 = stop.getTime();
long diff = l2 - l1;
long secondInMillis = 1000;
long minuteInMillis = secondInMillis * 60;
long hourInMillis = minuteInMillis * 60;
long dayInMillis = hourInMillis * 24;
long elapsedDays = diff / dayInMillis;
diff = diff % dayInMillis;
long elapsedHours = diff / hourInMillis;
diff = diff % hourInMillis;
long elapsedMinutes = diff / minuteInMillis;
diff = diff % minuteInMillis;
long elapsedSeconds = diff / secondInMillis;
Это должно предоставить вам всю запрашиваемую информацию.
EDIT: поскольку люди, похоже, смущены, нет, это не учитывает такие переменные, как високосные годы или летнее время. Это чисто истекшее время, что и было предложено.
Не так просто со стандартным API Date.
Возможно, вы захотите посмотреть Joda Time или JSR-310 вместо этого.
Я не эксперт в Joda, но я думаю, что код будет:
Interval interval = new Interval(d1.getTime(), d2.getTime());
Period period = interval.toPeriod();
System.out.printf(
"%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n",
period.getYears(), period.getMonths(), period.getDays(),
period.getHours(), period.getMinutes(), period.getSeconds());
Что касается JodaTime, я только что получил это; благодаря ответчику, который это предложил. Здесь предлагается более сжатая версия кода Joda:
Period period = new Period(d1.getTime(), d2.getTime());
System.out.printf(
"%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n",
period.getYears(), period.getMonths(), period.getDays(),
period.getHours(), period.getMinutes(), period.getSeconds());
(не уверен, что это помогает исходному вопросу, но, конечно, поисковикам).
Ну, так как Java 1.5 вы должны использовать TimeUnit.
Вот простой и простой пример этого. Я думаю, что в groovy он может быть короче (как всегда).
/**
* Formats a given {@link Date} to display a since-then timespan.
* @param created
* @return String with a format like "3 minutes ago"
*/
public static String getElapsedTime(Date created) {
long duration = System.currentTimeMillis() - created.getTime();
long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
long days = TimeUnit.MILLISECONDS.toDays(duration);
long hours = TimeUnit.MILLISECONDS.toHours(duration);
long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
if (days > 0) {
return days + " days";
}
if (hours > 0) {
return hours + " hrs";
}
if (minutes > 0) {
return minutes + " minutes";
}
return seconds + " seconds";
}
О, и избегайте нескольких возвратов, пожалуйста;)
Собственно, в отношении вышеприведенных ответов о Joda-Time.
Есть более простой способ сделать это с помощью Joda-Times Period class:
Period period = new Period(startDate, endDate);
System.out.println(PeriodFormat.getDefault().print(period));
Чтобы настроить выход, просмотрите PeriodFormat, PeriodFormatter и PeriodFormatterBuilder.
Duration.between( then , Instant.now() )
Современный способ использует классы java.time, которые вытесняют проблемные старые классы даты и времени.
Вместо Date
используйте Instant
. Класс Instant
представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).
Instant then = Instant.now();
…
Instant now = Instant.now();
Используйте класс Duration
для промежутка времени, не привязанного к временной шкале, с разрешением день-часы-минуты-секунды-нано.
Duration d = Duration.between( then , now );
В течение определенного промежутка времени с разрешением лет-месяцев-дней используйте класс Period
.
Генерация строки в стандартном формате ISO 8601 format для длительностей: PnYnMnDTnHnMnS
. P
отмечает начало. T
отделяет любые годы-месяцы-дни от часов-минут-секунд. Так что два с половиной часа - это PT2H30M
.
String output = d.toString();
В Java 9 и более поздних версиях вы можете получить доступ к отдельным частям с помощью методов toDaysPart
, toHoursPart
и т.д.
Также в Java 9 и более поздних версиях есть усовершенствование Instant.now
, где он фиксирует текущий момент в микросекундах, а не в миллисекундах, наблюдаемых в Java 8. Конечно, во всех версиях Java Класс Instant
может содержать значение в наносекундах.
Среда java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date
, Calendar
и & SimpleDateFormat
.
Проект Joda-Time, который теперь находится в режиме обслуживания, рекомендует выполнить переход на классы java.time.
Чтобы узнать больше, см. Учебное пособие по Oracle. И поищите в Кару множество примеров и объяснений. Спецификация: JSR 310.
Где взять классы java.time?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и еще more.
Хмм, если я получу то, что вы просите, вы хотите знать, что если:
start = 1 января 2001 года, 10: 00: 00 000 утра и
stop = 6 января 2003 года, 12: 01: 00.000 вечера
вы хотите получить ответ от 2 лет, 0 месяцев, 5 дней, 2 часов, 1 минута
К сожалению, это благоразумный ответ. Что, если даты были 2 января и 31 января? Это будет 29 дней? Хорошо, но с 2 февраля по 2 марта составляет 28 (29) дней, но будет указан как 1 месяц?
Продолжительность времени в чем-либо, кроме секунд или, возможно, дней, является переменной, не зная контекста, поскольку месяцы и годы имеют разную длину. Разница между двумя датами должна быть в статических единицах, которые легко вычислимы из stop.getTime() - start.getTime() (что является разницей в миллисекундах)
Помимо вышеупомянутого большого API JodaTime, который я рекомендую сделать, лучшей стандартной альтернативой Java, которую вы можете использовать это java.util.Calendar
. Работа с ним громоздка (это преуменьшение. Смотрите здесь однострочные примеры JodaTime), но вы также можете рассчитать истекшее время с ним. Важным ключом является то, что вы должны использовать Calendar#add()
в цикле, чтобы получить прошедшее значение в течение нескольких лет, месяцев и дней, чтобы учитывать периоды високосных, лет и веков. Вы не должны вычислять их обратно из (милли) секунд.
Вот базовый пример:
import java.util.Calendar;
public class Test {
public static void main(String[] args) throws Exception {
Calendar start = Calendar.getInstance();
start.set(1978, 2, 26, 12, 35, 0); // Just an example.
Calendar end = Calendar.getInstance();
Integer[] elapsed = new Integer[6];
Calendar clone = (Calendar) start.clone(); // Otherwise changes are been reflected.
elapsed[0] = elapsed(clone, end, Calendar.YEAR);
clone.add(Calendar.YEAR, elapsed[0]);
elapsed[1] = elapsed(clone, end, Calendar.MONTH);
clone.add(Calendar.MONTH, elapsed[1]);
elapsed[2] = elapsed(clone, end, Calendar.DATE);
clone.add(Calendar.DATE, elapsed[2]);
elapsed[3] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 3600000;
clone.add(Calendar.HOUR, elapsed[3]);
elapsed[4] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 60000;
clone.add(Calendar.MINUTE, elapsed[4]);
elapsed[5] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 1000;
System.out.format("%d years, %d months, %d days, %d hours, %d minutes, %d seconds", elapsed);
}
private static int elapsed(Calendar before, Calendar after, int field) {
Calendar clone = (Calendar) before.clone(); // Otherwise changes are been reflected.
int elapsed = -1;
while (!clone.after(after)) {
clone.add(field, 1);
elapsed++;
}
return elapsed;
}
}
Он должен напечатать мой возраст с этого момента =)
О, я должен добавить, вы можете "конвертировать" Date
в Calendar
с помощью Calendar#setTime()
.
Это легко; Вы должны установить правильный часовой пояс
import java.util.TimeZone;
import java.util.logging.Logger;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class ImportData {
private final static Logger log = Logger.getLogger(ImportData.class.getName());
private final static DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
private final static DateTimeFormatter dtfh = DateTimeFormat.forPattern("HH:mm:ss.SSS");
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));
// Quotes connection=Quotes.getInstance();
final long start = System.currentTimeMillis();
// do something here ...
// connection.importTickdata();
Thread.currentThread().sleep(2000);
final long end = System.currentTimeMillis();
log.info("[start] " + dtf.print(start));
log.info("[end] " + dtf.print(end));
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
DateTimeZone.setDefault(DateTimeZone.forID("UTC"));
log.info("[duration] " + dtfh.print(end - start));
// connection.logOff();
// System.exit(0);
}
возвращает:
10.11.2010 00:08:12 ImportData main INFO: [start] 2010-11-10 00:08:10.306 10.11.2010 00:08:12 ImportData main INFO: [end] 2010-11-10 00:08:12.318 10.11.2010 00:08:12 ImportData main INFO: [duration] 00:00:02.012
Я делаю это в общем:
def start_time = System.currentTimeMillis()
...
def end_time = System.currentTimeMillis()
println (end_time - start_time) +' ms'
Затем вы можете разбить это на любую единицу времени, которую вы хотите, используя класс Duration Groovy http://docs.groovy-lang.org/latest/html/api/groovy/time/Duration.html.
Нет смысла создавать объект Date, поскольку все это происходит, это wrap System.currentTimeMillis(). Функция getTime() просто распаковывает объект Date. Я предлагаю вам использовать эту функцию для получения долгого времени.
Если вам нужна только вторая точность, это нормально. Однако, если вы хотите, чтобы точность в миллисекундах использовала System.nanoTime(), чтобы получить время простоя.
Это полная функция, которую я реализовал на основе ответа Sebastian Celis. И снова, с его поста - это не принимает во внимание такие вещи, как високосные годы или переход на летнее время. Это чистое истекшее время.
Выход выполнен с учетом моей потребности. Это выводит только три важных раздела. Вместо возврата
4 месяца, 2 недели, 3 дня, 7 часов, 28 минут, 43 секунды
Он просто возвращает первый 3-й блок (см. больше примеров прогона в конце сообщения):
4 месяца, 2 недели, 3 дня
Вот полный исходный код метода:
/**
* Format milliseconds to elapsed time format
*
* @param time difference in milliseconds
* @return Human readable string representation - eg. 2 days, 14 hours, 5 minutes
*/
public static String formatTimeElapsedSinceMillisecond(long milisDiff) {
if(milisDiff<1000){ return "0 second";}
String formattedTime = "";
long secondInMillis = 1000;
long minuteInMillis = secondInMillis * 60;
long hourInMillis = minuteInMillis * 60;
long dayInMillis = hourInMillis * 24;
long weekInMillis = dayInMillis * 7;
long monthInMillis = dayInMillis * 30;
int timeElapsed[] = new int[6];
// Define time units - plural cases are handled inside loop
String timeElapsedText[] = {"second", "minute", "hour", "day", "week", "month"};
timeElapsed[5] = (int) (milisDiff / monthInMillis); // months
milisDiff = milisDiff % monthInMillis;
timeElapsed[4] = (int) (milisDiff / weekInMillis); // weeks
milisDiff = milisDiff % weekInMillis;
timeElapsed[3] = (int) (milisDiff / dayInMillis); // days
milisDiff = milisDiff % dayInMillis;
timeElapsed[2] = (int) (milisDiff / hourInMillis); // hours
milisDiff = milisDiff % hourInMillis;
timeElapsed[1] = (int) (milisDiff / minuteInMillis); // minutes
milisDiff = milisDiff % minuteInMillis;
timeElapsed[0] = (int) (milisDiff / secondInMillis); // seconds
// Only adds 3 significant high valued units
for(int i=(timeElapsed.length-1), j=0; i>=0 && j<3; i--){
// loop from high to low time unit
if(timeElapsed[i] > 0){
formattedTime += ((j>0)? ", " :"")
+ timeElapsed[i]
+ " " + timeElapsedText[i]
+ ( (timeElapsed[i]>1)? "s" : "" );
++j;
}
} // end for - build string
return formattedTime;
} // end of formatTimeElapsedSinceMillisecond utility method
Вот пример тестового заявления:
System.out.println(formatTimeElapsedSinceMillisecond(21432424234L));
// Output: 8 months, 1 week, 1 day
System.out.println(formatTimeElapsedSinceMillisecond(87724294L));
// Output: 1 day, 22 minutes, 4 seconds
System.out.println(formatTimeElapsedSinceMillisecond(123434L));
// Output: 2 minutes, 3 seconds
Это еще одна аналогичная функция: она не будет отображаться в течение нескольких дней, часов, минут и т.д., если ее не нужно менять, если нужно, литералы.
public class ElapsedTime {
public static void main(String args[]) {
long start = System.currentTimeMillis();
start -= (24 * 60 * 60 * 1000 * 2);
start -= (60 * 60 * 1000 * 2);
start -= (60 * 1000 * 3);
start -= (1000 * 55);
start -= 666;
long end = System.currentTimeMillis();
System.out.println(elapsedTime(start, end));
}
public static String elapsedTime(long start, long end) {
String auxRet = "";
long aux = end - start;
long days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
// days
if (aux > 24 * 60 * 60 * 1000) {
days = aux / (24 * 60 * 60 * 1000);
}
aux = aux % (24 * 60 * 60 * 1000);
// hours
if (aux > 60 * 60 * 1000) {
hours = aux / (60 * 60 * 1000);
}
aux = aux % (60 * 60 * 1000);
// minutes
if (aux > 60 * 1000) {
minutes = aux / (60 * 1000);
}
aux = aux % (60 * 1000);
// seconds
if (aux > 1000) {
seconds = aux / (1000);
}
milliseconds = aux % 1000;
if (days > 0) {
auxRet = days + " days ";
}
if (days != 0 || hours > 0) {
auxRet += hours + " hours ";
}
if (days != 0 || hours != 0 || minutes > 0) {
auxRet += minutes + " minutes ";
}
if (days != 0 || hours != 0 || minutes != 0 || seconds > 0) {
auxRet += seconds + " seconds ";
}
auxRet += milliseconds + " milliseconds ";
return auxRet;
}
}
import groovy.time.TimeCategory
import groovy.time.TimeDuration
time = { closure ->
use(TimeCategory) {
def started = new Date()
def res = closure()
TimeDuration duration = new Date() - started
logger.info("Execution duration: " + duration.toMilliseconds() + "ms")
res
}
}
time {
println 'A realy heavy operation here that you want to measure haha'
}
Это проблема, и нужно сделать алгоритм для учета високосных лет и точного количества месяцев и дней в течение нескольких лет. Интересно, как это просто, если нужно использовать только одну единицу измерения. Например, общее количество дней между двумя днями является правильным, как указано на число напоминаний за несколько дней после того, как количество месяцев и лет рассчитывается в течение двух десятилетий.
В настоящее время я работаю над этим, чтобы предоставить его из моей реализации PML, например, в форме:
unemployed <- date.difference[
From = 2009-07-01,
Till = now,
YEARS, MONTHS, DAYS
]: yyyy-MM-dd
$$-> *unemployed -> date.translate[ YEARS, MONTHS, DAYS ] -> print["Unemployed for:", .]
Конечно, это также было бы полезно и требовалось для точных расчетов процентных ставок.