Формат Продолжительность времени

Я провел все утро, пытаясь найти способ выполнить то, что я изначально считал относительно простой задачей: преобразовать продолжительность времени, выраженную в числовом виде, в удобочитаемый вид. Например, для ввода 3,5 вывод должен быть «3 года и 6 месяцев».

Судя по тому, что я читал, настоятельно рекомендуется библиотека Joda Time. Используя эту библиотеку и следуя этому сообщению, я пробовал такие вещи, как:

    Period p = new Period(110451600000L); // 3 years and a half

    PeriodFormatter formatter = new PeriodFormatterBuilder()
        .appendYears()
        .appendSuffix(" year", " years")
        .appendSeparator(" and ")
        .appendMonths()
        .appendSuffix(" month", " months")
        .toFormatter();

    System.out.println(formatter.print(p));

Но на выходе ничего. Не знаю, почему это не работает.

Я также пытался использовать Apache DurationFormatUtils, но не работает.

У кого-нибудь есть идея?

Заранее спасибо.


person Alejandro García Seco    schedule 03.09.2012    source источник
comment
Возможно, вас заинтересует этот очень старый ответ. stackoverflow.com/a/12/559299   -  person Hinton    schedule 03.09.2012
comment
Хинтон, большое спасибо за быстрый ответ. Хотя предложенный вами ответ предназначен для С#, я думаю, что смогу легко адаптировать алгоритм. Тем не менее, это было бы мое последнее решение, потому что я считаю, что, например, должен быть более простой и чистый способ использования Joda Time. Мой приоритет - не изобретать велосипед :D Еще раз спасибо за ваш ответ!   -  person Alejandro García Seco    schedule 03.09.2012


Ответы (2)


После некоторых исследований, тестов и помощи Бенджамина у меня есть решение:

    DateTime dt = new DateTime(); // Now
    DateTime plusDuration = dt.plus(new Duration(110376000000L)); // Now plus three years and a half

    // Define and calculate the interval of time
    Interval interval = new Interval(dt.getMillis(), plusDuration.getMillis());

    // Parse the interval to period using the proper PeriodType
    Period period = interval.toPeriod(PeriodType.yearMonthDayTime());

    // Define the period formatter for pretty printing the period
    PeriodFormatter pf = new PeriodFormatterBuilder()
            .appendYears().appendSuffix("y ", "y ")
            .appendMonths().appendSuffix("m", "m ").appendDays()
            .appendSuffix("d ", "d ").appendHours()
            .appendSuffix("h ", "h ").appendMinutes()
            .appendSuffix("m ", "m ").appendSeconds()
            .appendSuffix("s ", "s ").toFormatter();

    // Print the period using the previously created period formatter
    System.out.println(pf.print(period).trim());

Я нашел действительно полезной официальную документацию Joda-Time и особенно этот пост: Правильное определение продолжительности с помощью JodaTime

Тем не менее, хотя это работает, я не на 100% доволен, потому что вывод приведенного выше кода - «3 года 6 м 11 часов», и я не понимаю причину этих одиннадцати часов: S В любом случае, мне нужна только точность лет и месяцев, поэтому я считаю, что это не большая проблема. Если кто-нибудь знает причину и / или может ли это быть проблемой в определенных сценариях, сообщите мне об этом в комментарии.

person Alejandro García Seco    schedule 10.09.2012

Период p в вашем коде не содержит лет или месяцев, поэтому форматер вообще ничего не выводит. Используя форматер PeriodFormat.getDefault(), вы бы увидели, что он содержит часы, а именно 30681 = 110451600000/1000/60/60.

И вот почему: миллисекунды могут быть преобразованы в секунды, минуты и часы определенным образом. Но вычисление количества дней, месяцев или лет неоднозначно, поскольку количество часов в сутках может быть разным (сдвиг часового пояса), равно как и количество дней в месяце и количество дней в году. См. документацию: http://joda-time.sourceforge.net/apidocs/org/joda/time/Period.html#Period%28long%29

Как там нашел:

Для большего контроля над процессом преобразования у вас есть два варианта:

  • преобразовать продолжительность в интервал и оттуда получить период
  • укажите тип периода, который содержит точное определение дня и более крупные поля, такие как UTC
person benjamin    schedule 03.09.2012
comment
Отличное объяснение, теперь, по крайней мере, я понимаю, почему мой код не работает, и это действительно имеет смысл. С другой стороны, я совершенно не понимаю, как реализовать это с точки зрения выполнения чего-либо, что имеет смысл, принимая во внимание, что время, которое мне нужно преобразовать, — это не что иное, как количество времени или продолжительности и ничего больше. Любое предложение? Большое спасибо Бенджамин. - person Alejandro García Seco; 03.09.2012
comment
Кстати, прежде чем спрашивать, я пробовал с PeriodType.YearMonthDay, как говорится в документации, но у меня был тот же результат. - person Alejandro García Seco; 03.09.2012
comment
Ну, фактическое решение вашей проблемы зависит от того, откуда берется ваше количество миллисекунд. Вы можете использовать фактическое время следующим образом: new Duration(new DateTime(), new DateTime().plus(millis)).toPeriod();, что иногда может составлять 3 года и 5 месяцев, в зависимости от того, когда выполняется код. Или вы говорите, что миллисекунды всегда являются «нормальными» днями и годами, а затем делите свои миллисекунды на (1000 * 60 * 60 * 24 * 365) и округляйте до следующего целого числа. Но это довольно грязно. Было бы лучше указать соответствующий тип периода, но у меня нет опыта в этом. - person benjamin; 03.09.2012
comment
Спасибо Бенджамин. Ну, мое количество миллисекунд исходит из десятичного числа, которое представляет количество времени в годах (например, 3,5 года). Я пытаюсь преобразовать количество лет в миллисекунды (3,5 года = 110376000000 мс) для дальнейшего форматирования текста, например, 3 года и 6 месяцев. Возможно, я столкнулся с неправильным подходом... как вы думаете? - person Alejandro García Seco; 03.09.2012
comment
Я не знаю, имеете ли вы на это влияние, но вы могли бы изменить способ ввода лет таким образом, чтобы вы получали два целых числа для лет и мотыльков отдельно, а не десятичную дробь. Если это невозможно, сделайте что-нибудь вроде int allMoths = (int) (yearsDecimal * 12); int years = months / 12; int months = allMonths % 12;. Но обратите внимание, что это может привести к потере точности (подумайте о yearsDecimal = 3,14159). Я определенно предпочел бы первое предложение. - person benjamin; 03.09.2012
comment
Нет, я не имею на это влияния, потому что введенные годы представляют собой сгенерированную сумму после нескольких вычислений. Честно говоря, первая идея, которая у меня была, была чем-то похожа на ваше последнее предложение, путем разделения целых и десятичных частей числа, но я думаю, что это немного грязно и сложно, хе-хе-хе. Вот почему я попробовал Joda Time, думая, что у него будут утилиты для решения моей проблемы в чистом виде. Что ж, я подумаю о решении и опубликую его, когда оно заработает, поэтому оно может быть полезно для других с той же проблемой. Большое спасибо bejamin за столь конструктивный разговор! - person Alejandro García Seco; 03.09.2012
comment
Бенджамин, я разместил решение. Спасибо за вашу помощь. - person Alejandro García Seco; 10.09.2012