Date output issue - java

import java.text.DateFormat;
import java.util.Date;
public class DatePlus {
public static void main(String[] args) {
Date now = new Date();
//Date now1 = new Date();
Date now2 = new Date();
DateFormat currentDate = DateFormat.getDateInstance();
int count1=10;
int count2=15;
Date addedDate1 = addDays(now2, count1);
Date addedDate2 = addDays(addedDate1, count2);
System.out.println(currentDate.format(addedDate1));
System.out.println(currentDate.format(addedDate2));
}
public static Date addDays(Date d, int days) {
d.setTime(d.getTime() + days * 1000 * 60 * 60 * 24);
return d;
}
}
both the date addedDate1 and addedDate2 output statements are printing the same date though the expected output is different.

The problem is that you don't return a new Date instance but change the provided one. You always modify and print the same instance.
Change your function to
public static Date addDays(Date d, int days) {
return new Date(d.getTime() + days * 1000 * 60 * 60 * 24);
}

Instead of writing your own method you can use Calender class:
public static void main(String[] args)
{
Date now = new Date();
// Date now2 = new Date();
DateFormat currentDate = DateFormat.getDateInstance();
int count1=10;
int count2=15;
Calendar c=Calendar.getInstance();
c.setTime(now);
c.add(Calendar.DATE, count1);
Date addedDate1 = c.getTime();
c.setTime(addedDate1);
c.add(Calendar.DATE, count2);
Date addedDate2 = c.getTime();
System.out.println(currentDate.format(addedDate1));
System.out.println(currentDate.format(addedDate2));
}

As mentioned already in several answers/comments, doing these calculations manually is risky and error-prone.
Here is a basic example of what you need, using Joda Time library, a very stable and well-design alternative to JDK Date, Calendar. etc...
public static void main(String[] args) {
DateTime now = new DateTime();
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
int count1=10;
int count2=15;
DateTime addedDate1 = now.plusDays(count1);
DateTime addedDate2 = addedDate1.plusDays(count2);
System.out.println(fmt.print(addedDate1));
System.out.println(fmt.print(addedDate2));
}
Also, keep in mind that beside better design and clear documentation, Joda Time also is mostly thread-safe, as it always return immutable objects.
Finally, it's developed to be interoperable with JDK dates and calendars.

As mentionned by dystroy, you are not creating a new instance and this is the problem.
By the way, you could use an external library like Apache Commons Language to do this kind of logic, this is already well tested and you avoid such kind of problems. Commons Language has already an addDays method.
Even better, you could use Joda-Time which also has this kind of methods.

Related

getting Out of Range Compile Time Error in the Date Constructor

I am getting a date value as 1598331600000 from a API call
I am trying to convert this to Readable format using SimpleDateFormat
But i am getting Out of Range Compile Time Error in the Date Constructor
This is my Program
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Calendar cal = Calendar.getInstance();
Date date = new java.sql.Date(1598331600000);
SimpleDateFormat sdf = new java.text.SimpleDateFormat("MMddyyyy");
String formattedDate = sdf.format(date);
System.out.println(formattedDate);
}
}
Could you please let me know how to resolve this error .
1598331600000 without a suffix is treated as an int, and this value is too big for it (int can hold values up to around 2 billion, 2^31 - 1). Use L suffix for long type, which can hold values up to 2^63 - 1: 1598331600000L.
I would recommend to use java-8 date time api, and stop using legacy Calendar, SimpleDateFormat
Instant.ofEpochMilli(1598331600000l)
.atZone(ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("MMddyyyy")) //08252020
Your value here is treated as integer.
Date date = new java.sql.Date(1598331600000);
The constructor can take Long values. Like this :
long millis=System.currentTimeMillis();
Date date = new java.sql.Date(millis);
Hence it is throwing the error.
Try out this code :
import java.util.*;
import java.text.SimpleDateFormat;
public class Main{
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
/*long millis=System.currentTimeMillis(); <---- This also works
Date date = new java.sql.Date(millis);*/
Date date = new java.sql.Date(1598331600000L); // <---Look the L for Long here
SimpleDateFormat sdf = new java.text.SimpleDateFormat("MMddyyyy");
String formattedDate = sdf.format(date);
System.out.println(formattedDate);
}
}
Output :
08252020

Combine two type dates into one

I have two type dates that I get from my database :
Date : 2017-01-28 || Time : 12:59
And I want to combine it into a one Date variable.
this is the origin of the two variables :
#Temporal(value = TemporalType.DATE)
#Future
#DateTimeFormat(pattern = "dd/MM/YY")
#Column(name = "dateDebut", nullable = true)
private Date date;
#Temporal(TemporalType.TIME)
#Column(name="Start_Hour")
private Date startHour;
any help will be appreciated.Thank you.
Use a Calendar object:
private static Date combine(Date date, Date time) {
Calendar cal = Calendar.getInstance();
cal.setTime(time);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int min = cal.get(Calendar.MINUTE);
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, min);
return cal.getTime();
}
Test
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("2017-01-28");
Date startHour = new SimpleDateFormat("HH:mm").parse("12:59");
System.out.println(combine(date, startHour));
Output
Sat Jan 28 12:59:00 EST 2017
Now you need to do some conversions of your date and hour, you may as well convert them to one of the Java 8 date and time classes — provided you can use Java 8, of course. These classes are much nicer to work with downstream than the old-fashioned Date class. It’s even more straightforward than the other answers. For example:
LocalDate d = date.toInstant().atZone(ZoneOffset.systemDefault()).toLocalDate();
LocalTime t = startHour.toInstant().atZone(ZoneOffset.systemDefault()).toLocalTime();
LocalDateTime dt = d.atTime(t);
System.out.println(dt);
This prints:
2017-01-28T12:29
Depending on you requirements, it may be that you’ll prefer to stay with a ZonedDateTime or some other Java 8 type. These classes are quite versatile, so chances are that you can get what you want with few lines of code.
Edit: Some JPA implementations may support the Java 8 date and time classes directly, so you may spare the first two lines and only need the third. See JPA support for Java 8 new date and time API.
I got the idea you wanted to parse a date from that String (as I'm not sure what do you mean by that origin format).
So maybe this will help:
private static final String STRING_TO_FORMAT = "Date : 2017-01-28 || Time : 12:59";
public static void main(String[] args) {
Matcher matcher = Pattern.compile(".*(\\d{4}-\\d{2}-\\d{2}).*(\\d{2}:\\d{2})").matcher(STRING_TO_FORMAT);
matcher.find();
Date date = null;
try {
date = new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(matcher.group(1) + " " + matcher.group(2));
System.out.println(date);
} catch (ParseException e) {
}
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yy HH:mm");
System.out.println(formatter.format(date));
}

Java: how to use Date / Calendar

I'm making a small project for my university which is supposed to enroll students into different courses. I do have one issue though, each course has start/end enrollment day. How can I now use Date/Calendar to avoid having to make my own method. I will need two though, one is setDates(), used to set start and end dates for enrollment, and second is isOpen(), which will return error if a student tries to enroll too early or too late. (Assuming the moment of applying is the moment the program is run, so basically "now")
The JDK's Date and Calendar classes are notoriously lacking in both functionality and ease of use.
I'd suggest using the Joda Date library from http://joda-time.sourceforge.net/ to make things easier, but as far as I know, there is no existing library that exactly meets your needs - I think that you are still going to have to write something yourself.
It sounds like you care about dates, but not times, so beware of the JDK Date class, which incorporates date and time. This can cause all sorts of unexpected behavior when comparing Dates if you are not aware of this. Joda can help - it has, for instance, a LocalDate class which represents a 'day' - a date without a time.
isOpen() can be this simple:
public boolean isOpen() {
Date now = new Date();
return !now.before(startDate) && !now.after(endDate);
}
setDates() can just be a simple setter (though you should protect the invariant that end date cannot be before start date)
private Date startDate, endDate;
public void setDates(Date startDate, Date endDate) {
Date startCopy = new Date(startDate);
Date endCopy = new Date(endDate);
if ( startCopy.after(endCopy) ) {
throw new IllegalArgumentException("start must not be after end");
}
this.startDate = startCopy;
this.endDate = endCopy;
}
This type of logic is very common though and the third-party Joda-Time library does a very good job of encapsulating it for you (e.g. through the Interval class and its containsNow() method).
I'd personally extend the class and then make my own
setStartDate(date startDate)
setEndDate(date endDate)
isOpen()
Use #mark peters' isopen and just make the set assign the variables...
setDates -
public void setDates(Date start, Date end) {
this.start = start;
this.end = end;
}
isOpen -
public boolean isOpen() {
Date now = new Date();
if(now.before(this.start) || now.after(this.end)) {
return false;
}
return true;
}
I assume you will use some kind of date picker that returns the date as a String.
setDates will require this:
Two String parameters; start date and end date.
Parsing of the parameters (SimpleDateFormat).
Knowledge of the date format that is returned by the picker (I'll assume DD MON YYYY, for example: "12 Oct 2011")
Two Date objects to store the date: start date and end date.
Use of a Calendar to clear the unwanted parts of the Date (hour, minute, second, and milliseconds).
Adjust the end date to 11:59p.
isOpen is easier.
Verify that startDate and endDate are not null.
Get the current date (new Date()).
Check if it is outside the range.
Here is some code:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
/**
* #author David W. Burhans
*
*/
public final class Registration
{
private static final DateFormat dateFormat = new SimpleDateFormat("dd MMM yyyy");
private static Date endDate;
private static Date startDate;
private static boolean isOpen()
{
Date now = new Date();
boolean returnValue;
if (now.before(startDate) || now.after(endDate))
{
returnValue = false;
}
else
{
returnValue = true;
}
return returnValue;
}
/**
* #param args
*/
public static void main(String[] args)
{
setDates("21 Jan 2012", "28 Jan 2012");
System.out.print("Start Date: ");
System.out.println(startDate);
System.out.print("End Date: ");
System.out.println(endDate);
System.out.print("Is today in range: ");
System.out.println(isOpen());
}
private static void setDates(final String startDateString, final String endDateString)
{
// All or nothing.
if (StringUtils.isNotBlank(startDateString) && StringUtils.isNotBlank(endDateString))
{
Calendar calendar = Calendar.getInstance();
Date workingDate;
try
{
workingDate = dateFormat.parse(endDateString);
calendar.setTime(workingDate);
calendar.set(Calendar.HOUR, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
endDate = calendar.getTime();
}
catch (ParseException exception)
{
//System.out.println("endDate parse Exception");
// log that endDate is invalid. throw exception.
}
try
{
workingDate = dateFormat.parse(startDateString);
calendar.setTime(workingDate);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
startDate = calendar.getTime();
}
catch (ParseException exception)
{
//System.out.println("startDate parse Exception");
// log that startDate is invalid. throw exception.
}
}
else
{
// throw exception indicating which is bad.
}
}
}

Converting local time to UTC time or vice versa considering daylight saving time

I know how to convert local time to UTC time and vice versa.
But I am very much confused about daylight savings time(DST) handling while doing this.
So can anyone answer the below questions:
1. Does java internally handle DST when converting between timezones?
2. What things I need to do while converting between timezones?
3. Any good article which explains about this more clearly?
Thanks in advance.
Are you sure you know how to convert dates to UTC and back? Correctly?
I am afraid, I doubt that.
Yes.
You don't need to convert, you just need to assign correct TimeZone.
What you need an article for? OK, I am working on this, but for now let me put an answer here.
The first thing first. Your program should store Date (or Calendar) in UTC TimeZone internally. Well, in fact in GMT, because there are no leap seconds in Java, but that is another story.
The only place when you should be in need of "converting", is when you are going to display the time to user. That regards to sending email messages as well. In both cases you need to format date to get its textual representation. To that you would use DateFormat and assign correct TimeZone:
// that's for desktop application
// for web application one needs to detect Locale
Locale locale = Locale.getDefault();
// again, this one works for desktop application
// for web application it is more complicated
TimeZone currentTimeZone = TimeZone.getDefault();
// in fact I could skip this line and get just DateTime instance,
// but I wanted to show how to do that correctly for
// any time zone and locale
DateFormat formatter = DateFormat.getDateTimeInstance(
DateFormat.DEFAULT,
DateFormat.DEFAULT,
locale);
formatter.setTimeZone(currentTimeZone);
// Dates "conversion"
Date currentDate = new Date();
long sixMonths = 180L * 24 * 3600 * 1000;
Date inSixMonths = new Date(currentDate.getTime() + sixMonths);
System.out.println(formatter.format(currentDate));
System.out.println(formatter.format(inSixMonths));
// for me it prints
// 2011-05-14 16:11:29
// 2011-11-10 15:11:29
// now for "UTC"
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(formatter.format(currentDate));
System.out.println(formatter.format(inSixMonths));
// 2011-05-14 14:13:50
// 2011-11-10 14:13:50
As you can see, Java cares about handling DST. You can of course handle it manually, just read the TimeZone related JavaDoc.
Here is the best solution that I've found. I'm copying it here, but the solution came from http://biese.wordpress.com/2014/02/28/the-easy-way-to-convert-local-time-to-utc-time/.
package com.test.timezone;
import java.util.TimeZone;
public final class Utility {
public static final TimeZone utcTZ = TimeZone.getTimeZone("UTC");
public static long toLocalTime(long time, TimeZone to) {
return convertTime(time, utcTZ, to);
}
public static long toUTC(long time, TimeZone from) {
return convertTime(time, from, utcTZ);
}
public static long convertTime(long time, TimeZone from, TimeZone to) {
return time + getTimeZoneOffset(time, from, to);
}
private static long getTimeZoneOffset(long time, TimeZone from, TimeZone to) {
int fromOffset = from.getOffset(time);
int toOffset = to.getOffset(time);
int diff = 0;
if (fromOffset >= 0){
if (toOffset > 0){
toOffset = -1*toOffset;
} else {
toOffset = Math.abs(toOffset);
}
diff = (fromOffset+toOffset)*-1;
} else {
if (toOffset <= 0){
toOffset = -1*Math.abs(toOffset);
}
diff = (Math.abs(fromOffset)+toOffset);
}
return diff;
}
}
package com.test.timezone;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class TestTimezone {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM dd HH:mm:ss zzzz");
Calendar date1 = new GregorianCalendar(2014,0,15,10,0,0);
System.out.println(sdf.format(date1.getTime())+"\n");
long utcTimeStamp = Utility.toUTC(date1.getTimeInMillis(), date1.getTimeZone());
Calendar utcCal = Calendar.getInstance();
utcCal.setTimeInMillis(utcTimeStamp);
System.out.println("toUTC: "+sdf.format(utcCal.getTime())+"\n");
System.out.println("---------------------------------------");
Calendar date2 = new GregorianCalendar(2014,2,15,10,0,0);
System.out.println(sdf.format(date2.getTime())+"\n");
utcTimeStamp = Utility.toUTC(date2.getTimeInMillis(), date2.getTimeZone());
utcCal.setTimeInMillis(utcTimeStamp);
System.out.println("toUTC: "+sdf.format(utcCal.getTime())+"\n");
System.out.println("---------------------------------------");
Calendar date3 = new GregorianCalendar(2014,11,25,9,0,0);
System.out.println(sdf.format(date3.getTime())+"\n");
long uTime = Utility.toUTC(date3.getTimeInMillis(), date3.getTimeZone());
System.out.println("utcTimeStamp: "+uTime+"\n");
long lTime = Utility.toLocalTime(uTime, TimeZone.getTimeZone("EST"));
Calendar locCal = Calendar.getInstance();
locCal.setTimeInMillis(lTime);
System.out.println("toLocal: "+sdf.format(locCal.getTime())+"\n");
System.out.println("---------------------------------------");
Calendar date4 = new GregorianCalendar(2014,6,4,9,0,0);
System.out.println(sdf.format(date4.getTime())+"\n");
uTime = Utility.toUTC(date4.getTimeInMillis(), date4.getTimeZone());
System.out.println("utcTimeStamp: "+uTime+"\n");
lTime = Utility.toLocalTime(uTime, TimeZone.getTimeZone("EST"));
locCal = Calendar.getInstance();
locCal.setTimeInMillis(lTime);
System.out.println("toLocal: "+sdf.format(locCal.getTime())+"\n");
}
}
The code in TALE's answer can be simplified:
public final class Utility {
public static long toLocalTime(long time, TimeZone to) {
return time + to.getOffset(time);
}
public static long toUTC(long time, TimeZone from) {
return time - from.getOffset(time);
}
}

Compare Date objects with different levels of precision

I have a JUnit test that fails because the milliseconds are different. In this case I don't care about the milliseconds. How can I change the precision of the assert to ignore milliseconds (or any precision I would like it set to)?
Example of a failing assert that I would like to pass:
Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
assertEquals(dateOne, dateTwo);
There are libraries that help with this:
Apache commons-lang
If you have Apache commons-lang on your classpath, you can use DateUtils.truncate to truncate the dates to some field.
assertEquals(DateUtils.truncate(date1,Calendar.SECOND),
DateUtils.truncate(date2,Calendar.SECOND));
There is a shorthand for this:
assertTrue(DateUtils.truncatedEquals(date1,date2,Calendar.SECOND));
Note that 12:00:00.001 and 11:59:00.999 would truncate to different values, so this might not be ideal. For that, there is round:
assertEquals(DateUtils.round(date1,Calendar.SECOND),
DateUtils.round(date2,Calendar.SECOND));
AssertJ
Starting with version 3.7.0, AssertJ added an isCloseTo assertions, if you are using the Java 8 Date / Time API.
LocalTime _07_10 = LocalTime.of(7, 10);
LocalTime _07_42 = LocalTime.of(7, 42);
assertThat(_07_10).isCloseTo(_07_42, within(1, ChronoUnit.HOURS));
assertThat(_07_10).isCloseTo(_07_42, within(32, ChronoUnit.MINUTES));
It also works with legacy java Dates as well:
Date d1 = new Date();
Date d2 = new Date();
assertThat(d1).isCloseTo(d2, within(100, ChronoUnit.MILLIS).getValue());
Yet another workaround, I'd do it like this:
assertTrue("Dates aren't close enough to each other!", (date2.getTime() - date1.getTime()) < 1000);
Use a DateFormat object with a format that shows only the parts you want to match and do an assertEquals() on the resulting Strings. You can also easily wrap that in your own assertDatesAlmostEqual() method.
With AssertJ you could provide a custom comparator what is especially handy if you are comparing entire object structures and not single values so that other methods like isEqualToIgnoringMillis or isCloseTo are not practical.
assertThat(thing)
.usingRecursiveComparison()
.withComparatorForType(
(a, b) -> a.truncatedTo(ChronoUnit.MILLIS).compareTo(b.truncatedTo(ChronoUnit.MILLIS)),
OffsetDateTime.class
)
You could do something like this:
assertTrue((date1.getTime()/1000) == (date2.getTime()/1000));
No String comparisons needed.
You can chose which precision level you want when comparing dates, e.g.:
LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS);
// e.g. in MySQL db "timestamp" is without fractional seconds precision (just up to seconds precision)
assertEquals(myTimestamp, now);
In JUnit you can program two assert methods, like this:
public class MyTest {
#Test
public void test() {
...
assertEqualDates(expectedDateObject, resultDate);
// somewhat more confortable:
assertEqualDates("01/01/2012", anotherResultDate);
}
private static final String DATE_PATTERN = "dd/MM/yyyy";
private static void assertEqualDates(String expected, Date value) {
DateFormat formatter = new SimpleDateFormat(DATE_PATTERN);
String strValue = formatter.format(value);
assertEquals(expected, strValue);
}
private static void assertEqualDates(Date expected, Date value) {
DateFormat formatter = new SimpleDateFormat(DATE_PATTERN);
String strExpected = formatter.format(expected);
String strValue = formatter.format(value);
assertEquals(strExpected, strValue);
}
}
I don't know if there is support in JUnit, but one way to do it:
import java.text.SimpleDateFormat;
import java.util.Date;
public class Example {
private static SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss");
private static boolean assertEqualDates(Date date1, Date date2) {
String d1 = formatter.format(date1);
String d2 = formatter.format(date2);
return d1.equals(d2);
}
public static void main(String[] args) {
Date date1 = new Date();
Date date2 = new Date();
if (assertEqualDates(date1,date2)) { System.out.println("true!"); }
}
}
This is actually a harder problem than it appears because of the boundary cases where the variance that you don't care about crosses a threshold for a value you are checking. e.g. the millisecond difference is less than a second but the two timestamps cross the second threshold, or the minute threshold, or the hour threshold. This makes any DateFormat approach inherently error-prone.
Instead, I would suggest comparing the actual millisecond timestamps and provide a variance delta indicating what you consider an acceptable difference between the two date objects. An overly verbose example follows:
public static void assertDateSimilar(Date expected, Date actual, long allowableVariance)
{
long variance = Math.abs(allowableVariance);
long millis = expected.getTime();
long lowerBound = millis - allowableVariance;
long upperBound = millis + allowableVariance;
DateFormat df = DateFormat.getDateTimeInstance();
boolean within = lowerBound <= actual.getTime() && actual.getTime() <= upperBound;
assertTrue(MessageFormat.format("Expected {0} with variance of {1} but received {2}", df.format(expected), allowableVariance, df.format(actual)), within);
}
Using JUnit 4 you could also implement a matcher for testing dates according to your chosen precision. In this example the matcher takes a string format expression as a parameter. The code is not any shorter for this example. However the matcher class may be reused; and if you give it a describing name you can document the intention with the test in an elegant way.
import static org.junit.Assert.assertThat;
// further imports from org.junit. and org.hamcrest.
#Test
public void testAddEventsToBaby() {
Date referenceDate = new Date();
// Do something..
Date testDate = new Date();
//assertThat(referenceDate, equalTo(testDate)); // Test on equal could fail; it is a race condition
assertThat(referenceDate, sameCalendarDay(testDate, "yyyy MM dd"));
}
public static Matcher<Date> sameCalendarDay(final Object testValue, final String dateFormat){
final SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
return new BaseMatcher<Date>() {
protected Object theTestValue = testValue;
public boolean matches(Object theExpected) {
return formatter.format(theExpected).equals(formatter.format(theTestValue));
}
public void describeTo(Description description) {
description.appendText(theTestValue.toString());
}
};
}
use AssertJ assertions for Joda-Time (http://joel-costigliola.github.io/assertj/assertj-joda-time.html)
import static org.assertj.jodatime.api.Assertions.assertThat;
import org.joda.time.DateTime;
assertThat(new DateTime(dateOne.getTime())).isEqualToIgnoringMillis(new DateTime(dateTwo.getTime()));
the test failing message is more readable
java.lang.AssertionError:
Expecting:
<2014-07-28T08:00:00.000+08:00>
to have same year, month, day, hour, minute and second as:
<2014-07-28T08:10:00.000+08:00>
but had not.
If you were using Joda you could use Fest Joda Time.
Just compare the date parts you're interested in comparing:
Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
assertEquals(dateOne.getMonth(), dateTwo.getMonth());
assertEquals(dateOne.getDate(), dateTwo.getDate());
assertEquals(dateOne.getYear(), dateTwo.getYear());
// alternative to testing with deprecated methods in Date class
Calendar calOne = Calendar.getInstance();
Calendar calTwo = Calendar.getInstance();
calOne.setTime(dateOne);
calTwo.setTime(dateTwo);
assertEquals(calOne.get(Calendar.MONTH), calTwo.get(Calendar.MONTH));
assertEquals(calOne.get(Calendar.DATE), calTwo.get(Calendar.DATE));
assertEquals(calOne.get(Calendar.YEAR), calTwo.get(Calendar.YEAR));
JUnit has a built in assertion for comparing doubles, and specifying how close they need to be. In this case, the delta is within how many milliseconds you consider dates equivalent. This solution has no boundary conditions, measures absolute variance, can easily specify precision, and requires no additional libraries or code to be written.
Date dateOne = new Date();
dateOne.setTime(61202516585000L);
Date dateTwo = new Date();
dateTwo.setTime(61202516585123L);
// this line passes correctly
Assert.assertEquals(dateOne.getTime(), dateTwo.getTime(), 500.0);
// this line fails correctly
Assert.assertEquals(dateOne.getTime(), dateTwo.getTime(), 100.0);
Note It must be 100.0 instead of 100 (or a cast to double is needed) to force it to compare them as doubles.
You can use isEqualToIgnoringSeconds method to ignore seconds and compare only by minutes:
Date d1 = new Date();
Thread.sleep(10000);
Date d2 = new Date();
assertThat(d1).isEqualToIgnoringSeconds(d2); // true
Something like this might work:
assertEquals(new SimpleDateFormat("dd MMM yyyy").format(dateOne),
new SimpleDateFormat("dd MMM yyyy").format(dateTwo));
Instead of using new Date directly, you can create a small collaborator, which you can mock out in your test:
public class DateBuilder {
public java.util.Date now() {
return new java.util.Date();
}
}
Create a DateBuilder member and change calls from new Date to dateBuilder.now()
import java.util.Date;
public class Demo {
DateBuilder dateBuilder = new DateBuilder();
public void run() throws InterruptedException {
Date dateOne = dateBuilder.now();
Thread.sleep(10);
Date dateTwo = dateBuilder.now();
System.out.println("Dates are the same: " + dateOne.equals(dateTwo));
}
public static void main(String[] args) throws InterruptedException {
new Demo().run();
}
}
The main method will produce:
Dates are the same: false
In the test you can inject a stub of DateBuilder and let it return any value you like. For example with Mockito or an anonymous class which overrides now():
public class DemoTest {
#org.junit.Test
public void testMockito() throws Exception {
DateBuilder stub = org.mockito.Mockito.mock(DateBuilder.class);
org.mockito.Mockito.when(stub.now()).thenReturn(new java.util.Date(42));
Demo demo = new Demo();
demo.dateBuilder = stub;
demo.run();
}
#org.junit.Test
public void testAnonymousClass() throws Exception {
Demo demo = new Demo();
demo.dateBuilder = new DateBuilder() {
#Override
public Date now() {
return new Date(42);
}
};
demo.run();
}
}
Convert the dates to String using SimpleDateFromat, specify in the constructor the required date/time fields and compare the string values:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String expectedDate = formatter.format(dateOne));
String dateToTest = formatter.format(dateTwo);
assertEquals(expectedDate, dateToTest);
I did a small class that might be useful for some googlers that end up here : https://stackoverflow.com/a/37168645/5930242
Here is a utility function that did the job for me.
private boolean isEqual(Date d1, Date d2){
return d1.toLocalDate().equals(d2.toLocalDate());
}
i cast the objects to java.util.Date and compare
assertEquals((Date)timestamp1,(Date)timestamp2);

Categories