How to handle full period in java.time?

后端 未结 3 1604
感情败类
感情败类 2020-12-07 00:50

The Period class in java.time handles only the date-oriented potion: years, months, days.

What about the time portion: hours, minutes, seconds?

How can we p

3条回答
  •  余生分开走
    2020-12-07 01:33

    Short answer related to java.time (JSR-310):

    No, that package does not offer a solution.

    Alternatively, you can use the class Duration in the package javax.xml.datatype for parsing strings like PnYnMnDTnHnMnS. This is also available in older JDK-versions since Java-5. Example:

    // parsing
    String iso = "P2Y4M30DT17H5M57.123S";
    javax.xml.datatype.Duration xmlDuration =
        DatatypeFactory.newInstance().newDuration(iso);
    int years = xmlDuration.getYears();
    int months = xmlDuration.getMonths();
    int days = xmlDuration.getDays();
    int hours = xmlDuration.getHours();
    int minutes = xmlDuration.getMinutes();
    int fullSeconds = xmlDuration.getSeconds();
    BigDecimal seconds = (BigDecimal) xmlDuration.getField(DatatypeConstants.SECONDS);
    
    // generating ISO-string
    String xml = xmlDuration.toString();
    System.out.println(xml); // P2Y4M30DT17H5M57.123S
    

    If you ask for limitations/issues, well, here you get a list:

    • Some (alternative) ISO-formats like P0001-04-20T4H cannot be parsed.

    • Some methods defined in javax.xml.datatype.Duration rely on an internal Calendar-instance (documented) so that those methods might not work if an instance of Duration holds very large values.

    • Working with fractional seconds might be awkward and sometimes limited in precision if operating on a Calendar-instance.

    • There is only one single normalization method using a Calendar-instance. At least this method takes into account DST-effects in a standard way.

    • Formatting (not even to mention localized printing) is not offered.

    If you want to overcome those issues then you can consider an external library (and yes, I don't only think of Joda-Time whose precision is constrained to millisecs and whose internationalization is limited, too). Otherwise the package javax.xml.datatype has the advantage to save the effort to embed an external library into your classpath.

    Update:

    About the question in comment related to external libraries, I know Joda-Time and my library Time4J.

    First one (Joda-Time) offers a special class called ISOPeriodFormat. This class is also able to parse alternative ISO-formats (although PyyyyWwwddThhmmss is not mentioned in original ISO-8601-paper while support for PYYYY-DDD is missing). Joda-Time defines a builder-driven approach for period formatters which can also be used for printing durations (periods). Furthermore, there is a limited support for localized printing (with version 2.9.3 of Joda-Time in 13 languages). Finally the class Period offers various normalization methods (see javadoc).

    Second one (Time4J) offers the classes net.time4j.Duration and two formatting tools (Duration.Formatter for pattern-based printing/parsing and net.time4j.PrettyTime for localized printing in actually 78 languages). The class Duration offers for parsing ISO-strings the static method parsePeriod(String) and also various normalizing methods. Example for the interoperability with java.time (JSR-310) proving that this library can be considered and used as powerful extension of new java-8-date-time-api:

    // input: using java.time-package
    LocalDateTime start = LocalDateTime.of(2016, 3, 7, 10, 15, 8);
    LocalDateTime stop = LocalDateTime.of(2016, 6, 1, 22, 15);
    
    // define how you measure the duration (zone correction would also be possible)
    Duration duration =
        TimestampInterval.between(start, stop).getDuration(
            CalendarUnit.YEARS,
            CalendarUnit.MONTHS,
            CalendarUnit.DAYS,
            ClockUnit.HOURS,
            ClockUnit.MINUTES,
            ClockUnit.SECONDS
        );
    
    // generate standard ISO-representation
    String s = duration.toStringISO();
    System.out.println(s); // P2M25DT11H59M52S
    
    // parse ISO-String and prove equality with original
    System.out.println(Duration.parsePeriod(s).equals(duration)); // true
    
    // adding duration to  yields 
    System.out.println(start.plus(duration.toTemporalAmount())); // 2016-06-01T22:15
    
    // format in human time
    System.out.println(PrettyTime.of(Locale.US).print(duration));
    // output: 2 months, 25 days, 11 hours, 59 minutes, and 52 seconds
    

    For completeness I should also mention ocpsoft.PrettyTime but I am not sure if that library is able to process ISO-strings. It is rather designed for relative times.

提交回复
热议问题