4

How to convert java.time.Period to seconds?

The code below produces unexpected results

java.time.Period period = java.time.Period.parse( "P1M" );
final long days = period.get( ChronoUnit.DAYS ); // produces 0
final long seconds = period.get( ChronoUnit.SECONDS ); // throws exception

I am looking for the Java 8 equivalent to:

// import javax.xml.datatype.DatatypeFactory;
// import javax.xml.datatype.Duration;

DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
Duration d1 = datatypeFactory.newDuration( "P1M" ); 
final long sec = d1.getTimeInMillis( new Date() ) / 1000;
  • [`Period`](https://docs.oracle.com/javase/8/docs/api/java/time/Period.html) is described as a "date-based amount of time". It doesn't support fields finer than days. What could possibly be the correct answer to "the number of seconds in one month" anyway? – khelwood Jan 27 '17 at 12:28
  • 1
    So I did not get the point. The older class javax.xml.datatype.Duration is much better as the newer java.time.Period and Duration duo? I thought migration to Java 8 will bring me benefits, but I see it is better to stay with the old code and do not touch Period and Duriation classes from Java 8. – Seweryn Habdank-Wojewódzki Jan 27 '17 at 12:53

2 Answers2

12

As it says in the documentation, Period is a period of time expressed in days, months, and years; your example is "one month."

The number of seconds in a month is not a fixed value. February has 28 or 29 days while December has 31, so "one month" from (say) February 12th has fewer seconds than "one month" from December 12th. On occasion (such as last year), there's a leap second in December. Depending on the time zone and month, it might have an extra 30 minutes, hour, or hour and a half; or that much less than usual, thanks to going into or out of daylight saving time.

You can only ask "Starting from this date in this timezone, how many seconds are there in the next [period] of time?" (or alternately, "How many seconds in the last [period] before [date-with-timezone]?") You can't ask it without a reference point, it doesn't make sense. (You've now updated the question to add a reference point: "now".)

If we introduce a reference point, then you can use a Temporal (like LocalDateTime or ZonedDateTime) as your reference point and use its until method with ChronoUnit.MILLIS. For example, in local time starting from "now":

LocalDateTime start = LocalDateTime.now();
Period period = Period.parse("P1M");
LocalDateTime end = start.plus(period);
long milliseconds = start.until(end, ChronoUnit.MILLIS);
System.out.println(milliseconds);

Live Copy

Naturally, that can be more concise, I wanted to show each step. More concise:

LocalDateTime start = LocalDateTime.now();
System.out.println(start.until(start.plus(Period.parse("P1M")), ChronoUnit.MILLIS));
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Honestly spoken I disagree with all those downgrades and the last statement, if we consider that javax.xml.datatype.Duration class is correct. For example the code works well: DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); Duration d1 = datatypeFactory.newDuration( "P1M" ); final long sec = d1.getTimeInMillis( new Date() ); – Seweryn Habdank-Wojewódzki Jan 27 '17 at 12:49
  • @SewerynHabdank-Wojewódzki: `java.xml.datatype.Duration`'s `getTimeInMillis` **supports** my final statement: Notice how it accepts a reference point in time as an argument. Your code tells you how many milliseconds there are in the month starting "now." To do the equivalent of that, use `ZonedDateTime`'s [`plus`](http://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html#plus-java.time.temporal.TemporalAmount-) and pass in your `Period` and then determine milliseconds between the two points in time. – T.J. Crowder Jan 27 '17 at 12:53
  • If I would expect that seconds in P1M is fixed value, I would define "constant" value in the application and do not use Period class. – Seweryn Habdank-Wojewódzki Jan 27 '17 at 13:00
  • 1
    This is the core of my question. What is the optimal way to get seconds. I understand that reviewers think I am idiot. But for me is not clear now to get such a calculations with Java 8 spirit. Especially that ava.xml.datatype.Duration may hold both Date based Period/Duriation and time based Period/Duriation. Java 8 splited responsibility, what makes problems in usage when the string might be time or date dased. So it is not my point to get fixed whatever value, but I would like to get this calculation done well with respect to Java 8 API. – Seweryn Habdank-Wojewódzki Jan 27 '17 at 13:05
  • @SewerynHabdank-Wojewódzki: I've updated the answer to show one way to get a month **from now** (the "from now" was the missing part of your question) with the Java 8 API. – T.J. Crowder Jan 27 '17 at 13:16
-2

The "get" method accepts only ChronoUnit.YEARS, ChronoUnit.MONTHS and ChronoUnit.DAYS.