ZonedDateTime для даты до Java 8 в ранней версии Android - PullRequest
0 голосов
/ 22 февраля 2019

Я пытаюсь заменить метод ZonedDateTime.toInstant, потому что он доступен только после API 26 для Android.
Но мое приложение должно поддерживать API 19.
Я хочу преобразовать ZonedDateTime в Date, чтобыя могу сделать что-то вроде этого:

final Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
final long millis = calendar.getTimeInMillis();

Что я хочу достичь, это следующее:
Я хочу рассчитать разницу между текущей датой и другой датой в секундах, минутах, часах, ... побеждает максимально возможная единица, поэтому я получу, например, 5 days ago в результате.

Ответы [ 3 ]

0 голосов
/ 23 февраля 2019

Уже есть хороший ответ Василия Бурка.После ваших комментариев я подумал, что могу быть немного более конкретным:

public static String diff(String thenStr) {
    Instant now = Instant.now();
    Instant then = Instant.parse(thenStr);
    ChronoUnit[] units = ChronoUnit.values();
    // try longest units first, they are in the far end of the array
    for (int i = units.length - 1; i >= 0; i--) {
        if (then.isSupported(units[i])) {
            long diffInCurrentUnit = units[i].between(then, now);
            if (diffInCurrentUnit != 0) {
                return "" + diffInCurrentUnit + ' ' + units[i].toString().toLowerCase();
            }
        }
    }
    return "0";
}

Давайте попробуем:

    System.out.println(diff("2019-02-23T16:50:21Z"));
    System.out.println(diff("2019-02-23T20:15:21Z"));

Вывод при запуске только сейчас:

3 hours
36 seconds

Импорт, который я использовал:

import org.threeten.bp.Instant;
import org.threeten.bp.temporal.ChronoUnit;
import org.threeten.bp.temporal.UnsupportedTemporalTypeException;

Instant не поддерживает более грубые единицы, чем дни (при 24 часах).Если вам нужно иметь возможность возвращать недели, месяцы или годы, просто используйте OffsetDateTime вместо Instant.

Вопрос: Могу ли я использовать java.time на своем уровне API Android?

Да, java.time прекрасно работает на старых и новых устройствах Android.Для этого требуется как минимум Java 6 .

  • В Java 8 и более поздних версиях и на более новых устройствах Android (начиная с уровня API 26) современный встроенный API.В этом случае импортируйте из java.time с подпакетами.
  • В Java 6 и 7 получите ThreeTen Backport, бэкпорт современных классов (ThreeTen для JSR 310; см. Ссылки внизу).
  • На (более старых) Android используется версия Android ThreeTen Backport.Это называется ThreeTenABP.И убедитесь, что вы импортируете классы даты и времени из org.threeten.bp с подпакетами.

Поток?

РЕДАКТИРОВАТЬ: @Basil Bourque спросил в комментарии:

Интересно, можно ли это сжать в поток, возможно, в одну строку?

Может, но я не думаю, что это будетпреимущество в этом случае:

    return IntStream.range(0, units.length)
            .map(i -> units.length - i - 1)
            .mapToObj(i -> units[i])
            .filter(then::isSupported)
            .filter(unit -> unit.between(then, now) != 0)
            .map(unit -> "" + unit.between(then, now) + ' ' + unit.toString().toLowerCase())
            .findFirst()
            .orElse("0");

Я нахожу код для возврата элементов массива, .map(i -> units.length - i - 1), немного трудным для чтения.Нам нужно вычислить разницу дважды, сначала для фильтрации, а затем для сборки строкового результата.Но это работает, и вы можете пойти с ним, если хотите.

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

            .flatMap(unit -> LongStream.of(unit.between(then, now))
                    .filter(diff -> diff != 0)
                    .mapToObj(diff -> "" + diff + ' ' + unit.toString().toLowerCase()))

Ссылки

0 голосов
/ 26 февраля 2019

Решение (библиотека ThreeTen-Backport):
Работает отлично, я уже опробовал его на эмуляторе KitKat.

private static final ChronoUnit[] chronoUnits = {ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS, ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS};
private static final Map<ChronoUnit, Integer> chronoUnitPluralIdMap = new HashMap<ChronoUnit, Integer>() {{
    put(ChronoUnit.YEARS, R.plurals.chrono_unit_years_ago);
    put(ChronoUnit.MONTHS, R.plurals.chrono_unit_months_ago);
    put(ChronoUnit.DAYS, R.plurals.chrono_unit_days_ago);
    put(ChronoUnit.HOURS, R.plurals.chrono_unit_hours_ago);
    put(ChronoUnit.MINUTES, R.plurals.chrono_unit_minutes_ago);
    put(ChronoUnit.SECONDS, R.plurals.chrono_unit_seconds_ago);
}};

public static String getTimeStringUntilNowFromUTC(Context context, String utcDate) {
    Instant now = Instant.now(Clock.systemUTC());
    Instant then = Instant.parse(utcDate);
    for (ChronoUnit chronoUnit : chronoUnits) {
        if (then.isSupported(chronoUnit)) {
            long units = chronoUnit.between(then, now);
            if (units > 0) {
                //noinspection ConstantConditions
                return context.getResources().getQuantityString(chronoUnitPluralIdMap.get(chronoUnit), (int)units, (int)units);
            }
        }
    }
    return "-";
}

public static String getTimeBetweenTwoDates(Context context, String date1, String date2) {
    Instant date1Instant = Instant.parse(date1);
    Instant date2Instant = Instant.parse(date2);
    final long seconds = ChronoUnit.SECONDS.between(date1Instant, date2Instant);
    return getMinutesSecondsString(context, seconds);
}
0 голосов
/ 22 февраля 2019

tl; dr

Для Android до 26 используйте библиотеку ThreeTen-ABP .

Избегайте устаревших классов даты и времени

Старые классы даты и времени, такие как Calendar и Date, являются ужасными , действительно, ужасно убогие классы.Они нагружены плохими дизайнерскими решениями и взломами, созданными людьми, которые не понимали обработку даты и времени.Избежать их.Они были полностью вытеснены java.time классами с принятием JSR 310 по причине - фактически, много причин.

Избегайте этих устаревших классов.Используйте только java.time классы.

ThreeTen-Backport библиотека

Для Java 6 и Java 7 большинство функций java.time перенесены в ThreeTen-Backport проект.

ThreeTen-ABP

Этот бэк-порт дополнительно адаптирован к более ранней версии Android (<26) в проекте <em>ThreeTen-ABP .

Я призываю вас добавить эту библиотеку в ваш проект, чтобы вы никогда не использовали трагические унаследованные классы.

Преобразование

Там, где вам нужно взаимодействовать со старым кодом, который еще не обновлен до java.time , конвертировать назад и вперед между устаревшим и современным.

В Java 8 и более поздних версиях выполните преобразование, вызвав новые методы to… и from…, найденные в старых классах.

В заднем порту выполните преобразование с использованием методов преобразования to…, имеющихся в классе org.threeten.bp.DateTimeUtils.

Истекшее время

Ваш вопрос говорит о подсчете прошедшего времени.

Для подсчета лет, месяцев и дней используйте Period.

Для подсчета дней (24-часовой период времени, не связанный с календарем), часов, минут, секунд и доли секунды, используйте Duration.

Поиск переполнения стека для получения дополнительной информации.Эти классы были покрыты уже много раз.


О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии.Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на java.time классы.

Вы можете обмениваться java.time объектами напрямую с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большинство функций java.time перенесено в Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии реализации связки Android java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

Проект ThreeTen-Extra расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

...