Как преобразовать период 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
с подпакетами.
связи
- Учебник Oracle: Дата и время, объясняющие, как использовать
java.time
, Раздел Период и Длительность. - Запрос спецификации Java (JSR) 310, где
java.time
был впервые описан. - Проект ThreeTen Backport, бэкпорт
java.time
в Java 6 и 7 (ThreeTen для JSR-310). - ThreeTenABP, Android-версия ThreeTen Backport
- Вопрос: Как использовать ThreeTenABP в Android Project, с очень подробным объяснением.
- Статья в Википедии: ISO 8601
Если вы хотите заново изобрести колесо, это простое решение для анализа продолжительности 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");
}
}