If I have two instants in JodaTime, for example
DateTime then=new DateTime(0);
DateTime now=DateTime.now();
and I want to get the number of years between these two dates, I can do
new Period(then,now).getYears();
or
Years.yearsBetween(then,now);
But the problem is that if the interval is not an exact number of years, both of these methods will return the floor of the number of years. So for example, of you have two instants which are two years and 11 months apart, it will still return "0" years.
Is there any way JodaTime provides to get the rounded number of years,months,etc?
The purpose of this is that I wish to display durations in a human friendly format, for example
1 year, 11 months, 30 days, 1 hour -> 2 years.
6 days 4 hours 1 minute -> 1 week
4 hours 18 minutes 5 seconds -> 4 hours
And so I'd like to display properly rounded amounts.
I think I could probably check whether the end of the interval is closer to N Units in the future or N+1 Units, but is there a better way to do this?
Related
I am using this to calculate the number of days difference in hebrew calendar and it returns correct days difference. Now I want to convert those days in the months or years.
But the problem is in the Hebrew calendar
A year in the Hebrew calendar can be 353, 354, 355, 383, 384, or 385
days long. Regular common years have 12 months with a total of 354
days. Leap years have 13 months and are 384 days long. Months with
uneven numbers usually have 30 days, while months with even numbers
have 29 days.
I have tried to divide the days with total days in a year but it has a different total number of days in the year. Can you please me an idea of how to achieve this?
Looks like a loop that keeps subtracting is the easiest to be understood. I guess you know the year at either end of the difference. Then a loop like this could work:
int yearBegin = 1234;
int daysDiff = calcDaysDiff(); // your existing routine
int yearAnalyzing = yearBegin;
int years = 0;
while (daysDiff > 0) {
int daysInThatYear = calcDaysInYear (yearAnalyzing); // you calc accdg your rules
while (daysDiff >= daysInThatYear) {
++years;
daysDiff -= daysinThatYear;
yearAnalyzing++; // or --, depending which direction you want to go
}
// less than a year is left
// calculate the months (should be easy)
}
If your beginning date starts in the middle of the year you would have to work these days off your difference first, before you start the loop.
You can use my lib Time4J which offers the feature to determine differences measured in years, months or days. Example (from a JUnit test case):
HebrewCalendar start = HebrewCalendar.of(5778, HebrewMonth.HESHVAN, 6);
HebrewCalendar end = HebrewCalendar.of(5778, HebrewMonth.ELUL, 6);
assertThat(HebrewCalendar.Unit.MONTHS.between(start, end), is(10));
start = start.plus(CalendarDays.ONE);
assertThat(HebrewCalendar.Unit.MONTHS.between(start, end), is(9));
start = start.minus(3, HebrewCalendar.Unit.YEARS);
assertThat(HebrewCalendar.Unit.YEARS.between(start, end), is(3));
start = start.plus(6, HebrewCalendar.Unit.YEARS).minus(CalendarDays.of(2)); // AM-5781-HESHVAN-5
assertThat(HebrewCalendar.Unit.YEARS.between(start, end), is(-2));
start = start.with(HebrewCalendar.MONTH_OF_YEAR, HebrewMonth.ELUL); // AM-5781-ELUL-5
assertThat(HebrewCalendar.Unit.MONTHS.between(start, end), is(-36));
start = start.plus(CalendarDays.ONE);
assertThat(HebrewCalendar.Unit.MONTHS.between(start, end), is(-37));
start = start.minus(37, HebrewCalendar.Unit.MONTHS);
assertThat(start, is(end));
The logic is somehow similar to the standard logic in the java.time-package. When the day-of-month of end date is smaller than that of start date, then the calculated month delta (or year delta) will be decreased by one.
Generally I cannot recommend to try to convert days into months or years applying a fixed factor because the Hebrew calendar has sometimes 12, sometimes 13 months. My lib does not try it, too, but applies an optimized kind of counting. It is also impossible to convert a day delta to a month delta without any further informations about start or end date for principal reasons:
Imagine the SAME day delta had been determined with a start date
short before Adar I (leap month) or with another month later. Then the month
delta will be different because the second case does not include a leap month!
More examples how to handle the Hebrew calendar can be seen in the API online.
If you are on Android then please use the specialized derivate Time4A with similar API.
This question already has answers here:
Get the number of weeks between two Dates.
(19 answers)
Closed 9 years ago.
Is it possible to determine the number of weeks between 2 dates in Java/JSP? For example if date one is 2013-10-29 and date two is 2013-11-12, I would like the number of weeks to be output.
Could somebody pleas help? :-)
Joda can help you, but I'm never able to use it because of its license.
If like me, Joda is not appropriate for you, you can solve this problem as follows:
initialize endDate object
initialize startDate object
initialize weeksBetween as
milliseconds between end&start/milliseconds per day, divided by seven (integer floor, ceiling or round this).
//may need to normalize dates and set them to be both midnight or noon or some common time
output weeksBetween
You can get the milliseconds between them by converting the calendars to Date (Calendar has such a method to do this).
I lifted this from: How to calculate the total hour worked between two dates?
You can use the Joda Time library :
Object Weeks, method weeksBetween :
Given a period such as 3 days, or 5 weeks (a period with only one field type), I want to round a given DateTime to the nearest unit of that period (i.e, ignore the 5 in '5 days'). Examples:
Example 1:
Period: 3 days.
DateTime: Wednesday 4:26 AM UTC (2013-05-15T04:26:00Z)
Rounded DateTime: Wednesday Midnight UTC (2013-05-15T00:00:00Z)
Example 2:
Period: 5 weeks.
DateTime: Wednesday 4:26 AM UTC (2013-05-15T04:26:00Z)
Rounded DateTime: Monday Midnight UTC (2013-05-13T00:00:00Z)
My initial idea was to use Period's DurationFieldType getFieldTypes() method, and for every matching field in a DateTime (below the largest field), set them to zero. However, I don't know how to get the DateTimeFieldTypes from a DateTime and how to compare them to a DurationFieldType.
I would prefer not to do a huge if else approach.
Example bellow is a solution in case you can express period in days (can be modified to weeks, months etc.). Using DateTime Joda Java Library.
Unfortunately with rounding you require I see possible issue. You need to have a starting point in time since when you calculate the periods. In example bellow we calculate periods since 1970/01/01 00:00:00 UTC. Or are you actually asking to get period of 3 days from first day of a month (year) etc? It would make more sense.
Questions you need to ask your self: What will happen on leap days?
Java Method
DateTime roundDays(DateTime dt, int windowDays) {
Duration p = Duration.standardDays(windowDays);
long t = dt.getMillis() / p.getMillis() * p.getMillis();
// Keep TimeZone and round floor to a day
return new DateTime(t, dt.getZone()).dayOfMonth().roundFloorCopy();
}
Example use:
DateTime dt = new DateTime(1385578964580L, DateTimeZone.UTC);
System.out.println(roundDays(dt, 3));
System.out.println(roundDays(dt.plusDays(2), 3));
System.out.println(roundDays(dt.plusDays(4), 3));
System.out.println(roundDays(dt.plusDays(6), 3));
// Prints data rounded to every 3 days
// 2013-11-26T00:00:00.000Z
// 2013-11-29T00:00:00.000Z
// 2013-11-29T00:00:00.000Z
// 2013-12-02T00:00:00.000Z
Too long for comment:
It's not clear what that "rounding" means. To start with, you should deal with LocalDateTimes, not with DateTimes (they are very different things, see my answer here ).
It seems to me you want to set to zero all fields with resolution lower than that of your "period" unit, and then set the next field to a multiple of the given value... is that so? Then, I don't understand your second example (where are the 5 weeks?), and anyway, that would be badly specified: what to do with a period of "40 months" ?
I try to calculate a List with times. But using LocalTime from Joda Time I can only get a 24 hours.
What is the right class to use to get e.g. 34hours 20minutes 14 seconds?
Thanks in advance
You may be look for Period:
A period in Joda-Time represents a period of time defined in terms of fields, for example, 3 years 5 months 2 days and 7 hours. This differs from a duration in that it is inexact in terms of milliseconds. A period can only be resolved to an exact number of milliseconds by specifying the instant (including chronology and time zone) it is relative to.
If you are looking to add times, so you can tell how many hours/seconds... are in between, you would maybe be better off if you use plain miliseconds calculations, add all the miliseconds and then subsrtact the miliseconds from your first time, and there you are, you have the span in miliseconds...
I'm trying to set my Period object using the "millis" constructor and have all the relevant fields be updated accordingly (years, months, weeks, days, hours, minutes, seconds)
That is, using the following code:
mPeriod = new Period(millis, PeriodType.standard());
doesn't fill all the relevant fields accordingly.
only weeks and minutes (for input millis of 1325965615539)
can someone please help me figure this thing out ?
You can normalize it using Period#normalizedStandard();
However, there's no way Period can "fill in all the relevant fields", because it can't make assumptions about the number of days in months or years. The best it can do is to turn it into weeks, days, and time fields.
The Javadoc touches on this, but not in great detail:
If the period contains years or months, then the months will be
normalized to be between 0 and 11. The days field and below will be
normalized as necessary, however this will not overflow into the
months field. Thus a period of 1 year 15 months will normalize to 2
years 3 months. But a period of 1 month 40 days will remain as 1 month
40 days.
(Emphasis mine)
If you need it to normalize into years and months, you need to construct the Period with values in those fields.
Alternatively, you could use a Duration:
Construct a Duration with milliseconds
Use Duration#toPeriodFrom(ReadableInstant) to create a Period starting at a given instant in time (e.g. new DateTime()). According to the docs, this should work:
This conversion will determine the fields of a period accurately. The
results are based on the instant millis, the chronology of the
instant, the standard period type and the length of this duration.
Here's what normalize() should do to your millisecond input:
import org.joda.time.Period;
class Normalize {
public static void main(String[] args) {
Period period = new Period(1325965615539L);
System.out.println(period);
System.out.println(period.normalizedStandard());
}
}
// outputs
PT368323H46M55.539S
P2192W2DT19H46M55.539S
Notice the second line has been normalized, but only up to weeks.