How many days from now is the Duration? - java

I have a Duration, like P3M (3 months). How can I get number of days it is from now?
All I have now is this:
Duration.parseWeekBasedPeriod("P3M")
I know the period parameter will never be shorter than 1 week, so parseWeekBasedPeriod() should be ok. But I'm reading JavaDoc, and I can't figure out how to get those days.
I understand, the problem is that months can has 31, 30, 29 and 28 days.

Using parseWeekBasedPeriod(...) is certainly wrong if you want to apply durations measured in months. This very special method handles week based years which can last either 364 or 371 days (52 or 53 weeks). So I suggest just to use the standard parsing method for calendar-based durations. The following code also strongly simplifies the evaluation of days between two dates (see last line).
Duration<CalendarUnit> duration = Duration.parseCalendarPeriod("P3M");
PlainDate today = PlainDate.nowInSystemTime();
PlainDate later = today.plus(duration);
long days = CalendarUnit.DAYS.between(today, later);
By the way, I have tested the method for weekbased durations once again. It will usually throw an exception if it tries to parse months. You didn't seem to have seen any exception so I assume that the fact that you use untyped constructs like "val" has shadowed the necessary type information in processing the duration string (and Time4J is a strongly typed library). Hence - if technically possible for you -, I strongly recommend to use type-safe code as shown in my solution.

Finaly figured it out:
val period = Duration.parseWeekBasedPeriod("P3M")
val start = PlainDate.nowInSystemTime()
val end = start.plus(period)
val days: Long = Duration.`in`(CalendarUnit.DAYS).between(start, end).getPartialAmount(CalendarUnit.DAYS)

Related

How to manipulate Ranges of Time of a Day

I'm working with an agenda in Java. I have stored in my database the day of the week, the start and end time of some labs availability.
Now I need to provide a service for a schedule system by showing only the unavailable times of the day. For example, if day one has start time 13:00 and end time 19:00, I need to return a range just like this:
[00:00 - 13:00, 19:00 - 23:59] . Remembering that a day can have more than a range available.
Is there any Java Class or API that could help me on subtracting these ranges?
My lib Time4J offers following solution for the subtraction problem:
ClockInterval fullDay = ClockInterval.between(PlainTime.of(0), PlainTime.of(24));
ClockInterval slot = ClockInterval.between(PlainTime.of(13, 0), PlainTime.of(19, 0));
IntervalCollection<PlainTime> icoll = IntervalCollection.onClockAxis().plus(fullDay);
List<ChronoInterval<PlainTime>> result = icoll.minus(slot).getIntervals();
The resulting list of half-open intervals (with open end) can be easily iterated through and gives the expected result {[T00:00/T13:00), [T19:00/T24:00)}. Every result interval can be converted to a standard ClockInterval, too. There are also various methods to print such intervals in a localized way. Furthermore, you might find the class DayPartitionBuilder interesting which allows to connect weekdays and time schedules in streaming, see the example given in the documentation.
About compatibility with java.time:
The between()-methods of ClockInterval also accept instances of java.time.LocalTime.
Every instance of PlainTime can be converted back to LocalTime by help of the method toTemporalAccessor() with the exception of the value 24:00 which exists in Time4J but not in java.time.LocalTime.

Print a Duration in human readable format by EL

First of all I'm new to java.time package.
I'm writing a webapp that need to work with specific times of the day and with several durations of events.
So I wrote my code using LocalTime and Duration classes of java.time package.
When I need to render their value in JSP it is very simple for LocalTime object (because .toString() returns a human readable vale), so I can just write ${startTime} and everything goes in the right way (e.g. it is rendered as 9:00).
The same approach doesn't work for Duration, because its representation is something like PT20M (in this case for 20 minutes).
Does it exist an elegant way to perform a human-readable conversion in JSP directly by EL?
Yes, I know I can convert the object in a string in my classes (before JSP), but I'm searching for the suggested approach (that I'm not able to find)... another point is that I not see an official "convert()" (or whatever else) method in Duration object... so I'm thinking I'm using the wrong object to map a duration of time (to add or subtract on LocalTimes).
Thank you.
Unfortunately there exists no elegant builtin way to format a Duration in Java 8. The best i have found is to use the method bobince describes in this answer:
Duration duration = Duration.ofHours(1).plusMinutes(20);
long s = duration.getSeconds();
System.out.println(String.format("%d:%02d:%02d", s/3600, (s%3600)/60, (s%60)));
Which prints:
1:20:00
The code will have to be tuned if you need longer durations.
I'm not sure what you mean that you are missing a convert method, but Duration is well suited for adding/subtracting on LocalTime. The methods LocalTime.plus() and LocalTime.minus() accepts Duration as argument.
If you're interested in words, apache commons will do the trick:
DurationFormatUtils.formatDurationWords(System.currentTimeMillis() - start, true, false))
2 days 1 hour 5 minutes 20 seconds
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/time/DurationFormatUtils.html#formatDurationWords-long-boolean-boolean-

is com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl#newDurationDayTime broken?

This:
com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl sun = new com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl();
final long aTime = TimeUnit.DAYS.toMillis(32)
System.err.println(sun.newDurationDayTime(aTime));
will print P1DT0H0M0.000S, or 0 months and 1 day if I use getMonths and getDays respectively.
I realize the months should not be set given what's said in the javadocs
whose lexical representation contains only day, hour, minute, and second components.
So months being 0 seems fine, but the number of days in that case should be 32.
If I use org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl I get the expected results, 32 days or P32DT0H0M0.000S.
Is the com.sum version broken, or is there something in the contract that is not mention that the plain xerces implementation is not strict about where that method cannot be used for durations >= one month?
Edit:
I can see in DurationDayTimeImpl w/in com.sum the constructor used in this case seems to get the duration correct. After the call to super the months are 1 and the days are 1. But then after canonicalizing the time component, the years and months are wiped out:
this.years = null;
this.months = null;
This is how it ends up with a value of a single day. I can see why it clears those values given what the javadocs say, but that seems like a bug to not down convert those into days.
The plain xerces impl simply divides off the individual components; the com.sun version uses XMLGregorianCalendar.

Getting JODA Duration to work

The following code does not print the days correctly, I need to print out days and minutes as well.
Duration duration = new Duration(1328223198241L - 1326308781131L);
Period p2 = new Period(duration.getMillis());
System.out.println(p2.getDays()); // prints 0, should print 22 days
System.out.println(p2.getHours()); // prints 531 which is expected.
According to the javadoc, "Only precise fields in the period type will be used. For the standard period type this is the time fields only. Thus the year, month, week and day fields will not be populated." thus you are getting zero.
Consider this alternative.
Duration duration = new Duration(1328223198241L - 1326308781131L);
Period p2 = new Period(duration.getMillis());
System.out.println(p2.getHours()); // prints 531 which is expected.
System.out.println(p2.toStandardDays().getDays()); // prints 22 days
This behavior is explained in the javadocs: "duration is larger than one day then all the remaining duration will be stored in the largest available precise field, hours in this case."
If you explain what you're trying to do, as opposed to how you're trying to do it, then I'm sure we'll be able to help out. For example, to find what I think you're trying to get from p2.getDays():
Days.daysBetween(dateTime1, dateTime2).getDays()
Does the following not suffice: System.out.println(duration.getStandardDays());

number of periods (custom) between two dates

I want to find out how many periods (custom) are there between two dates. Like how many weeks are between 1 july to 2nd Aug or how many half months are there between 2 nd Juy and 14 Dec, where in half month would be customizable whether it ends on 15th or 16th.
IS there any library where this or something similar has been done? Not that its tricky but just want to know if such things exists.
Joda Time is great but it doesn't have direct support for your needs, although it represents the concepts you want to handle
http://joda-time.sourceforge.net/quickstart.html
In particular, see http://joda-time.sourceforge.net/key_period.html
and the methods .dividedBy(int) and .multipliedBy(int)

Categories