Missing something obvious when it comes to comparing dates (Android Date) - java

I have put together a method that is supposed to check if a given date is within a certain lower and upper limit.
It shouldn't consider the time, only the dates. It seemed to be a quite simple task but I am getting some strange behavior when debugging it.
I have tried different approaches for removing the time value from the input dates. (inDate.) but they all seem to give me the same unexpected behavior of putting my inLeft date before inLeft and thus making the function result as false.
As you can see from the screenshot inLeft and inLeft are equal (if we ignore time) so why is int leftLimit = DateTimeComparator.getDateOnlyInstance().compare(inLeft, inDate); resulting in 1 rather that 0?
My conclusion is that I am doing something wrong but cannot find what. Please forgive me if this is something totally obvious.
Here is my Code:
protected boolean checkDateInRange(Date inDate, Date inLeft, Date inRight) {
System.out.println("inDate = " + inDate);
System.out.println("inLeft = " + inLeft);
System.out.println("inRight = " + inRight);
int leftLimit = DateTimeComparator.getDateOnlyInstance().compare(inLeft, inDate);
int rightLimit = DateTimeComparator.getDateOnlyInstance().compare(inDate, inRight);
System.out.println("leftLimit = " + leftLimit);
System.out.println("rightLimit = " + rightLimit);
if (leftLimit > 0 || rightLimit > 0) {
return false;
}
return true;
}
I/System.out: inDate = Mon Sep 26 00:00:00 GMT+02:00 2016
I/System.out: inLeft = Mon Sep 26 20:14:13 GMT+02:00 2016
I/System.out: inRight = Mon Sep 26 00:00:00 GMT+02:00 2016
I/System.out: leftLimit = 1
I/System.out: rightLimit = 0
The problem is that leftLimit == 1, instead of 0, inDate and inLeft without the time are the same. but leftLimit still results 1.
Edit (Final Solution):
According to sumandas' and Roberts solution i have written a new method that gives me the expected behaviour.
New code:
protected boolean checkDateInRange(Date inDate, Date inLeft, Date inRight) {
SimpleDateFormat simpleDateFormatter = new SimpleDateFormat("yyyy-MM-dd");
String dateString = simpleDateFormatter.format(inDate);
String leftString = simpleDateFormatter.format(inLeft);
String rightString = simpleDateFormatter.format(inRight);
if (leftString.compareTo(dateString) > 0 || dateString.compareTo(rightString) > 0)
return false;
return true;
}
I still don't understand why my initial solution should not work.

Try this:
String date1 = "2014/09/12"
String date2 = "2016/09/12"
SimpleDateFormat simpleDateFormatter = new SimpleDateFormat("yyyy-MM-dd");
Date inDate = simpleDateFormatter.parse(date1);
Date inLeft = simpleDateFormatter.parse(date2);
Date rightDate = simpleDateFormatter.parse(date2);
Pass of of these to the function as below and do the comparison:
protected boolean checkDateInRange(Date inDate, Date inLeft, Date inRight) {
if (inDate.before(inLeft) || inDate.after(inRight)) {
// Do something
}
}
My two cents, I tried using Joda Time earlier and due to too many if else I switched to simpledateformat, but joda time helps a lot in ISO date formats.
Why the proposed solution didn't work:
If you read the documentation it says LHS < RHS returns -ve
Else returns +ve
Now with your example, getDateOnlyInstance returns only date where
LHS = Sep 26 2016 = RHS and returns a 1. // Hope this helps.

Based on the comments, I'm assuming you're using joda-time API (I used version 2.7 for this test).
To explain why your first attempt doesn't work, I've made a test. First, I created the equivalent DateTime objects for your test inputs:
// equivalent date/times in GMT+02:00
DateTime in = new DateTime(2016, 9, 26, 0, 0, 0, 0, DateTimeZone.forOffsetHours(2));
DateTime left = new DateTime(2016, 9, 26, 20, 14, 13, 0, DateTimeZone.forOffsetHours(2));
DateTime right = new DateTime(2016, 9, 26, 0, 0, 0, 0, DateTimeZone.forOffsetHours(2));
Then I called your method:
// using toDate to convert org.joda.time.DateTime to java.util.Date
checkDateInRangeWrong(in.toDate(), left.toDate(), right.toDate());
And the output I've got:
inDate = Sun Sep 25 19:00:00 BRT 2016
inLeft = Mon Sep 26 15:14:13 BRT 2016
inRight = Sun Sep 25 19:00:00 BRT 2016
Note that inDate's day is 25 (instead of 26), and time is 19 (instead of 00). Also note that the timezone is BRT (instead of GMT+02:00).
This happens because when DateTimeComparator.compare() is called with java.util.Date instances, it uses the default timezone to convert the objects.
As my default timezone (java.util.TimeZone.getDefault()) is "America/Sao_Paulo" (or BRT - Brazil Standard Time), the date/time 26/09 at 00:00 GMT+02:00 is converted to 25/09 at 19:00 in BRT.
So the code is actually comparing leftDate (26/09) with inDate (25/09), and that's why leftLimit is 1.
Depending on how you're creating the variables inDate, leftDate and rightDate, there might be variations during the day (so the code might work during only some part of the day, for example). And there could also be differences during Daylight Saving Time (when hours move forward or back 1 hour), which can also cause a shift in the day.
And your new code (using SimpleDateFormat) also doesn't work for me (it has the same problem, as SimpleDateFormat also uses the default timezone) - and the same error occurs if I create the Date objects with java.util.Calendar instead of using DateTime.toDate().
So, to solve this, I've used org.joda.time.LocalDate class (a date without the time fields), because I just need to compare the dates (day/month/year) and ignore the time (hour/minute/second). I used the constructor that receives the timezone, so I don't depend on the system's default and I can be sure that I'm always working on the same timezone.
protected boolean checkDateInRange(Date inDate, Date inLeft, Date inRight) {
// convert inputs to LocalDate, using the specified timezone
LocalDate left = new LocalDate(inLeft, DateTimeZone.forOffsetHours(2));
LocalDate right = new LocalDate(inRight, DateTimeZone.forOffsetHours(2));
LocalDate date = new LocalDate(inDate, DateTimeZone.forOffsetHours(2));
System.out.println("inDate = " + date);
System.out.println("inLeft = " + left);
System.out.println("inRight = " + right);
int leftLimit = left.compareTo(date);
int rightLimit = date.compareTo(right);
System.out.println("leftLimit = " + leftLimit);
System.out.println("rightLimit = " + rightLimit);
if (leftLimit > 0 || rightLimit > 0) {
return false;
}
return true;
}
Now calling:
checkDateInRange(in.toDate(), left.toDate(), right.toDate());
produces the output:
inDate = 2016-10-26
inLeft = 2016-10-26
inRight = 2016-10-26
leftLimit = 0
rightLimit = 0
true
Notes:
As you're using joda-time, you can make a method that receives a DateTime object (or even better, a LocalDate), instead of using the old error-prone java.util.Date API. Changing to a LocalDate is better because it's making explicit that the method doesn't need the time fields:
protected boolean checkDateInRange(LocalDate inDate, LocalDate inLeft, LocalDate inRight) {
System.out.println("inDate = " + inDate);
System.out.println("inLeft = " + inLeft);
System.out.println("inRight = " + inRight);
int leftLimit = inLeft.compareTo(inDate);
int rightLimit = inDate.compareTo(inRight);
System.out.println("leftLimit = " + leftLimit);
System.out.println("rightLimit = " + rightLimit);
if (leftLimit > 0 || rightLimit > 0) {
return false;
}
return true;
}
// in, left and right are DateTime instances
checkDateInRange(in.toLocalDate(), left.toLocalDate(), right.toLocalDate());
I'm assuming that DateTimeZone.forOffsetHours(2) is the timezone for all your inputs. If it's not the case, I recommend to handle each case accordingly and extract the LocalDate (using the constructor LocalDate(dateObject, DateTimeZone) described above) before doing any comparison.

Related

Java Calendar how to validate date

I'm trying to validate a given date, but it's not working how I would like it. The user inputs a date, and it gets parsed and passed to an array, and I'm trying to validate the date is a correct date(taking into account leap years, Feb, etc) without making the code extremely lengthy.
Calendar calendar = new GregorianCalendar(getValidYear(), getValidMonth() - 1, getValidDay());
if( validYear < 2010 )
{
throw new InvalidDateException("Year must be greater than 2009");
} else {
if(validMonth < 1 || validMonth > 12 )
{
throw new InvalidDateException("Month value must be greater than or equal to 1 or less than or eqaul to 12");
} else {
if(validDay > calendar.getActualMaximum(Calendar.DAY_OF_MONTH) || validDay <= 0)
{
throw new InvalidDateException(String.format ("Day value must be greater than 0 and less than or equal to %s ",
calendar.getActualMaximum(Calendar.DAY_OF_MONTH) ) );
}
}//end nested if month
}//end nested IF year
}
If I put 2018/02/33 in and have it print for the exception it shows the date as March 05, 2018 and Im not exactly sure where these numbers are coming from. The code to parse the date is
String dateGiven[] = validDate.split("/");
validYear = Integer.parseInt(dateGiven[0]);
validMonth = Integer.parseInt( dateGiven[1] );
validDay = Integer.parseInt( dateGiven[2] );
And when I build the string to show the date it prints correctly, but it is not working with Calendar and Im not sure what Im doing wrong. Any help is appreciated!
It would be easier to use Java 8 time features:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate date = LocalDate.parse("2018/02/33", formatter);
will result in a DateTimeException when date is invalid:
java.time.DateTimeException: Invalid value for DayOfMonth (valid values 1 - 28/31): 33
Calendar is lenient by default. Quoting from the documentation of its method setLenient:
With lenient interpretation, a date such as "February 942, 1996" will
be treated as being equivalent to the 941st day after February 1,
1996. With strict (non-lenient) interpretation, such dates will cause an exception to be thrown. The default is lenient.
If you want to receive an exception if an invalid date is set on the Calendar then use setLenient(false);.
Otherwise 2018/02/33 is going to be interpreted as 32 days after February 1, which is March 5.

How to convert util.Date to time.LocalDate correctly for dates before 1893

I googled for a while and the most commonly used method seems to be
date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
However, this method seems to fail for dates before 1893-04-01
The following test fails on my machine with an outcome of 1893-03-31 instead of 1893-04-01:
#Test
public void testBeforeApril1893() throws ParseException {
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1893-04-01");
System.out.println(date);
LocalDate localDate2 = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
System.out.println(localDate2);
assertEquals(1893, localDate2.getYear());
assertEquals(4, localDate2.getMonth().getValue());
assertEquals(1, localDate2.getDayOfMonth());
}
The System.out.prinlns are for me to double check the created dates. I see the following output:
Sun Apr 02 00:00:00 CET 1893
1893-04-02
Sat Apr 01 00:00:00 CET 1893
1893-03-31
For 1400-04-01 I even get an output of 1400-04-09.
Is there any method to convert dates before 1893-04 correctly to LocalDate?
As some helpfully pointed out, the reason for this shift is explained in this question. However, I don't see how I can deduce a correct conversion based on this knowledge.
If you're just parsing a String input, it's straighforward:
LocalDate d1 = LocalDate.parse("1893-04-01");
System.out.println(d1); // 1893-04-01
LocalDate d2 = LocalDate.parse("1400-04-01");
System.out.println(d2); // 1400-04-01
The output is:
1893-04-01
1400-04-01
But if you have a java.util.Date object and need to convert it, it's a little bit more complicated.
A java.util.Date contains the number of milliseconds from unix epoch (1970-01-01T00:00Z). So you can say "it's in UTC", but when you print it, the value is "converted" to the system's default timezone (in your case, it's CET). And SimpleDateFormat also uses the default timezone internally (in obscure ways that I must admit I don't fully understand).
In your example, the millis value of -2422054800000 is equivalent to the UTC instant 1893-03-31T23:00:00Z. Checking this value in Europe/Berlin timezone:
System.out.println(Instant.ofEpochMilli(-2422054800000L).atZone(ZoneId.of("Europe/Berlin")));
The output is:
1893-03-31T23:53:28+00:53:28[Europe/Berlin]
Yes, it's very strange, but all places used strange offsets before 1900 - each city had its own local time, before UTC standard took place. That explains why you get 1893-03-31. The Date object prints April 1st probably because the old API (java.util.TimeZone) doesn't have all the offsets history, so it assumes it's +01:00.
One alternative to make this work is to always use UTC as the timezone:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC")); // set UTC to the format
Date date = sdf.parse("1893-04-01");
LocalDate d = date.toInstant().atZone(ZoneOffset.UTC).toLocalDate();
System.out.println(d); // 1893-04-01
This will get the correct local date: 1893-04-01.
But for dates before 1582-10-15, the code above doesn't work. That's the date when the Gregorian Calendar was introduced. Before it, the Julian Calendar was used, and dates before it need an adjustment.
I could do it with the ThreeTen Extra project (an extension of java.time classes, created by the same guy BTW). In the org.threeten.extra.chrono package there are the JulianChronology and JulianDate classes:
// using the same SimpleDateFormat as above (with UTC set)
date = sdf.parse("1400-04-01");
// get julian date from date
JulianDate julianDate = JulianChronology.INSTANCE.date(date.toInstant().atZone(ZoneOffset.UTC));
System.out.println(julianDate); // Julian AD 1400-04-01
The output will be:
Julian AD 1400-04-01
Now we need to convert the JulianDate to a LocalDate. If I do LocalDate.from(julianDate) it converts to Gregorian calendar (and the result is 1400-04-10).
But if you want to create a LocalDate with exactly 1400-04-01, you'll have to do this:
LocalDate converted = LocalDate.of(julianDate.get(ChronoField.YEAR_OF_ERA),
julianDate.get(ChronoField.MONTH_OF_YEAR),
julianDate.get(ChronoField.DAY_OF_MONTH));
System.out.println(converted); // 1400-04-01
The output will be:
1400-04-01
Just be aware that dates before 1582-10-15 have this adjustment and SimpleDateFormat can't handle these cases properly. If you need to work just with 1400-04-01 (year/month/day values), use a LocalDate. But if you need to convert it to a java.util.Date, be aware that it might not be the same date (due to Gregorian/Julian adjustments).
If you don't want to add another dependency, you can also do all the math by hand. I've adapted the code from ThreeTen, but IMO the ideal is to use the API itself (as it can cover corner cases and other things I'm probably missing by just copying a piece of code):
// auxiliary method
public LocalDate ofYearDay(int prolepticYear, int dayOfYear) {
boolean leap = (prolepticYear % 4) == 0;
if (dayOfYear == 366 && leap == false) {
throw new DateTimeException("Invalid date 'DayOfYear 366' as '" + prolepticYear + "' is not a leap year");
}
Month moy = Month.of((dayOfYear - 1) / 31 + 1);
int monthEnd = moy.firstDayOfYear(leap) + moy.length(leap) - 1;
if (dayOfYear > monthEnd) {
moy = moy.plus(1);
}
int dom = dayOfYear - moy.firstDayOfYear(leap) + 1;
return LocalDate.of(prolepticYear, moy.getValue(), dom);
}
// sdf with UTC set, as above
Date date = sdf.parse("1400-04-01");
ZonedDateTime z = date.toInstant().atZone(ZoneOffset.UTC);
LocalDate d;
// difference between the ISO and Julian epoch day count
long julianToIso = 719164;
int daysPerCicle = (365 * 4) + 1;
long julianEpochDay = z.toLocalDate().toEpochDay() + julianToIso;
long cycle = Math.floorDiv(julianEpochDay, daysPerCicle);
long daysInCycle = Math.floorMod(julianEpochDay, daysPerCicle);
if (daysInCycle == daysPerCicle - 1) {
int year = (int) ((cycle * 4 + 3) + 1);
d = ofYearDay(year, 366);
} else {
int year = (int) ((cycle * 4 + daysInCycle / 365) + 1);
int doy = (int) ((daysInCycle % 365) + 1);
d = ofYearDay(year, doy);
}
System.out.println(d); // 1400-04-01
The output will be:
1400-04-01
Just reminding that all this math is not needed for dates after 1582-10-15.
Anyway, if you have an input String and want to parse it, don't use SimpleDateFormat - you can use LocalDate.parse() instead. Or LocalDate.of(year, month, day) if you already know the values.
But converting these local dates from/to a java.util.Date is more complicated, because Date represents the full timestamp millis and dates can vary according to the calendar system in use.
Seems to be a known bug that won't get fixed: https://bugs.openjdk.java.net/browse/JDK-8061577
After a lot of research I gave up with every simple API method and just convert it by hand. You could wrap the date in a sql.Date and call toLocalDate() or you just use the same deprecated methods as sql.Date does.
Without deprecated methods you need to convert your util.Date to Calendar and get the fields one by one:
Calendar calendar = Calendar.getInstance();
calendar.setTime(value);
return LocalDate.of(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1,
calendar.get(Calendar.DAY_OF_MONTH));
If you futher want to have a two digit year conversion like in SimpleDateFormat (convert the date in range of now - 80 years till now + 19 years) you could use this implementation:
Calendar calendar = Calendar.getInstance();
calendar.setTime(value);
int year = calendar.get(Calendar.YEAR);
if (year <= 99) {
LocalDate pivotLocalDate = LocalDate.now().minusYears(80);
int pivotYearOfCentury = pivotLocalDate.getYear() % 100;
int pivotCentury = pivotLocalDate.minusYears(pivotYearOfCentury).getYear();
if (year < pivotYearOfCentury) {
year += 100;
}
year += pivotCentury;
}
return LocalDate.of(year, calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH));
Conclusion: it is realy ugly and I can't believe that there isn't any simple API!
This code works for me:
#Test
public void oldDate() throws ParseException {
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1893-04-01");
assertEquals("1893-04-01", String.format("%tF", date));
}

Java code to calculate number of mid nights (00:00:00) in a date range

I am trying to write a java block to find the number of mid-nights in a particular date range.
For example:
begin date: 05/01/2014 00:00:00
end date : 05/03/2014 00:00:00
this range has 3 mid-nights in it.
or
begin date : 05/01/2014 00:00:00
end date : 05/02/2014 23:59:59
this has only one.
It basically has to tell me how many times the time "00:00:00" occurrs in the date range.
Please help me out. I tried many approaches but none work correct.
I would just count the days (the actual dates), and add one if the earliest date has a time of 00:00:00.
begin date: 05/01/2014 00:00:00 end date : 05/03/2014 00:00:00
03 - 01 = 2 days.
Since the begin date has a time of 00:00:00, then add one:
2 + 1 = 3 midnights.
or
begin date : 05/01/2014 00:00:00 end date : 05/02/2014 23:59:59
02 - 01 = 1 day.
Since the begin date has a time of 00:00:00, then add one:
1 + 1 = 2 midnights.
Also,
begin date : 5/01/2014 23:59:59 end date : 5/02/2014 00:00:01
02 - 01 = 1 day.
Since the begin date doesn't have a time of 00:00:00, then don't add one:
1 midnight.
The answer using Joda-Time is not correct. As #khriskooper has noted the count of midnights between
2014-05-01 00:00:00 and 2014-05-02 23:59:59
is not one but two midnights!
So here the correction using Joda-Time (not tested), but it could also be any other library which supports day-range calculations (not true for old Java-pre8). I leave out the timezone detail because I do not consider it as really relevant for the question. If OP wants he can replace LocalDateTime by DateTime and apply a timezone.
LocalDateTime ldt1 = new LocalDateTime(2014, 5, 1, 0, 0, 0);
LocalDateTime ldt2 = new LocalDateTime(2014, 5, 2, 23, 59, 59);
int days = Days.daysBetween(ldt1.toLocalDate(), ldt2.toLocalDate()).getDays();
if (ldt1.toLocalTime().equals(new LocalTime(0, 0))) {
days++;
}
One option is to use Joda-Time library:
DateTimeZone zone = DateTimeZone.forID("America/New_York");
int days = Days.daysBetween(new DateTime(startDate, zone), new DateTime(endDate, zone)).getDays();
I think this is the easiest way. The drawback is that you need one more library..
Hope this can help!
Using Joda's DateTime library (one I would recommmend anyway), an elegant way to do so would be:
private int getNumberOfNights(DateTime start, DateTime end) {
int nightCount = 0;
DateTime tempEnd = new DateTime(end);
while (tempEnd.withTimeAtStartOfDay().isAfter(start)) {
nightCount++;
tempEnd = tempEnd.minusDays(1);
}
return nightCount;
}
... or if you want to avoid a while loop:
private int getNumberOfNights(DateTime start, DateTime end) {
int nightCount = Days.daysBetween(start, end).getDays();
DateTime leftOver = new DateTime(end.minusDays(nightCount));
if (leftOver.withTimeAtStartOfDay().isAfter(start)) {
nightCount++;
}
return nightCount;
}
With Java 7
public long countDays(Date dtStart, Date dtEnd) {
long startDay = TimeUnit.DAYS.convert(dtStart.getTime(), TimeUnit.MILLISECONDS)
long endDay = TimeUnit.DAYS.convert(dtEnd.getTime(), TimeUnit.MILLISECONDS)
return endDay - startDay
}

Dates comparison in Java

I'm trying to compare two dates with the current date. It seems not to work when I try to know if a date is the same as the current date. Here's what I do in my code :
//BeginDate is set earlier
Date myDate= new SimpleDateFormat("dd/MM/yyyy").parse(BeginDate);
Date now = new Date();
System.out.println("Now : " + now);
System.out.println("myDate : " + myDate);
System.out.println("equals : " + myDate.equals(now));
System.out.println(myDate.compareTo(now));
And I get this in the console :
Now : Thu Dec 29 00:28:45 CET 2011
myDate : Thu Dec 29 00:00:00 CET 2011
equals : false
-1
The first comparison should return true and the second "0" right ? Or am I missing something ?
Comparing dates with either equals() or compareTo() compares the times (hours, minutes, seconds, millis) as well as the dates. Your test is failing because myDate is midnight today, whereas now is a little later than that.
Your comparison is failing because you need to format now so that both dates have the same format and thus may be compared.
Or, if you prefer, you can convert dates into strings and perform the comparison:
String beginDate = "28/12/2011";
Calendar now = Calendar.getInstance();
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
String nowStr = df.format(new Date());
System.out.println("equals : " + beginDate.equals(nowStr));
Are you specifying the milliseconds when creating the dates? If you are, don't. So when creating the dates earlier, only specify the Day, Hour etc, not seconds/milliseconds.
And, change the SimpleDateFormat respectively. That "should" work.
Date object in Java is nothing but a number that represents milliseconds since January 1, 1970, 00:00:00 GMT. It doesn't have any attribute called day, date, month, year etc. That's because date, month, year varies based on the type of calendar and timezone. These attributes belong to Calendar instance.
So, if you have 2 Date objects and you want to compare day of month, month and year then you should create corresponding Calendar instance and compare them separately.
// Parse begin date
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date beginDate = dateFormat.parse(beginDateAsString);
// Create calendar instances
Calendar beginDateCalendar = Calendar.getInstance();
beginDateCalendar.setTime(beginDate);
Calendar todayCalendar = Calendar.getInstance();
// Check Equals
boolean dayEquals = todayCalendar.get(Calendar.DAY_OF_MONTH) == beginDateCalendar
.get(Calendar.DAY_OF_MONTH);
boolean monthEquals = todayCalendar.get(Calendar.MONTH) == beginDateCalendar
.get(Calendar.MONTH);
boolean yearEquals = todayCalendar.get(Calendar.YEAR) == beginDateCalendar
.get(Calendar.YEAR);
// Print Equals
System.out.println(dayEquals && monthEquals && yearEquals);
Above code is cumbersome for the current problem but explains how date operations must be done in JAVA.
If you just want to solve the equals problem you have mentioned then the code below will suffice:
String todayAsString = (new SimpleDateFormat("dd/MM/yyyy")).format(new Date());
System.out.println(beginDateAsString.equals(todayAsString));
If you are only going to be dealing with dates between the years 1900 and 2100, there is a simple calculation which will give you the number of days since 1900:
public static int daysSince1900(Date date) {
Calendar c = new GregorianCalendar();
c.setTime(date);
int year = c.get(Calendar.YEAR) - 1900;
int month = c.get(Calendar.MONTH) + 1;
int days = c.get(Calendar.DAY_OF_MONTH);
if (month < 3) {
month += 12;
year--;
}
int yearDays = (int) (year * 365.25);
int monthDays = (int) ((month + 1) * 30.61);
return (yearDays + monthDays + days - 63);
}
Thus, Date (only) comparison can be achieved by checking if the number of days since 1900 of the 2 dates are equal.
NOTE: The above method should have code added to check if the dates are outside the valid range (1/1/1900 - 31/12/2099) and throw an IllegalArgumentException.
And don't ask me where this calculation came from because we've used it since the early '90s.

Help with dates in Android

Looking for a bit of help with taking a dat from a DatePicker Widget and storing it in an sqlite database within the app. I have the following code:
java.util.Date utilDate = null;
String y = Integer.toString(date.getDayOfMonth()) + "/" + (date.getMonth()+1) + "/" + Integer.toString(date.getYear());
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyy");
utilDate = formatter.parse(y);
java.sql.Date z = new java.sql.Date(utilDate.getDate());
x = z.toString();
Log.v("The date: ", x);
}
Where date is the DatePicker widget. If I output the utilDate variable (i.e. the Java version of date) using logCat it seems to work fine and gives me a format like: Tue Jan 04 00:00:00 GMT 2011 which I am expecting but using the code above to get the sql version of the date, it always gives me the date 1970-01-01. I'm pretty sure the solution is very simple but I just can't see it.
This part: utilDate.getDate() is wrong.
Quote from Javadoc:
Returns the day of the month represented by this Date object. The value returned is between 1 and 31 representing the day of the month that contains or begins with the instant in time represented by this Date object, as interpreted in the local time zone.
So, you get a number between 1 and 31, and you expect a long that represents number of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.
Use
java.sql.Date z = new java.sql.Date(utilDate.getTime());
and everything should be OK.

Categories

Resources