Как определить время между настоящим моментом и произвольной будущей датой в Java - PullRequest
1 голос
/ 23 ноября 2011

В настоящее время я пытаюсь определить количество времени между двумя датами (одна из которых является текущей датой / временем, другая - произвольной будущей датой). Я использую только Java и Android API, но у меня есть несколько проблем с GregorianCalendar. Мой код до сих пор можно увидеть ниже, но проблема, с которой я сталкиваюсь, заключается в том, что время между двумя датами в значительной степени неточное. Как вы увидите, в этом примере я установил будущую дату как Рождество, но он говорит, что до этого времени осталось более 62 дней, что явно неправильно.

    date = new GregorianCalendar();
    currentTime = date.getTimeInMillis();
    calendar = new GregorianCalendar();
    calendar.set(2011, 12, 25, 0, 0, 0);
    long difference = calendar.getTimeInMillis()-currentTime;

    long x = difference / 1000;
    seconds = x % 60;
    x /= 60;
    minutes = x % 60;
    x /= 60;
    hours = x % 24;
    x /= 24;
    days = x;

При отладке я добавил date.set (2011, 11, 23, 13, 1, 15); который был намного более точным, но он по-прежнему отображал 32 дня, когда я считаю, что правильное количество дней - 31.

Большое спасибо заранее за любую помощь, высоко ценится.

Ответы [ 4 ]

2 голосов
/ 23 ноября 2011

проблема в вашем коде заключается в методе calendar.set(2011, 12, 25, 0, 0, 0);, который вы хотите calendar.set(2011, 11, 25, 0, 0, 0);

, вы также можете использовать Calendar.DECEMBER.

Javadoc понятен для этого метода:

  • @ param month значение, используемое для установки поля календаря MONTH.* Значение месяца основано на 0.например, 0 для января.
1 голос
/ 05 сентября 2015

java.time

Новая инфраструктура java.time, встроенная в Java 8 и более поздние версии, заменяет старые запутанные классы java.util.Date/.Calendar

В учебнике показано, как получить промежуток времени, определяемый как общее количество дней, а также период, логическое число лет, месяцев и дней.

LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1960, Month.JANUARY, 1);

Period p = Period.between(birthday, today);
long p2 = ChronoUnit.DAYS.between(birthday, today);
System.out.println("You are " + p.getYears() + " years, " + p.getMonths() +
               " months, and " + p.getDays() +
               " days old. (" + p2 + " days total)");

Код производит вывод, подобный следующему:

Вам 53 года, 4 месяца и 29 дней. (Всего 19508 дней)

Я бы улучшил пример Tutorial, передав часовой пояс в now, а не полагаясь косвенно на текущий часовой пояс JVM по умолчанию, который может измениться в любой момент. В то время как LocalDate не имеет назначенного часового пояса (это то, что означает локальный), при определении даты часовой пояс имеет решающее значение. Например, в Париже новый день наступает раньше, чем в Монреале.

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

Чтобы получить дни до следующего дня рождения, создайте будущую дату, подставив год. Инфраструктура Java.time использует неизменяемые объекты, поэтому этот показанный синтаксис создает новый объект на основе значений оригинала, оставляя оригинал нетронутым и незатронутым.

LocalDate birthdayThisYear = birthday.withYear( today.getYear() );
if ( birthdayThisYear.isBefore( today ) ) {
    birthdayThisYear.plusYears( 1 );
}
long daysUntilBirthday = ChronoUnit.DAYS.between( today , birthdayThisYear );

Joda-Time

Библиотека Joda-Time послужила источником вдохновения для java.time. Используйте Joda-Time, когда технология Java 8 недоступна, например, в Android. Специально для Android вы можете найти специальные сборки Joda-Time из других источников, чтобы решить проблему медленной загрузки в Dalvik.

В этом случае код похож между Joda-Time и java.time.

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
LocalDate today = LocalDate.now( zone );
LocalDate birthdate  = new LocalDate( 1966 , 1 , 2 );
LocalDate nextBirthday = birthdate.withYear( today.getYear() );
if ( nextBirthday.isBefore( today ) ) {
    nextBirthday = nextBirthday.plusYears( 1 );
}
int daysUntilBirthday = Days.daysBetween( today , nextBirthday ).getDays();

Joda-Time также предлагает класс Period. Однако этот класс обрабатывает неполные дни, тогда как java.time Period - только целые дни. Поэтому нам нужно преобразовать наши экземпляры LocalDate в экземпляры DateTime для подачи в конструктор Period.

DateTime start = today.toDateTimeAtStartOfDay( zone );
DateTime stop = nextBirthday.toDateTimeAtStartOfDay( zone );
Period period = new Period( start , stop );

Форматтер по умолчанию использует стандартные форматы ISO 8601. Таким образом, вызов period.toString() отображает что-то вроде этого на три месяца и два дня:

P3M2D

1 голос
/ 23 ноября 2011

Вместо этого:

 long x = difference / 1000;
seconds = x % 60;
x /= 60;
minutes = x % 60;
x /= 60;
hours = x % 24;
x /= 24;
days = x;

построить объект Date с разницей между двумя датами (длинное значение). Затем вы можете установить setDate (Date) для объекта Calendar и проанализировать его.

Кроме того, вы можете взглянуть на Joda Time Api, который относительно прост в использовании.

0 голосов
/ 15 мая 2017

Сначала я предлагаю вам использовать библиотечные методы для расчетов.Во-первых, вы не должны изобретать велосипед.Во-вторых, некоторые расчеты могут оказаться сложными, например, если вы также хотите указать месяцы или годы и вам необходимо учитывать разные длины месяцев и високосные годы.Не в последнюю очередь, хотя легко разделить на 60 для преобразования из секунд в минуты, в то время как пишет код, в то время как читает это имя метода, в котором есть «минуты» или «секунды»более четко передаст почему вы делите на 60.

В эти дни у Java есть два класса для количества времени:

  • Duration для времени междучасы, например, 2 часа 46 минут 30 секунд (он также может обрабатывать дни, но не знает ни недель, ни месяцев).
  • Period - время между датами, например, 2 месяца 9 дней.

Для общего решения я покажу, как вы можете использовать оба для своей задачи.Сначала я нахожу Period между датами.Если это с сегодняшнего дня в 2 часа дня до послезавтра в 10 часов утра, вы получите два дня, в которые мы хотели 1 день 20 часов, поэтому нам нужно скорректировать это, вычтя 1 день до вычисления Duration.

    LocalDateTime dateTimeOne = LocalDateTime.of(2016, Month.APRIL, 25, 9, 5, 30);
    LocalDateTime dateTimeTwo = LocalDateTime.of(2017, Month.MAY, 15, 9, 10, 50);

    Period p = Period.between(dateTimeOne.toLocalDate(), dateTimeTwo.toLocalDate());
    LocalDateTime dtOnePlusPeriod = dateTimeOne.plus(p);
    if (dtOnePlusPeriod.isAfter(dateTimeTwo)) { // too far
        p = p.minusDays(1);
    }
    Duration d = Duration.between(dateTimeOne.plus(p), dateTimeTwo);

    long hours = d.toHours();
    d = d.minusHours(hours);
    long minutes = d.toMinutes();
    d = d.minusMinutes(minutes);
    long seconds = d.getSeconds();

    if (p.isZero() && d.isZero()) {
        System.out.println("0 seconds");
    } else {
        if (p.getYears() != 0) {
            System.out.print("" + p.getYears() + " years ");
        }
        if (p.getMonths() != 0) {
            System.out.print("" + p.getMonths() + " months ");
        }
        if (p.getDays() != 0) {
            System.out.print("" + p.getDays() + " days ");
        }
        if (hours != 0) {
            System.out.print("" + hours + " hours ");
        }
        if (minutes != 0) {
            System.out.print("" + minutes + " minutes ");
        }
        if (seconds != 0) {
            System.out.print("" + seconds + " seconds");
        }
        System.out.println();
    }

Печатается

1 years 20 days 5 minutes 20 seconds

Используя LocalDateTime, я игнорирую изменения в летнее время и в летнее время (DST).Если вам нужно принять это во внимание, просто используйте ZonedDateTime.

Все классы находятся в пакете java.time.Я включу ссылку на учебник Oracle внизу.

Если вы хотите использовать java.time на Android, вы получите их в ThreeTenABP.Дополнительные ссылки ниже.

С Java 9 появятся некоторые новые методы в Duration, toHoursPart(), toMinutesPart() и toSecondsPart(), которые дадут нам часы, минуты и секунды, которые мы хотим, во многомЯ уже сделал с Period.Тогда нам больше не нужно будет вычитать сначала часы, а затем минуты при расчете отдельных полей.

Ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...