How to count the number of days between two LocalDate's in java?
I tried like this
LocalDate startDate = LocalDate.parse("2016-11-02");
LocalDate endDate = LocalDate.parse("2016-11-04");
long days = startDate.until(endDate, ChronoUnit.DAYS);
//and
long days= ChronoUnit.DAYS.between(startDate, endDate);
//and
long days= Duration.between(startDate.atStartOfDay(), endDate.atStartOfDay()).toDays();
All above are giving days between two dates, but how to count inclusive of both dates.
As per above steps, getting 2 days as no. of days, but required 3 days.
The javadoc is clear that the end date is not included in the calculation. So you can simply add 1:
long days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
If you want literal 24 hour days, you can use the Duration class instead:
long days = Duration.between(startDate.atStartOfDay(), endDate.atStartOfDay()).toDays() + 1;
For more information, please see this document regarding Java SE 8 Date and Time.
tl;dr
Beginning being inclusive, and ending being exclusive in a span of time is the norm.
If you absolutely cannot follow that approach, add one.
days = days + 1 ;
Half-Open
A common and wise way to define a span of time is the Half-Open approach. The beginning is inclusive while the ending is exclusive.
Sometimes, but not always, we use this approach intuitively in everyday life. For example, a classroom’s lunch period is said to be noon to 1 PM which means all the students are to be returned to class and ready before the class strikes 13:00. Class is said to run 1 PM to 2 PM. So the spans can abut one another without overlapping, and without the tricky task of determining the last moment of an infinitely divisible last second of last minute of that hour.
I suggest following this approach in all your date-time coding will make your code easier to read, easier to debug, and less error-prone by reducing the cognitive overload of resolving the inclusive-exclusive ambiguity.
The java.time classes use the Half-Open approach throughout.
long days = ChronoUnit.DAYS.between( start , stop ) ; // Half-open
If you code must return an ending-inclusive result, just add one to the java.time results.
long daysClosed = ( days + 1 ) ;
Ideally you would use Half-Open consistently in your code and in your user interface, while educating your users as to the issue of ambiguity. I have seen countless mistakes made by businesspeople wrongly assuming that date ranges were open (), closed [], or half-open [), and even occasionally the opposite half closed (] while the author meant another.
Related
I know there's a lot of questions about this but I couldn't find one that match with my case.
I have to know if a date is exactly x months after another.
With ChonoUnit it's just not possible because 2020/05/25 and 2020/07/27or 2020/07/25 will return the same number of month and I can't handle the difference with the days. I have the same type of response with JodaTime
I tried with Perdiod and it's not relevant either.
LocalDate localDate = LocalDate.of(2020,1,30);
LocalDate toTest = localDate.plusMonths(1L); // returns 2020/02/29
Period.between(localDate, toTest);
returns months 0, days 30
I read that the endDate is exclusive, so I tried adding a day
LocalDate localDate = LocalDate.of(2020,1,30);
LocalDate toTest = localDate.plusMonths(1L); // returns 2020/02/29
Period.between(localDate, toTest.plusDays(1L));
returns months 1, days 1
So my question is : Is there a method to get this information that is compatible with the way LocalDate handles the months ?
Edit
Ok, I was not precise enough in my request. I know a month is not an absolute value, and my conception of a month doesn't matter.
In my case I have a LocalDate input that I can't contraint. I have to generate outputs every X months minus Y number of days.
Knowing that I test in a schedule if today is exactly X months after my input minus Y days (to be precise, I test if the number of month between the two dates modulo X equals 0). But if my input is the 31st of the month, Period will never return me 1 months, 0 days. If it's the 30st and my output should trigger in february it will never be neither.
Given that if on the short months the output occurs one day before the inexistant logic date it's not a problem.
The exemple I gave with LocalDate is just extracted from my tests but it's the way I thank I could do the thing, thus without doing myself a complicated algorithm with many conditions.
I think you in your description you tried with January and February. That might be causing problem. So you have to manually handle this case. Otherwise your code is working.
A month is not exact time unit. Think about it: we can tell exactly how many seconds are in 1 minute, in 1 hour, 1 day and 1 week. But the number of seconds for different months would be different. So you need to define the logic what do you see as two dates that differ exactly one month? Once you define all the expected behaviors (including such cases as what is exactly one month from January 30th? Feb 28/29? or march 1st?) then you can see if there is anything out of the box that works for you or you need to implement your own logic
I have to know if a date is exactly x months after another.
That is an unclear request. One obvious interpretation would appear to be:
int monthA = a.getYear() * 12 + a.getMonthValue();
int monthB = b.getYear() * 12 + b.getMonthValue();
// Months.between can probably also be used instead of this math.
return a.getDayOfMonth() == b.getDayOfMonth() && (monthA - monthB) == x;
But that does mean it is -impossible- for a date to exist that is 'exactly 1 month after' March 30th: There is no feb 30th and there never will be.
Is that what you really wanted? Given that the length of a month depends on which month you ask, 'exactly 1 month later' is not a sensible question to ask. Hence: What do you actually mean?
Same day-of-month, X months later? (And realizing that there are many dates for which there cannot be such a date).
X days afterwards, where X is some formulaic approach based on which month we are in.
I probably still haven’t got it. Allow me a shot in spite, elaborating on my idea from the comment: If you like the way LocalDate.plusMonths() does, then use that method.
int monthsBetween = 3; // X
int daysBefore = 11; // Y
LocalDate originalDate = LocalDate.of(2020, Month.JANUARY, 30);
int nextTimeCount = 1; // next time to generate output will be the 1st time
LocalDate nextDate = originalDate.plusMonths(nextTimeCount * monthsBetween).minusDays(daysBefore);
LocalDate today = LocalDate.now(ZoneId.systemDefault());
while (! nextDate.isAfter(today)) {
System.out.format("Generating output no. %d for %s%n", nextTimeCount, nextDate);
nextTimeCount++;
nextDate = originalDate.plusMonths(nextTimeCount * monthsBetween).minusDays(daysBefore);
}
Output when I ran just now (December 30):
Generating output no. 1 for 2020-04-19
Generating output no. 2 for 2020-07-19
Generating output no. 3 for 2020-10-19
Assuming that your program will not be running uninterrupted for months you will need some way to persist the data, of course. So my code will not work as it stands, but if the behaviour is otherwise as expected, you can probably use the same mthod calls that I am using.
I was working with a school question to figure out the algorithm to find the days between two given dates which would then be implemented in Java.
The algorithm of interest was found here:
http://www.sunshine2k.de/articles/coding/datediffindays/calcdiffofdatesindates.html
(Point 4)
It was one of the more efficient algorithms because it would have the least conditions to consider during the implementation. I understand how it works in this context, but I couldn't quite wrap my mind around the use of an origin/reference point anywhere else because it seems that a simple subtraction would get most jobs done.
Eg. To find the difference between 9 and 5,
I could just do 9-5 instead of
ref = 1
difference = (9-ref) - (5-ref)
Question: Why does using this reference/origin point work in this situation? What other situations can I consider using this reference/origin point to solve problems?
First rule of Software Engineering is "Don't reinvent the wheel".
Getting the days between two dates in Java 8 and later is trivial, there's no need to code your own algorithm:
LocalDate d2 = LocalDate.now();
LocalDate d1 = LocalDate.of(1950, Month.JANUARY, 1);
long days = d1.until(d2,ChronoUnit.DAYS);
Or even better
long days = ChronoUnit.DAYS.between(d1, d2);
To get difference between 9-th and 5-th day of the same month, you can just subtract 9-5 (if there was no calendar revolution in that period :)). But for different months and different years you must account for varying number of days in the month and varying number of days in the year.
The simplest way to account for these factors is to get absolute number of days from some origin day - so-named Julian day with our era beginning as origin
Actually, 9-5 uses a reference of 0 in the same way as (9-0) - (5-0).
Unlike numbers, where 0 is the reference point, for dates, the reference point is not obvious. Should it be 0 AD, 1900 AD, or something else? With the different number of days in months, leap years etc, the day scale is not uniform. So, it is useful to find the "distance" of a date from a common date, for e.g. 1970-01-01.
I would like to know exactly how many months and days(possibly years) some older date is from today. Is there a method to do that?
I know how to get the difference of the months, I know how to get the difference in days. But I am unable to get the months and the days.
Ex:
old = '2013-03-04'
now = '2013-04-17'
so the result im looking for is something like 1 month(s) and 13* day(s)
*maybe its 12 im not every sure.
This can be done by using Period in JodaTime.
For example,
LocalDate old = new LocalDate(2013, 3, 4);
LocalDate now = new LocalDate(2013, 4, 17);
Period p = new Period(old, now, PeriodType.yearMonthDay());
To get the months, use p.getMonths(), to get the days p.getDays().
The result of the example is 1 month, 13 days.
Yes, see the documentation of intervals:
Intervals
An interval in Joda-Time represents an interval of time from one
instant to another instant. Both instants are fully specified instants
in the datetime continuum, complete with time zone.
Intervals are implemented as half-open, which is to say that the start
instant is inclusive but the end instant is exclusive. The end is
always greater than or equal to the start. Both end-points are
restricted to having the same chronology and the same time zone.
Two implementations are provided, Interval and MutableInterval, both
are specializations of ReadableInterval.
So I'm using JodaTime in an app I've got and I need a way to tell if the current time is within 6 hours of midnight. Well actually I need to know if the time is within 8 hours of 2am, but JodaTime seems to provide a constant for midnight so I was looking at that. Anyway, I've tried a number of different things but nothing quite works. Any help or pointers would be appreciated.
This can be accomplished simply by using JodaTime without any math involved.
DateTime time = new DateTime(DateTimeZone.UTC);
Period period = new Period(time, time.plusDays(1).toDateMidnight());
System.out.println(period.getHours());
The time.plusDays(1).toDateMidnight() (yes, I was lazy), is so that I'm comparing with the next midnight, and not with today's midnight (which already passed).
If you want to check both before and after, just check both periods.
I would suggest using a DateTime object.
DateTime date = new DateTime();
int i = getSecondOfDay();
Then using a little math we can find the number of seconds 6pm would be.
18hours*60min*60seconds= 64800 seconds.
if ( i > 64800 ){
// Do what you need here
}
I assumed you needed to tell if it was 8 hours of am of this current day and not a specific day.
This is a bit hardcoded and pcalcao's answer is probably more flexible:
private static boolean isLessThan8HoursFrom2AM(DateTime date) {
return (date.getHourOfDay() >= 18 || date.getHourOfDay() < 10);
}
You can also check if the time of day is 6 hours from midday.
if(Math.abs(timeOfDay - 43200) >= 21600) // first or last 6 hours of day.
Is there a Java package with all the annoying time constants like
milliseconds/seconds/minutes in a minute/hour/day/year? I'd hate to duplicate something like that.
I would go with java TimeUnit if you are not including joda-time in your project already. You don't need to include an external lib and it is fairly straightforward.
Whenever you need those "annoying constants" you usually need them to mutliply some number for cross-unit conversion. Instead you can use TimeUnit to simply convert the values without explicit multiplication.
This:
long millis = hours * MINUTES_IN_HOUR * SECONDS_IN_MINUTE * MILLIS_IN_SECOND;
becomes this:
long millis = TimeUnit.HOURS.toMillis(hours);
If you expose a method that accepts some value in, say, millis and then need to convert it, it is better to follow what java concurrency API does:
public void yourFancyMethod(long somePeriod, TimeUnit unit) {
int iNeedSeconds = unit.toSeconds(somePeriod);
}
If you really need the constants very badly you can still get i.e. seconds in an hour by calling:
int secondsInHour = TimeUnit.HOURS.toSeconds(1);
Java 8 / java.time solution
As an alternative to TimeUnit, you might for some reason prefer the Duration class from java.time package:
Duration.ofDays(1).getSeconds() // returns 86400;
Duration.ofMinutes(1).getSeconds(); // 60
Duration.ofHours(1).toMinutes(); // also 60
//etc.
Additionally, if you would go deeper and have analyzed how Duration.ofDays(..) method works, you would see the following code:
return create(Math.multiplyExact(days, SECONDS_PER_DAY), 0);
where SECONDS_PER_DAY is a package protected static constant from LocalTime class.
/**
* Seconds per day.
*/
static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
//there are also many others, like HOURS_PER_DAY, MINUTES_PER_HOUR, etc.
I think it is safe to assume that if there would be any package, which would defined "all the annoying time constants like miliseconds/seconds/minutes" as you call them, I believe Java SDK Developers would have use them.
Why are this LocalTime constants package protected and not public that is a good question, I believe there is a reason for that. For now it looks like you really have to copy them and maintain on your own.
If on android, I suggest:
android.text.format.DateUtils
DateUtils.SECOND_IN_MILLIS
DateUtils.MINUTE_IN_MILLIS
DateUtils.HOUR_IN_MILLIS
DateUtils.DAY_IN_MILLIS
DateUtils.WEEK_IN_MILLIS
DateUtils.YEAR_IN_MILLIS
Joda-Time contains classes such as Days, which contain methods such as toStandardSeconds(). So you can write:
int seconds = Days.ONE.toStandardSeconds();
although it seems a little verbose, and perhaps is only useful for more complex scenarios such as leap years etc.
The Java TimeUnit seems to be what you want
Joda Time also has a DateTimeConstants class with things like MILLIS_PER_SECOND, SECONDS_PER_MINUTE, MILLIS_PER_DAY, etc, etc.
Here's what I use for getting milliseconds.
import javax.management.timer.Timer;
Timer.ONE_HOUR
Timer.ONE_DAY
Timer.ONE_MINUTE
Timer.ONE_SECOND
Timer.ONE_WEEK
While TimeUnit discussed in this Answer and Duration discussed in this Answer probably more directly addresses the Question, there are some other handy units-of-time features in Java.
java.time
For units, see the ChronoUnit enum:
FOREVER
ERAS
MILLENNIA
CENTURIES
DECADES
YEARS
MONTHS
WEEKS
DAYS
HALF_DAYS
HOURS
MINUTES
SECONDS
MILLIS
MICROS
NANOS
The java.time package has sophisticated enums for DayOfWeek and Month. So rather than pass around a mere number or string, you can pass full-fledged objects such as DayOfWeek.TUESDAY or Month.FEBRUARY.
The java.time framework also includes classes such as MonthDay, YearMonth, and Year. Again, you can pass full-fledged objects rather than mere numbers or strings to make your code more self-documenting, ensure valid values, and provide type-safety.
Converting between TimeUnit and ChronoUnit
We can easily convert between TimeUnit and ChronoUnit. See the new methods added to the older class, TimeUnit.
TimeUnit.of( ChronoUnit )
TimeUnit::toChronoUnit()
ThreeTen-Extra project
The ThreeTen-Extra project provides additional classes to work with java.time. These include: DayOfMonth, DayOfYear, AmPm, Quarter, YearQuarter, YearWeek, Days, Weeks, Months, Years, and Interval.
One more approach with already baked (for multiple call) Duration instances (and 0 math operations):
ChronoUnit.DAYS.getDuration().getSeconds()
60 * 1000 miliseconds in 1 minute
60 seconds in 1 minute
1 minute in 1 minute
1/60 hours in 1 minute
1/(60*24) days in 1 minute
1/(60*24*365) years in 1 minute
1/(60*24*(365 * 4 + 1)) 4 years in 1 minute
* 60 is in 1 hour
* 60 * 24 is in 1 day
* 60 * 24 * 365 is in 1 year
etc.
Create them yourself, I guess, is the easiest. You can use the Date and Calendar classes to perform calculations with time and dates. Use the long data type to work with large numbers, such as miliseconds from 1 Januari 1970 UTC, System.currentTimeMillis().
If you mean to obtain the values Calendar have all fields related to time management, with some simple reflection you can do
Field[] fields = Calendar.class.getFields();
for (Field f : fields)
{
String fName = f.toString();
System.out.println(fName.substring(fName.lastIndexOf('.')+1).replace("_", " ").toLowerCase());
}
this will output:
era
year
month
week of year
week of month
date
day of month
day of year
day of week
day of week in month
am pm
hour
hour of day
minute
second
millisecond
zone offset
dst offset
field count
sunday
monday
tuesday
wednesday
thursday
friday
saturday
january
february
march
april
may
june
july
august
september
october
november
december
undecimber
am
pm
all styles
short
long
from which you can exclude what you don't need.
If you need just constants you have them: Calendar.DAY_OF_MONTH, Calendar.YEAR and so on..
If the constants are to be used as Compile-time constants (for example, as an attribute in an annotation), then Apache DateUtils will come in handy.
import org.apache.commons.lang.time.DateUtils;
DateUtils.MILLIS_PER_SECOND
DateUtils.MILLIS_PER_MINUTE
DateUtils.MILLIS_PER_HOUR
DateUtils.MILLIS_PER_DAY
These are primitive long constants.