This question already has answers here:
How do I check if a date is within a certain range?
(17 answers)
Closed 7 years ago.
One thing I want to know is how to calculate what date will it be 10 days from today.
Second thing is to check if one Date is between two other Dates.
For example, let's say I have an app that shows what events I need to do in the next 10 days (planner). Now how can I see if the date I assigned to an event is between today and the date that is 10 days from today?
Manipulating and comparing dates using java.util.Date and java.util.Calendar is pretty a pain, that's why JodaTime exist. None of the answers as far have covered the time in question. The comparisons may fail when the dates have a non-zero time. It's also unclear whether you want an inclusive or exclusive comparison. Most of the answers posted so far suggest exclusive comparision (i.e. May 24 is not between May 20 and May 24) while in real it would make more sense to make it inclusive (i.e. May 24 is between May 20 and May 24).
One thing I want to know is how to calculate what date will it be 10 days from today.
With the standard Java SE 6 API, you need java.util.Calendar for this.
Calendar plus10days = Calendar.getInstance();
plus10days.add(Calendar.DAY_OF_YEAR, 10);
With JodaTime you would do like this:
DateTime plus10days = new DateTime().plusDays(10);
Second thing is to check if one Date is between two other Dates. For example, let's say I have an app that shows what events I need to do in the next 10 days (planner). Now how can I see if the date I assigned to an event is between today and the date that is 10 days from today?
Now comes the terrible part with Calendar. Let's prepare first:
Calendar now = Calendar.getInstance();
Calendar plus10days = Calendar.getInstance();
plus10days.add(Calendar.DAY_OF_YEAR, 10);
Calendar event = Calendar.getInstance();
event.set(year, month - 1, day); // Or setTime(date);
To compare reliably using Calendar#before() and Calendar#after(), we need to get rid of the time first. Imagine it's currently 24 May 2010 at 9.00 AM and that the event's date is set to 24 May 2010 without time. When you want inclusive comparison, you would like to make it return true at the same day. I.e. both the (event.equals(now) || event.after(now)) or -shorter but equally- (!event.before(now)) should return true. But actually none does that due to the presence of the time in now. You need to clear the time in all calendar instances first like follows:
calendar.clear(Calendar.HOUR);
calendar.clear(Calendar.HOUR_OF_DAY);
calendar.clear(Calendar.MINUTE);
calendar.clear(Calendar.SECOND);
calendar.clear(Calendar.MILLISECOND);
Alternatively you can also compare on day/month/year only.
if (event.get(Calendar.YEAR) >= now.get(Calendar.YEAR)
&& event.get(Calendar.MONTH) >= now.get(Calendar.MONTH)
&& event.get(Calendar.DAY_OF_MONTH) >= now.get(Calendar.DAY_OF_MONTH)
{
// event is equal or after today.
}
Very verbose all.
With JodaTime you can just use DateTime#toLocalDate() to get the date part only:
LocalDate now = new DateTime().toLocalDate();
LocalDate plus10days = now.plusDays(10);
LocalDate event = new DateTime(year, month, day, 0, 0, 0, 0).toLocalDate();
if (!event.isBefore(now) && !event.isAfter(plus10days)) {
// Event is between now and 10 days (inclusive).
}
Yes, the above is really all you need to do.
public static boolean between(Date date, Date dateStart, Date dateEnd) {
if (date != null && dateStart != null && dateEnd != null) {
if (date.after(dateStart) && date.before(dateEnd)) {
return true;
}
else {
return false;
}
}
return false;
}
EDIT: Another suggested variant:
public Boolean checkDate(Date startDate, Date endDate, Date checkDate) {
Interval interval = new Interval(new DateTime(startDate),
new DateTime(endDate));
return interval.contains(new DateTime(checkDate));
}
Use JodaTime calendar replacement classes: http://joda-time.sourceforge.net/
You can use before, after and compareTo methods of Date class.
Here're some examples
http://www.roseindia.net/java/example/java/util/CompareDate.shtml
http://www.javafaq.nu/java-example-code-287.html
http://www.esus.com/javaindex/j2se/jdk1.2/javautil/dates/comparingdates.html
And here's API on Date class
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Date.html
Good Luck!
To add ten days:
Date today = new Date();
Calendar cal = new GregorianCalendar();
cal.setTime(today);
cal.add(Calendar.DAY_OF_YEAR, 10);
To check if between two dates:
myDate.after(firstDate) && myDate.before(lastDate);
To check if date is between two dates, here is simple program:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
String oeStartDateStr = "04/01/";
String oeEndDateStr = "11/14/";
Calendar cal = Calendar.getInstance();
Integer year = cal.get(Calendar.YEAR);
oeStartDateStr = oeStartDateStr.concat(year.toString());
oeEndDateStr = oeEndDateStr.concat(year.toString());
Date startDate = sdf.parse(oeStartDateStr);
Date endDate = sdf.parse(oeEndDateStr);
Date d = new Date();
String currDt = sdf.format(d);
if((d.after(startDate) && (d.before(endDate))) || (currDt.equals(sdf.format(startDate)) ||currDt.equals(sdf.format(endDate)))){
System.out.println("Date is between 1st april to 14th nov...");
}
else{
System.out.println("Date is not between 1st april to 14th nov...");
}
}
I took the initial answer and modified it a bit. I consider if the dates are equal to be "inside"..
private static boolean between(Date date, Date dateStart, Date dateEnd) {
if (date != null && dateStart != null && dateEnd != null) {
return (dateEqualOrAfter(date, dateStart) && dateEqualOrBefore(date, dateEnd));
}
return false;
}
private static boolean dateEqualOrAfter(Date dateInQuestion, Date date2)
{
if (dateInQuestion.equals(date2))
return true;
return (dateInQuestion.after(date2));
}
private static boolean dateEqualOrBefore(Date dateInQuestion, Date date2)
{
if (dateInQuestion.equals(date2))
return true;
return (dateInQuestion.before(date2));
}
Related
I am asking this question cause actually I have absolutely no way to test this case, and maybe someone could explain it to me :)
I have been working on a piece of code that was written by a person who is very new to programming. This code looks like this:
List<Date> dateList = infoFacade.getDateFrom(documentId);
for(Date from : dateList) {
LocalDate now1 = LocalDate.now();
int year = now1.getYear();
int previousyear = now1.getYear()-1;
int yearfrom = from.getYear()+1900;
if((yearfrom == year )|| (yearfrom == previousyear )){
idoc.setBauinfoArzvon(from);
}
}
I have rewritten it a little bit, so we stop using a deprecated method. It looks like this:
for (Date from : infoFacade.getDateFrom(documentId))
{
cal.setTime(from);
int yearfrom = cal.get(Calendar.YEAR);
if ((yearfrom == LocalDate.now().getYear())
|| (yearfrom == (LocalDate.now().getYear() - 1)))
{
idoc.setDateFrom(from);
}
}
I am worried about all that +1900 or -1900 thing. Should I add or substract something from the yearfrom variable to get the same results as in the code before refactoring?
Assuming you cannot change the return type of infoFacade.getDateFrom() my suggestion would be:
ZoneId zone = ZoneId.systemDefault();
LocalDate now1 = LocalDate.now(zone);
int year = now1.getYear();
int previousYear = year - 1;
List<Date> dateList = infoFacade.getDateFrom(documentId);
for (Date from : dateList) {
int yearfrom = from.toInstant().atZone(zone).getYear();
if (yearfrom == year || yearfrom == previousYear) {
idoc.setBauinfoArzvon(from);
}
}
Both versions of your code implicitly rely on the JVM’s time zone (which is fragile). I have made this dependency explicit. I am reading the default time zone and the current date only once to ensure consistent results. And by converting the Date first to an Instant and then to ZonedDateTime I am avoiding both the deprecated method and the old and outdated Calendar class. And any considerations about whether to add or subtract 1900 or not, which gives clearer code and fewer doubts on the part of the reader.
To answer your question more directly too: No, in your rewritten version of the code you should neither add nor subtract 1900 (or any other number). The code does give the same result. This is because Date uses a “1900-based year” (where 2018 is given as 118, for example), while the also outdated Calendar class numbers the years the same way humans do. My worry is different: If either the default time zone changes while the code is running or (unlikely, but possible) New Year passes, LocalDate.now() will not give the same result each time, so your results will be inconsistent. The JVM’s default time zone can be changed at any time from another part of your program or another program running in the same JVM.
I have written a simple test:
public static void main(String[] args) {
Date date = new GregorianCalendar().getTime();
Calendar cal = new GregorianCalendar();
cal.setTime(date);
System.out.println(cal.get(Calendar.YEAR));
System.out.println((LocalDate.now().getYear() - 1));
System.out.println(LocalDate.now().getYear());
LocalDate now1 = LocalDate.now();
int year = now1.getYear();
int previousyear = now1.getYear()-1;
int yearfrom = date.getYear()+1900;
System.out.println(year);
System.out.println(previousyear);
System.out.println(yearfrom);
}
The output of this test is:
2018
2017
2018
2018
2017
2018
So both code samples are giving the same result.
BUT i will try to use the #Ole V.V. answer tomorrow to see what will happen.
This is my first question, so please be gentle with me! I am having a problem with some pre-existing java code.
It is pretty simple, you pass it two dates in the format "2013-10-31", it then calculates the ms difference between the two values and then does some more calculations after that. The problem is that every now and again, even though two different dates are passed, they both have the same millisecond value. An example of this is if you pass "2013-10-31" and "2013-11-01", it returns the difference as 0. The ms values both being "1385856000000".
Code is:
public int getTotalStartEndTime( java.sql.Date startdate, java.sql.Date enddate, java.sql.Time starttime, java.sql.Time endtime )
{
if(startdate != null & enddate != null && starttime !=null && endtime!= null){
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
int styr = Integer.parseInt(startdate.toString().substring(0,startdate.toString().indexOf("-")),10);
int stmm = Integer.parseInt(startdate.toString().substring(startdate.toString().indexOf("-")+1,startdate.toString().lastIndexOf("-")),10);
int stdd = Integer.parseInt(startdate.toString().substring(startdate.toString().lastIndexOf("-")+1),10);
int enyr = Integer.parseInt(enddate.toString().substring(0,enddate.toString().indexOf("-")),10);
int enmm = Integer.parseInt(enddate.toString().substring(enddate.toString().indexOf("-")+1,enddate.toString().lastIndexOf("-")),10);
int endd = Integer.parseInt(enddate.toString().substring(enddate.toString().lastIndexOf("-")+1),10);
//calendar1.set(styr, stmm, stdd);
calendar1.set(Calendar.YEAR, styr);
calendar1.set(Calendar.MONTH, stmm);
calendar1.set(Calendar.DAY_OF_MONTH, stdd);
calendar1.set(Calendar.HOUR, 0);
calendar1.set(Calendar.MINUTE, 0);
calendar1.set(Calendar.SECOND, 0);
calendar1.set(Calendar.MILLISECOND,0);
//calendar2.set(enyr, enmm, endd);
calendar2.set(Calendar.YEAR, enyr);
calendar2.set(Calendar.MONTH, enmm);
calendar2.set(Calendar.DAY_OF_MONTH, endd);
calendar2.set(Calendar.HOUR, 0);
calendar2.set(Calendar.MINUTE, 0);
calendar2.set(Calendar.SECOND, 0);
calendar2.set(Calendar.MILLISECOND,0);
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
Any help would be greatly appreciated, as I cannot work out what is happening!
calendar month is 0-11, in your code, you parsing date from string and month 10 is converted to november, which has not 31 days and set to first december.
As it has been said, MONTH is 0-11.
Your code didn't throw an exception since the default value of lenient is true.
You should set it to false (unless you explicitly want this behavior) to detect this kind of situation more easily :
calendar1.setLenient(false);
calendar2.setLenient(false);
It's not actually answering your question, but if all you need is the value of diff, there is no need to work with Calendar instances, but you can replace your code entirely with:
long diff = enddate.getTime() - startdate.getTime();
If you actually need the Calendar objects for other operations, there is still no need to parse the string representation of the dates, you can simply set the Calendar to the Date value with one operation:
Calendar calendar1 = Calendar.getInstance();
calendar1.setTimeInMillis(startdate.getTime());
I have this code here:
public static String AddRemoveDays(String date, int days) throws ParseException
{
SimpleDateFormat k = new SimpleDateFormat("yyyyMMdd");
Date d = k.parse(date);
d = new Date(d.getTime() + days*86400000);
String time = k.format(d);
return time;
}
It take String formed "yyyyMMdd", and adds int days to it. It should work then the days is negative - then he would substract the days from the date. When it does it's math, it returns String formated "yyyyMMdd".
At least that is what it should do. It works for small numbers, but if I try to add (or remove), for example, a year (365 or -365), it returns wierd dates.
What's the problem?
Should I do it a completley another way?
d = new Date(d.getTime() + days*86400000);
If you multiply 86400000 by 365 integer cant hold it. Change 86400000 to Long
d = new Date(d.getTime() + days*86400000L);
and it will be fine.
Hard to say what's going on without specific dates.
If you're committed to doing this with the raw Java classes, you might want to look at using Calendar -e.g.
Calendar calendar = Calendar.getInstance();
calendar.setTime(d);
calendar.add(Calendar.DATE, days); // this supports negative values for days;
d = calendar.getTime();
That said, I would recommend steering clear of the java Date classes, and look to use jodaTime or jsr310 instead.
e.g. in jsr310, you could use a DateTimeFormatter and LocalDate:
DateTimeFormatter format = DateTimeFormatters.pattern("yyyyMMdd");
LocalDate orig = format.parse(dateString, LocalDate.rule());
LocalDate inc = orig.plusDays(days); // again, days can be negative;
return format.print(inc);
I'm trying to do a simple date comparison between yesterday and today
if (yesterday.before(today)) {
...
}
The issue is that with the before method I will eval to true even if it's just a few seconds difference. How might I compare just the day (because I only want to eval this to true if it was the previous day (minutes/seconds should be ignored)
Thank you in advance
using DateUtils -
if (!DateUtils.isSameDay(yesterday, today) && (yesterday.before(today)) {
//...
}
EDIT: it can be done without DateUtils as well. See this thread.
If you don't want to use a 3rd party library implement a method like this:
public boolean before(Calendar yesterday, Calendar today) {
if(yesterday == today) return false;
if(yesterday == null || today == null) return false;
return yesterday.get(Calendar.YEAR) < today.get(Calendar.YEAR) ? true :
yesterday.get(Calendar.YEAR) == today.get(Calendar.YEAR) && yesterday.get(Calendar.DAY_OF_YEAR) < today.get(Calendar.DAY_OF_YEAR);
}
If you're up to adding a library that handles dates better than the standard Java libraries, you might want to look at Joda.
Using Joda, you can compute difference between days by:
Days d = Days.daysBetween(startDate, endDate);
int days = d.getDays();
where startDate and endDate are the Joda version of dates, DateTime (actually a superclass of that).
Converting Java Date objects to Joda DateTime objects can be done by a constructor call:
DateTime dateTime = new DateTime(javaDate);
Adding this library may be overkill for this specific problem, but if you deal with date and time manipulation a lot, the library is definitely worth it.
If you want to stick to Date you could temporarily lower your current date by one day. If before() still leads to the same result you have a timespan of at least one day.
final static long DAY_MILLIS = 86400000;
Date d1 = new Date(2011, 06, 18);
Date d2 = new Date(2011, 06, 16);
Date temp = new Date(d1.getTime() - DAY_MILLIS);
if (temp.before(d2))
// Do stuff
}
Please note I used a deprecated constructor but it should do the job.
I recently discovered a difference between Oracle adds months to a given date (using ADD_MONTHS function) and the way Java adds months to a Calendar object.
For instance in oracle:
select add_months('2009-02-28', +1) from dual;
produced the result: "09-03-31"
And the query:
select add_months('2009-02-28', -1) from dual;
Produces the result "09-01-31"
However in Java, the results of the same calculations (using GregorianCalendar.add() method) are (respectively):
09-03-28
and
09-01-28
Is there some way to make Oracle and Java behave the same? (e.g. some setting in oracle or some parameter in Java)?
When you do month arithmetic you need to decide, from the business point of view, what is the right way to deal with months with differing numbers of days. The flip side to the issue you raised is what happens when going from a longer month, like August, to a shorter one like February (and even from Feb to Feb if leap years are involved).
If you are happy for errors to be reported because the calculation cannot find 'Feb-30', then look at INTERVAL
You can create own DateService class like bellow and use "addMonthToDateLikeOracle" method.
package db;
import org.joda.time.LocalDate;
import java.util.Calendar;
import java.util.Date;
public class DateService {
public static Date addMonthToDateLikeOracle(Date date, int months) {
Calendar c = Calendar.getInstance();
c.setTime(date);
Date retval;
if (DateService.isLastDayOfMonth(date)) {
c.add(Calendar.MONTH, 1);
c.add(Calendar.MONTH, 1);
c.set(Calendar.DATE, 1);
c.add(Calendar.DATE, -1);
retval = c.getTime();
} else {
retval = LocalDate.fromDateFields(date).plusMonths(months).toDate();
}
return retval;
}
public static boolean isLastDayOfMonth(Date date) {
if (date == null) {
throw new RuntimeException("The date parameter cannot be null!");
}
Date endOfMonth = getEndOfMonth(date);
return endOfMonth.equals(date);
}
public static Date getEndOfMonth(Date date) {
Date startOfMonth = getStartOfMonth(date);
Date startOfNextMonth = LocalDate.fromDateFields(startOfMonth).plusMonths(1).toDate();
return LocalDate.fromDateFields(startOfNextMonth).plusDays(-1).toDate();
}
public static Date getStartOfMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DAY_OF_MONTH, 1);
return calendar.getTime();
}
}
From the Oracle reference on add_months (http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/functions004.htm)
If date is the last day of the month or if the resulting month has fewer days than the day component of date, then the result is the last day of the resulting month. Otherwise, the result has the same day component as date.
That means you're going to have to write a method for Java that performs the same check to get the same results (or a function in PL/SQL that behaves the same as Java).
You could write your own add months function in java.
public Date functionAddMonth(Date d, int month)
{
Calendar c = Calendar.getInstance();
c.setTime(d);
c.add(Calendar.DAY, 1);
c.add(Calendar.MONTH, month);
c.add(Calendar.DAY, -1);
return c.getTime();
}