Joda time, Period from millis - java

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.

Related

Difference Between Two Joda DateTime In Months and Left Over Days

I have a requirement to get the amount of months between two DateTime objects and then get the number of days left over.
Here is how I get the months between:
Months monthsBetween = Months.monthsBetween(dateOfBirth,endDate);
I am unsure how to then find out how many days are left over into the next month. I have tried the following:
int offset = Days.daysBetween(dateOfBirth,endDate)
.minus(monthsBetween.get(DurationFieldType.days())).getDays();
But this does not have the desired effect.
Use a org.joda.time.Period:
// fields used by the period - use only months and days
PeriodType fields = PeriodType.forFields(new DurationFieldType[] {
DurationFieldType.months(), DurationFieldType.days()
});
Period period = new Period(dateOfBirth, endDate)
// normalize to months and days
.normalizedStandard(fields);
The normalization is needed because the period usually creates things like "1 month, 2 weeks and 3 days", and the normalization converts it to "1 month and 17 days". Using the specific DurationFieldType's above also makes it convert years to months automatically.
Then you can get the number of months and days:
int months = period.getMonths();
int days = period.getDays();
Another detail is that when using DateTime objects, the Period will also consider the time (hour, minute, secs) to know if a day has passed.
If you want to ignore the time and consider only the date (day, month and year), don't forget to convert them to LocalDate:
// convert DateTime to LocalDate, so time is ignored
Period period = new Period(dateOfBirth.toLocalDate(), endDate.toLocalDate())
// normalize to months and days
.normalizedStandard(fields);

How to convert a Duration to Period in Joda?

Can someone explain why the following tests fails?
#Test
public void testDuration() {
Duration duration = Duration.standardDays(1);
assertTrue(duration.getStandardMinutes() == 1440); //OK
assertTrue(duration.toPeriod().getMinutes() == 1440); //NOK. result = 0
assertTrue(new Period(duration.getMillis()).getMinutes() == 1400); //NOK. result = 0
}
A Period in JodaTime represents a "set of duration field values". Therefore, the methods getMinutes(), getHours(), ... are returning the value of those fields rather than computing the minutes, hours, ...
Furthermore, the conversion from a Duration sets the fields according to a PeriodType and a chronology.
From the API (http://joda-time.sourceforge.net/apidocs/org/joda/time/ReadableDuration.html#toPeriod%28%29):
Period toPeriod()
Converts this duration to a Period instance using the standard period type and the ISO chronology.
Only precise fields in the period type will be used. Thus, only the hour, minute, second and millisecond fields on the period will be used. The year, month, week and day fields will not be populated.
If the duration is small, less than one day, then this method will perform as you might expect and split the fields evenly. If the duration is larger than one day then all the remaining duration will be stored in the largest available field, hours in this case.
This means, as a Duration's day has exactly 24 hours, all information is stored in the hours field and minutes stays at 0.
See this question for a good explanation of the differences between Interval, Duration and Period.
See here
A period of 1 day is not equal to a period of 24 hours, nor 1 hour equal to 60 minutes. This is because periods represent an abstracted definition of a time period (eg. a day may not actually be 24 hours, it might be 23 or 25 at daylight savings boundary).

Round down a DateTime based on a given Period using Joda-Time

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" ?

Adding times, calculate total time

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...

Joda-Time: what's the difference between Period, Interval and Duration?

In Joda-Time 2, what is the difference between the three kinds of time spans:
Period
Interval
Duration
Why do we need three classes?
Which one performs better?
Why is dividing a Period or Duration or Interval instance not implemented? E.g. p = p.divideBy(2);
3 classes are needed because they represent different concepts so it is a matter of picking the appropriate one for the job rather than of relative performance. From the documentation with comments added by me in italics:
An interval in Joda-Time represents an interval of time from one millisecond instant to another instant. Both instants are fully specified instants in the datetime continuum, complete with time zone. Specific times are defined e.g. this might be the interval between 20:00:00GMT yesterday and 09:00:00GMT this morning.
A duration in Joda-Time represents a duration of time measured in milliseconds. The duration is often obtained from an interval. i.e. we can subtract start from end of an interval to derive a duration
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. e.g. consider the period of 1 year, if we add this to January 1st we will always arrive at the next January 1st but the duration will depend on whether the intervening year is a leap year or not. Similarly if we add 1 month to the 1st of a month then we will arrive at the 1st of the next month but the duration (in milliseconds) will vary based on the month in question
For question 3, A specific method to divide a duration is not really needed because we can always get the number of milliseconds from the duration as a long (using getMillis()), divide it and construct a new duration (using new Duration(long duration)).
Dividing a period doesn't really have a real meaning based on the definition of a period above. e.g. what is half a month? (its length would depend on which month).
To add to mikej's answer:
A Joda-Time duration is a "physical" time interval; eg:
12000 milliseconds <-- this is a duration
A Joda-Time interval is actually a pair of instants (start instant - end instant). An instant is, again, a "physical" concept, a point in the timeline. Eg (just a possible notation):
(2010/3/3 19:00:00.000 UTC ; 2010/3/3 20:00:00.000 UTC) <-- this is an interval
An interval, then, can be converted to a duration, but not the reverse.
Consider these two intervals:
I1=(2010/3/3 19:00:00.000 UTC ; 2010/3/3 20:00:00.000 UTC)
I2=(2010/3/3 21:00:00.000 UTC ; 2010/3/3 22:00:00.000 UTC)
As intervals, I1 and I2 are different, because the end-points are different; but if I convert them to durations, I get the same thing: 3600000 milliseconds.
(Math analogy: the intervals [10,12] and [95,97] are different intervals, but they have the same length: "interval length" maps to duration).
Finally, a period is a lapse of "civil time", expressed as a number of months, days, hours, etc. It does not -by itself- represent a "physical" interval, hence it can't be directly converted to a duration (months have variable lengths...).
This answers question 3: you can only divide by two a physical time (a duration).

Categories