Java/Android: Literally Compare date of 2 Calendar objects - java

I am trying to compare 2 calendar objects with their dates.
My code:
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.set(2017, 1,2);
c2.set(2017, 1,1);
int compared = c1.compareTo(c2);
textView.setText("" + compared);
The result should be an int of either -1 or 1, in which my case should be: -1.
However, this is not the result I want. I want to be able to compare dates directly say:
01/20/2010 compared to 02/30/2014 returns true or false.
Is there some ways to achieve this based on the Calendar lib?
I am aware of built in methods such as getDay(), getMonth(), equals() and so on. The problem is that in using getDay(), getMonth(), getYear(), it is very difficult to make a comparison as I'm comparing between 3 ints.
Also, I got a feeling that to compare between 2 dates, I will have to set the timezone and the timeinMillis to be the same. Meaning to compare the date direct, for cal1 and cal2, its time zone and timeinmillis has to be the same.
Can someone clarify this to me?

You should be careful there from a conceptual point of view: compareTo() has that very specific meaning of returning an int, with that - 1, 0,1 results telling you about how to order the compared objects.
That boolean result you are looking for indicates that you should think/speak using verbs like equals, before, or after!
It is a bad idea to take a well defined concept, keeping the name but changing the meaning under the covers!

tl;dr
LocalDate.of( 2010 , 1 , 20 )
.isBefore(
LocalDate.of( 2014 , 2 , 30 )
)
true
Details
You are using the wrong method on the wrong class.
The Calendar class represents a date and time-of-day. But you want a date-only value without a time-of-day.
You are calling the compareTo method which is defined by a specific interface Comparable with a specific purpose. This method is designed to return integers whereas you want a boolean result of "isBefore" or "isAfter".
Using java.time
Also, the troublesome Calendar class is one of the old date-time classes that are now legacy, supplanted by the java.time classes.
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate ld1 = LocalDate.of( 2010 , 1 , 20 ) ;
LocalDate ld2 = LocalDate.of( 2014 , 2 , 30 ) ;
Compare with boolean methods.
boolean ld1IsBefore = ld1.isBefore( ld2 );
boolean ld1IsAfter = ld1.isAfter( ld2 );
boolean ld1IsEqual = ld1.isEqual( ld2 );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….

you could use either Calendar#before or Calendar#after to make a comparison which returns a boolean.
SimpleDateFormat formatC1 = new SimpleDateFormat("yyyy-MM-dd");
String formattedC1 = formatC1.format(c1.getTime());
SimpleDateFormat formatC2 = new SimpleDateFormat("yyyy-MM-dd");
String formattedC2 = formatC2.format(c2.getTime());
textView.setText(formattedC1 + " compared to " + formattedC2 + " returns " + c1.before(c2));

you can do it this way
textView.setText("c1 compared to c2 returns " + (c1.compareTo(c2) == 0));
As per the javadocs
Compares the time values (millisecond offsets from the Epoch) represented by two Calendar objects.
Test
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c2.add(Calendar.MINUTE, 1);
System.out.println ("c1 compared to c2 returns " + (c1.compareTo(c2) == 0));

Related

Convert SQL date to Java.util.date

My requirement is to return the dueDate field as a date to the calling service.
The back end code returns the date in mm/dd/yy. When I map those fields to the Java code, my object contains the date field of type java.sql.Date.
The field that is defined in the object is (note it's the pseudo):
import java.sql.Date;
private Date dueDate;
/**
* #return the dueDate
*/
public Date getDueDate() {
return dueDate;
}
/**
* #param DueDate the DueDate to set
*/
public void setDueDate(Date dueDate) {
this.dueDate = dueDate;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("DueDetails [dueAmount=").append(dueAmount).append(", dueDate=").append(dueDate)
.append("]");
return builder.toString();
}
When I print the object, the Date field comes in this form:
dueDate=Thu Oct 25 20:00:00 EDT 2018
dueDate=Thu Aug 02 20:00:00 EDT 2018
When I query from backend, it shows me the proper format (mm/dd/yy), which I should return to the calling service.
check this
//converting java.util.Date to java.sql.Date in Java
java.sql.Date sqlDate = new java.sql.Date(now.getTime());
System.out.println("Converted value of java.sql.Date : " + sqlDate);
//converting java.sql.Date to java.util.Date back
java.util.Date utilDate = new java.util.Date(sqlDate.getTime());
System.out.println("Converted value of java.util.Date : " + utilDate);
from this link: http://www.java67.com/2012/12/how-to-convert-sql-date-to-util-date.html
Then you can use SimpleDateFormat to format the date as you like:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String strdate = simpleDateFormat.format(myJavaDate);
System.out.println(strdate);
java.util.Date vs java.sql.Date
Your output looks to be coming from a java.util.Date rather than a java.sql.Date.
It is unfortunately easy to mixup the two. Besides the Date name, the sql one technically is a subclass of the other util one. Beware: This is a hack, and a bad hack at that. The documentation warns us to pretend the two are not in an inheritance relationship. But the compiler does not know that.
Here is some example code showing these two classes and the different behavior of their respective toString method.
// Legacy classes
System.out.println( "java.sql.Date: " + new java.sql.Date( Instant.now().toEpochMilli() ) ) ;
System.out.println( "java.util.Date: " + new java.util.Date() ) ;
See this code run live at IdeOne.com.
java.sql.Date: 2018-07-31
java.util.Date: Tue Jul 31 22:44:14 GMT 2018
You can see the java.sql.Date::toString method uses the shorter YYYY-MM-DD format used in SQL environments. That format also happens to comply with ISO 8601 standard as well, by the way.
In contrast, the output you report matches that of java.util.Date::toString.
java.time
The issue is moot. You are using terrible old date-time classes that were supplanted years ago by the java.time classes.
java.sql.Date is replaced by java.time.LocalDate, a date-only only value without a time-of-day and without a time zone. (FYI, java.sql.Date pretends to have no time-of-day or time zone but actually has both, as an awkward subclass of java.util.Date.)
java.util.Date is replaced by java.time.Instant. Both represent a moment in UTC, though Instant has a finer resolution of nanoseconds instead of milliseconds. (FYI, java.util.Date actually has a time zone buried deep, inaccessible without getter/setter methods, but used in equals etc. One of many poor design decisions in these legacy classes.)
Here is some code, counterparts to that seen above.
// Modern classes
System.out.println( "LocalDate.now(): " + LocalDate.now() ;
System.out.println( "Instant.now(): " + Instant.now() ) ;
System.out.println( "ZonedDateTime.now( … ): " + ZonedDateTime.now( ZoneId.of( "Africa/Tunis" ) ) ) ;
See this code run live at IdeOne.com.
LocalDate.now(): 2018-07-31
Instant.now(): 2018-07-31T22:57:27.763Z
ZonedDateTime.now( … ): 2018-07-31T23:57:27.904+01:00[Africa/Tunis]
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Is there a better way to zero out Calendar date?

I'm looking to see if there is a better way in obtaining the same result as the following code:
Calendar date = Calendar.getInstance();
date.setTimeInMillis(System.currentTimeMillis());
date.set(Calendar.HOUR_OF_DAY, 0);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
I'm using this to be able to compare the difference in days between two dates. I am currently coding for target API 24 and am not interested in using Joda Time for such a simple task.
I've come up with the following function, but would love to hear if there is a simpler, perhaps built in, method for either zeroing out the date or an entire different method for getting the amount of days between two dates.
private long getFlatDateInMillis() {
Calendar currentDate = Calendar.getInstance();
currentDate.setTimeInMillis(System.currentTimeMillis());
currentDate.set(Calendar.HOUR_OF_DAY, 0);
currentDate.set(Calendar.MINUTE, 0);
currentDate.set(Calendar.SECOND, 0);
currentDate.set(Calendar.MILLISECOND, 0);
return currentDate.getTimeInMillis();
}
That way, I could quickly use:
Calendar date = getFlatDateInMillis();
I just want to make sure I'm not missing anything that is simpler, already pre-defined.
Thank you!
The correct way to do this is with the java.time.LocalDate class. It stores only the date, not the time, and it has a now() static method, which returns the current day.
LocalDate today = LocalDate.now();
If you're looking at Android, this was added at API level 26, but there are other ways of using the "new style" date classes with Android, such as the ThreeTen-Backport library.
tl;dr
ChronoUnit.DAYS.between( // Calculate elapsed time between a pair of `LocalDate` date-only objects. Returns a total number of elapsed days.
( (GregorianCalendar) myJavaUtilCal ) // Cast your legacy `java.util.Calendar` object to the subclass `java.util.GregorianCalendar`, also legacy.
.toZonedDateTime() // Convert from legacy `GregorianCalendar` to modern `ZonedDateTime` class.
.toLocalDate() , // Extract the date-only value, a `LocalDate`, lacking time-of-day and lacking time zone.
otherLocalDate // Compare to some other `LocalDate` object.
) // Returns a `long` number of days. Uses Half-Open approach where the beginning is *inclusive* while the ending is *exclusive*.
Details
The Answer by Kareem is correct. Some more thoughts here.
Is there a better way to zero out Calendar date?
Yes, there is a better way: don’t.
Trying to clear out the time-of-day on a date+time types is the wrong approach; use a date-only type instead (LocalDate).
And don’t use the troublesome old legacy classes such as Calendar, Date, SimpleDateFormat as they are now supplanted by the java.time classes.
the difference in days between two dates
First convert your legacy Calendar object to the modern ZonedDateTime class. To convert, call new methods added to the old classes.
GregorianCalendar myGregCal = (GregorianCalendar) myJavaUtilCal ; // Cast from superclass to subclass.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // Convert from legacy class to modern class.
Extract the date-only value.
LocalDate ld = zdt.toLocalDate() ; // Extract date-only object from date-time object.
Calculate elapsed time in days
long days = ChronoUnit.DAYS.between( ld , otherLd ) ;
Or represent the elapsed time as a Period.
Period p = Period.between( ld , otherLd ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
EDIT: Thanks to Basil and Kareem, I've updated to the following code (so, so much easier):
Added to gradle.build:
compile 'com.jakewharton.threetenabp:threetenabp:1.0.5'
Then, in my activity, etc,
AndroidThreeTen.init(this);
LocalDate today = LocalDate.now();
LocalDate anotherDay = LocalDate.of(2019, 3, 25);
long dayDifference = ChronoUnit.DAYS.between(today, anotherDay); //dayDifference = 365
One thing of note is that Calendar references months starting at 0 index, whereas LocalDate references months starting at 1 index.

Java, set date to 0/0/0

I have an object with some dates and I'd like to return them in the getter. The problem is that i need to do Date.toString(); because I have to print them, and when the date is null I get a NullPointerException.
I was thinking about returning the date 0/0/0 when the date is null, but I don't know how to set this value. Is there any way? Just like new Date(0) returns the 1970-01-01-00:00:00, is there anything similar to this but to return 0/0/0?
Thanks!
There is no Date 0/0/0, by definition, as there is no Day 0 and no Month 0. A day is a member of the set {1,..,28 or 30 or 31} and month is a member of the set {1,...12}. Hence, it is impossible - and it is good that it is impossible - to express 0/0/0 as Date Object.
The terrible Date and Calendar classes were supplanted years ago by the java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety. Ditto for Year & YearMonth.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Zero-date senseless
is there anything similar to this but to return 0/0/0?
No.
Trying to represent a null with a date of all zeros is the wrong way to go. There is no such thing as a date of all zeros (year, month, and day all being zero).
Instead, pick an arbitrary date to use as a special value. Document thoroughly your choice and its meaning.
Do not choose a date too distant in time. Many libraries and databases are limited in their range of values. You do not want your data to break there.
Generally I would suggest using the epoch of 1970-01-01T00:00:00Z, the first moment of 1970 in UTC (the Z means UTC, and is pronounced “Zulu”). This moment is used as the epoch reference for Unix, the legacy date-time classes bundled with Java, and the modern date-time classes built into Java 8 and later. So many programmers and sysadmins will recognize this moment as special. The java.time classes include a constant for your convenience: Instant.EPOCH.
Obviously my suggestion applies to common business-oriented apps interested in forward-looking near dates, with past history not reaching back to 1970. If that does not meet your needs, pick another arbitrary value, such as 1900-01-01.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Java uses the Gregorian Calendar which has no 0 year. Also, you have to keep in mind that there is now zero month either. Setting a month to '0' would result in getting January, as the months are based on 0-index. Zero day does not exist either.
Assuming that you are getting and returning "modern" dates (AD), you could set your "lower bound" date in BC era. So, when you get a null date you could return a BC date to differentiate it from your actual ones. Here's the code:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.ERA, GregorianCalendar.BC); //Set the BC era
cal.set(Calendar.YEAR, 1); //Set the year to 1 BC
cal.set(Calendar.MONTH, 0); //Set the month to January
cal.set(Calendar.DAY_OF_MONTH, 1); //Set the day to 1st
DateFormat df = new SimpleDateFormat("yyyy MMM d G"); //Format the date
String returnedDate = df.format(cal.getTime()); //Generate a String of it for other use
You could customize the code to your needs if you are also getting dates from BC era (maybe by setting an even older date).
EDIT: Of course you could use what the others have suggested, namely checking for null and returning a "0/0/0" String but this may cause further problems later on, when you will try to parse the aforementioned String. Also, due to the fact that by definition 0/0/0 is not a valid date in the Gregorian Calendar (see clarification), you should avoid using this "wildcard" String and set an actual date, as I detailed above.
CLARIFICATION: The Gregorian Calendar does not contain neither a 0 year nor a 0 month or 0 day by definition and not by implementation in Java (meaning it's not an intentional limitation, it's part of its concept).
Class: LocalDate
Package: Threetenabp
My solution was to create LocalDate constants using the EPOCH date as basis with LocalDate.ofEpochDay(). And instead of returning a null date (that does not exist) I return a LocalDate object according to the case evaluated. Then depending on what I get back the getBirthdate method in my domain I do something.
Definition of constants
public class LocalDateUtils {
public static final LocalDate EMPTY_FIELDS = createLocalDate(0);
public static final LocalDate EMPTY_FIELD_DAY_OF_MONTH = createLocalDate(1);
public static final LocalDate EMPTY_FIELD_MONTH = createLocalDate(2);
public static final LocalDate EMPTY_FIELD_YEAR = createLocalDate(3);
/**
* Purpose: Create a date with #param epochDay days added
* Observation: EPOCH (1970-01-01)
*/
private static LocalDate createLocalDate(long epochDay) {
return LocalDate.ofEpochDay(epochDay);
}
}
Implementation
/**
* Purpose: Describe a birthday or a constant indicating empty field (s).
* Observation: According to if the parameters are zeros.
*/
LocalDate getBirthdate(int year,
int month,
int dayOfMonth) {
if (dayOfMonth == 0 && month == 0 && year == 0)
return LocalDateUtils.EMPTY_FIELDS;
if (dayOfMonth == 0)
return LocalDateUtils.EMPTY_FIELD_DAY_OF_MONTH;
if (month == 0)
return LocalDateUtils.EMPTY_FIELD_MONTH;
if (year == 0)
return LocalDateUtils.EMPTY_FIELD_YEAR;
return LocalDate.of(year, month, dayOfMonth);
}
Usage
if (getBirthdate() == LocalDateUtils.EMPTY_FIELDS) {
}
if (getBirthdate() == LocalDateUtils.EMPTY_FIELD_DAY_OF_MONTH) {
}
if (getBirthdate() == LocalDateUtils.EMPTY_FIELD_MONTH) {
}
if (getBirthdate() == LocalDateUtils.EMPTY_FIELD_YEAR) {
}
Source
GL
This simple approach can get you what you need, as already mentioned in the comments to your question:
public String dateString(Date date) {
if (date != null)
return date.toString();
else
return "0/0/0";
}
or
String dateString;
try {
dateString = date.toString();
}
catch(NullPointerException e) {
dateString = "0/0/0";
}
Update: the second alternative is discouraged as suggested in the comments.

Incorrect date when converting unix epoch to human readable using Java

EDIT: Removed the '*1000' and still getting incorrect date but updated the log below to show what I am now getting.
Below is my code snippet and my log and I thought I implemented it correctly so I don't know why it isn't giving me the correct conversion:
NewFoodItem foodItem = data.get(position);
String date = new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(new java.util.Date (foodItem.date));
String a = Integer.toString(foodItem.date);
Log.d("returnedDate:", a);
Log.d("formattedDate:", date);
It won't let me post an image but the log looks like this:
D/returnedDate: 1409012824
D/formattedDate: 01/17/1970 02:23:32
D/returnedDate: 1409013004
D/formattedDate: 01/17/1970 02:23:33
The Answer by Andrew T. is correct: integer overflow. But the example code is now outmoded.
java.time
The modern approach uses the java.time classes.
The Instant class represents a moment. Like java.util.Date, Instant counts from the epoch reference of first moment of 1970 in UTC, 1970-01-01T00:00Z. But Instant uses a finer resolution of nanoseconds rather than milliseconds.
Append an L to the end of your numeric literal to indicate long type. Use underscores wherever you like to group your digits, with no meaning added (ignored by compiler).
long input = 1_409_012_824L ;
Instant instant = Instant.ofEpochSecond( input ) ;
Generate a textual representation of the value in standard ISO 8601 format.
String output = instant.toString() ;
2014-08-26T00:27:04Z
For more flexibility in generating text, convert to a OffsetDateTime.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
Automatically localize the output using a DateTimeFormatter.
Locale locale = Locale.US ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( locale ) ;
String output2 = odt.format( f ) ;
Aug 26, 2014, 12:27:04 AM
See this code run live at IdeOne.com.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I just tested with some assumption, and it seems that the problem is related to integer overflow.
I assume you defined NewFoodItem.date as int, instead of long. Hence, when you multiply the date * 1000 (both are int), it returns int.
int d = 1409012824; // foodItem.date
int d1000 = d * 1000; // returns 263550912 because of overflow, instead of 1409012824000
String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
.format(new Date(d1000)); // returns 01/04/1970 08:42:30
When I try changing one of them to long, it behaves as expected
// case 1
long d = 1409012824;
long d1000 = d * 1000; // now returns 1409012824000 correctly
String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
.format(new Date(d1000)); // returns 08/26/2014 08:27:04
// case 2
int d = 1409012824;
long d1000 = d * 1000L; // note the "L" suffix to indicate the number as long
long d1000f = d * 1000; // FAIL, still returns 263550912 because of integer overflow
String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
.format(new Date(d1000)); // returns 08/26/2014 08:27:04
String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
.format(new Date(d1000f)); // returns 01/04/1970 08:42:30
Generally when working with Date in Java, we define them as long since normally they are in millisecond. For easier maintenance, changing the type of NewFoodItem.date as long is the preferred one; much better if it's in millisecond also.

How to set an expiration date in java

I am trying to write some code to correctly set an expiration date given a certain date.
For instance this is what i have.
Date lastSignupDate = m.getLastSignupDate();
long expirationDate = 0;
long milliseconds_in_half_year = 15778463000L;
expirationDate = lastSignupDate.getTime() + milliseconds_in_half_year;
Date newDate = new Date(expirationDate);
However, say if i the sign up date is on 5/7/2011 the expiration date output i get is on 11/6/2011 which is not exactly half of a year from the given date. Is there an easier way to do this?
I would use the Calendar class - the add method will do this kind of thing perfectly.
http://download.oracle.com/javase/6/docs/api/java/util/Calendar.html
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.MONTH, 6);
java.util.Date expirationDate = cal.getTime();
System.err.println(expirationDate);
Here's a simple suggestion using joda-time:
DateTime dt = new DateTime(lastSignupDate);
dt = dt.plusDays(DateTimeConstants.MILLIS_PER_DAY * 365 / 2);
// you can also use dt.plusDays(364 / 2);
You can also use a Calendar:
Calendar c = Calendar.getInstance();
c.setTime(lastSignupDate);
c.add(Calendar.MILLISECOND, MILLIS_PER_DAY * 365 / 2);
// or c.add(Calendar.DAY_OF_YEAR, 364 / 2);
tl;dr
java.time.LocalDate.of( 2011 , Month.MAY , 7 )
.plusMonths( 6 )
.toString()
2011-11-07
java.time
You are using date-time values, so you must account for issues such as time zones, anomalies, and leap year. But you only want a date without a time-of-day and without a time zone, so much easier if you use a date-only class rather than a date-with-time class.
The modern approach uses java.time rather than the troublesome legacy date-time classes.
if i the sign up date is on 5/7/2011 the expiration date output i get is on 11/6/2011 which is not exactly half of a year from the given date
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate ld = LocalDate.of( 2011 , Month.MAY , 7 ) ;
You can do math with the java.time classes. Look for plus… and minus… methods.
LocalDate sixMonthsLater = ld.plusMonths( 6 ) ;
Or pass the amount of time.
Period p = Period.ofMonths( 6 ) ;
LocalDate sixMonthsLater = ld.plus( p ) ;
See this code run live at IdeOne.com.
2011-05-07
2011-11-07
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Do you really need an expiration-date, which is accurate to the millisecond?
I would implement it as 6 Months from x.
Jan. 1 => Jul 1
Sep. 28=> Feb 28
Sep. 29=> Feb 28
Sep. 30=> Feb 28
Oct. 1=> Mar 1
Maybe you like to be generous, and say 'Mar 1' for 'Sep 29 and 30' too.
Here's an example of using Date with TimeUnit that's a little more readable:
long year = TimeUnit.MILLISECONDS.convert(365, TimeUnit.DAYS);
Date expiry = new Date(System.currentTimeMillis() + year);
System.out.println(expiry);
Shame it doesn't have year and day, look at GregorianCalendar or Jodatime for a better API.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(new Date().getTime());
// 10 minutes expiration time
calendar.add(calendar.MINUTE, 10);
// prints 10 minutes ahead time
System.out.println(new Date(calendar.getTime().getTime()));

Categories