如何将 ISO 8601 句点转换为人类可读的字符串 [Android Studio]?

How to convert ISO 8601 period to a string readable by humans [Android Studio]?

关于如何将 ISO 8601 duration 格式 PnYnMnDTnHnMnS(例如:P1W、P5D、P3D)转换为天数有什么建议吗?

我正在尝试以向用户显示免费试用天数的方式设置按钮文本。

Google 通过密钥 "freeTrialPeriod" 以 ISO 8601 持续时间格式提供账单信息,但我需要用户可以实际阅读的数字。

应用程序当前的最低 API 级别是 18,因此 Java 8 的持续时间和周期 类 无济于事,因为它们适用于 APIs 等于或大于 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);
    }

有什么改进建议吗?

谢谢!

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 days

您需要添加一个检查以确保年份和月份是否为 0,或者如果不是,也将它们打印出来。使用 Period class.

getYearsgetMonths 方法

如您所见,周会自动转换为天。 Period class 在内部不代表周,仅代表年、月和日。支持所有示例字符串。可以解析P1Y(1年),P1Y6M(1年6个月),P1Y2M14D(1年2个月14天),甚至P1Y5DP2MP1M15DP35D,当然还有 P3W,等等

问题:我可以在 Android 上使用 java.time 吗?

是的,java.time 在新旧 Android 设备上都能很好地工作。它只需要至少 Java 6.

  • 在 Java 8 及更高版本和较新的 Android 设备上(从 API 级别 26),现代 API 是内置的。在这种情况下,从 java.time 而不是 org.threeten.bp.
  • 导入
  • 在 Java 6 和 7 中获取 ThreeTen Backport,新 classes 的 backport(ThreeTen 用于 JSR 310;请参阅底部的链接)。
  • 在(较旧的)Android 使用 ThreeTen Backport 的 Android 版本。它叫做 ThreeTenABP。并确保使用子包从 org.threeten.bp 导入日期和时间 classes。

链接

如果您确实想重新发明轮子,这里有一个解析 ISO 8601 持续时间的简单解决方案,它只支持 year/week/day 而不是时间部分,但当然可以添加。此解决方案的另一个限制是它期望不同类型(如果存在)按年->周->日

的顺序出现
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;
}

我需要转换成秒,

所以,我在看

@Joakim Danielson's

回答,

我稍微改进了正则表达式。请有需要的朋友参考。

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");
        }
    }