Как преобразовать период ISO 8601 в строку, читаемую людьми [Android Studio]?

Любые предложения о том, как конвертировать формат продолжительности ISO 8601 PnYnMnDTnHnMnS (например: P1W, P5D, P3D) на количество дней?

Я пытаюсь настроить текст кнопки таким образом, чтобы дни бесплатной пробной версии отображались для пользователя.

Google предоставляет информацию для выставления счетов в формате продолжительности ISO 8601 с помощью ключа "freeTrialPeriod", но он мне нужен в цифрах, которые пользователь действительно может прочитать.

Текущий минимальный уровень API приложения - 18, поэтому классы Duration и Period из Java 8 не помогут, поскольку они предназначены для API, равных или превышающих 26.

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

private String getTrialPeriodMessage() {
        String period = "";

        try {
            period = subsInfoObjects.get(SUBS_PRODUCT_ID).getString("freeTrialPeriod");
        } catch (Exception e) {
            e.printStackTrace();
        }

        switch (period) {
            case "P1W":
                period = "7";
                break;
            case "P2W":
                period = "14";
                break;
            case "P3W":
                period = "21";
                break;
            case "P4W":
                period = "28";
                break;
            case "P7D":
                period = "7";
                break;
            case "P6D":
                period = "6";
                break;
            case "P5D":
                period = "5";
                break;
            case "P4D":
                period = "4";
                break;
            case "P3D":
                period = "3";
                break;
            case "P2D":
                period = "2";
                break;
            case "P1D":
                period = "1";
        }

        return getString(R.string.continue_with_free_trial, period);
    }

Любые предложения о том, как его улучшить?

Спасибо!

3 ответа

Решение

java.time и ThreeTenABP

Это существует Не стоит изобретать велосипед.

import org.threeten.bp.Period;

public class FormatPeriod {

    public static void main(String[] args) {
        String freeTrialString = "P3W";
        Period freeTrial = Period.parse(freeTrialString);
        String formattedPeriod = "" + freeTrial.getDays() + " days";
        System.out.println(formattedPeriod);
    }
}

Эта программа выводит

21 день

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

Как видите, недели автоматически конвертируются в дни. Period класс не представляет недели внутри, только годы, месяцы и дни. Все ваши примеры строк поддерживаются. Вы можете разобрать P1Y (1 год), P1Y6M(1 год 6 месяцев), P1Y2M14D (1 год 2 месяца 14 дней), даже P1Y5D, P2M, P1M15D, P35D и конечно P3W, так далее.

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

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

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

связи

Если вы хотите заново изобрести колесо, это простое решение для анализа продолжительности ISO 8601, оно поддерживает только год / неделю / день, а не часть времени, но, конечно, его можно добавить. Другое ограничение этого решения состоит в том, что он ожидает, что различные типы, если они присутствуют, поступают в следующем порядке: год-> неделя-> день

private static final String REGEX = "^P((\\d)*Y)?((\\d)*W)?((\\d)*D)?";

public static int parseDuration(String duration) {            
    int days = 0;

    Pattern pattern = Pattern.compile(REGEX);
    Matcher matcher = pattern.matcher(duration);

    while (matcher.find()) {

        if (matcher.group(1) != null ) {
            days += 365 * Integer.valueOf(matcher.group(2));
        }
        if (matcher.group(3) != null ) {
            days += 7 * Integer.valueOf(matcher.group(4));
        }
        if (matcher.group(5) != null ) {
            days +=  Integer.valueOf(matcher.group(6));
        }

    }
    return days;
}

Мне нужно было преобразовать в секунды,

Итак, я смотрю на

@Йоаким Дэниелсон

отвечать,

Я немного улучшил регулярное выражение. Пожалуйста, обратитесь к тем, кто в этом нуждается.

      private int changeIso8601TimeIntervalsToSecond(String duration) throws Exception {

        //P#DT#H#M#S
        String REGEX = "^P((\\d*)D)?T((\\d*)H)?((\\d*)M)?((\\d*)S)?$";

        Pattern pattern = Pattern.compile(REGEX);
        Matcher matcher = pattern.matcher(duration);

        int seconds = 0;
        boolean didFind = false;

        while(matcher.find()){

            didFind = true;

            //D
            if(matcher.group(1) != null){
               seconds += 60 * 60 * 24 * Integer.parseInt(Objects.requireNonNull(matcher.group(2)));
            }

            //H
            if(matcher.group(3) != null){
                seconds += 60 * 60 * Integer.parseInt(Objects.requireNonNull(matcher.group(4)));
            }

            //M
            if(matcher.group(5) != null){
                seconds += 60 * Integer.parseInt(Objects.requireNonNull(matcher.group(6)));
            }

            //S
            if(matcher.group(7) != null){
                seconds += Integer.parseInt(Objects.requireNonNull(matcher.group(8)));
            }
        }

        if(didFind){
            return seconds;
        }else{
            throw new Exception("NoRegularExpressionFoundException");
        }
    }
Другие вопросы по тегам