I have a Origin-Destination matrix representing the elapsed time between 2 point in minute. I wonder what is the best way to add the elapsed time to a Date.
Date clock;
SimpleDateFormat reqDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
clock = reqDF.parse(line[25]);
Double distance = distDB.find_distance(O, D, mode, facility_id);
Date current_time = clock + distance;
Does it makes more easier if I use a Calendar type instead of Date ?
Thanks
tl;dr
Instant.parse( "2016-12-23T01:23:45Z" )
.plusNanos( Math.round(
yourNumberOfMinutesAsDouble *
TimeUnit.MINUTES.toNanos( 1 ) )
)
Avoid old date-time classes.
Actually, you should using neither java.util.Date nor java.util.Calendar. These old legacy classes are notoriously troublesome, confusing, and flawed. Now supplanted by the java.time classes.
For the old classes, the Answer by Jireugi is correct. For java.time classes, read on.
Avoid using a fractional number for elapsed time
Not a good idea using a double or Double to represent elapsed time. Firstly, that type uses floating-point technology which trades away accuracy for speed of execution. So you will often have extraneous extra digits to the right of your decimal fraction.
Secondly, this is an awkward way to handle time, given that we have sixty seconds to a minute, and sixty minutes to an hour, and so on.
In Java, use the Period or Duration classes. See Oracle Tutorial.
In text, use the standard ISO 8601 format PnYnMnDTnHnMnS where P marks the beginning and T separates the years-months-days from the hours-minutes-seconds. So two and a half minutes would be PT2M30S.
Nanoseconds
If we must work with the Double as a number of minutes for elapsed time, let’s convert from your fractional decimal number to a whole number (integer).
Note that the old legacy date-time classes are limited to a resolution of milliseconds while the java.time classes can go as fine as nanoseconds. So we want to convert your Double to a whole number of nanoseconds.
Rather than hard-code a magic number of the number of nanoseconds in a minute for this calculation, let's use the TimeUnit enum. That class can calculate the number of nanoseconds in a minute for us ( 60 * 1_000_000_000L ).
Finally, the Math.round function returns the closest long to the argument, with ties rounding to positive infinity.
long nanoseconds = Math.round(
yourNumberOfMinutesAsDouble *
TimeUnit.MINUTES.toNanos( 1 )
);
Instant
If working with date-time values in UTC, use the Instant class. Each Instant represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant Instant.parse( "2016-12-23T01:23:45Z" )
Instant future = Instant.plusNanos( nanoseconds );
Duration
Rather than passing around a Double as your elapsed time, I strongly suggest you pass around Duration objects.
Duration duration = Duration.ofNanos( Math.round( yourNumberOfMinutesAsDouble * TimeUnit.MINUTES.toNanos( 1 ) ) );
You can do math with a Duration such as plus and minus.
Instant instant = Instant.parse( "2016-12-23T01:23:45Z" )
Instant future = instant.plus( duration );
You can generate a String representation of the Duration in standard ISO 8601 format such as PT8H6M12.345S by merely calling toString. And Duration can parse such strings as well.
String output = duration.toString(); // PT8H6M12.345S
…or going the other direction…
Duration duration = Duration.parse( "PT8H6M12.345S" );
You could try this using Math.round:
Date clock;
SimpleDateFormat reqDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
clock = reqDF.parse(line[25]);
Double distance = distDB.find_distance(O, D, mode, facility_id);
long clockTimeMs = clock.getTime();
long distTimeInMs = Math.round(distance * 60000);
Date current_time = new Date(clockTimeMs + distTimeInMs);
Here the Date gets converted into a milliseconds timestamp.
Since the distance is in minutes, you need to convert it also into milliseconds by multiplying it by 60 * 1000 (= 60000) before you can add it to the start time ("clock"). Finally a new Date gets created that represents the distance from the start time.
Please find details of the Date class here: https://docs.oracle.com/javase/6/docs/api/java/util/Date.html
If i understood your situation, you want to get current date, then using matrix [i, j] value (which is time - in minutes) you want to update the time to give an indication of - if you start from Origin (i), till what time you would reach to Destination (j).
I would rather use java's Calendar class. it gives you more flexibility. using 'Calendar' class, you can getTime(), which returns 'Date' type instance and then use this class to add/delete your time offset (there are methods provided by this class for such manipulations) and convert the 'Date' back to Calendar.
Related
We received time as hour =11, minutes=29,seconds=54,milliseonds=999 along with timezone information.
How to convert this time to unix epoch milliseconds with no date part.
I have tried this code :
ZoneId zoneId = ZoneId.of("America/New_York");
LocalDate now = LocalDate.now(zoneId);
long epochMilli = ZonedDateTime.of(LocalDate.now(zoneId).atTime(11, 29, 20, 999 * 1000 * 1000), zoneId).toInstant().toEpochMilli();
long unixEpocSeconds = epochMilli % (24 * 60 * 60 * 1000); //86400000
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(zoneId));
calendar.setTimeInMillis(unixEpocSeconds);
System.out.println("( = " + (calendar.get(Calendar.HOUR)==11));
System.out.println("( = " + (calendar.get(Calendar.MINUTE)==29));
System.out.println("( = " + (calendar.get(Calendar.SECOND)==20));
System.out.println("( = " + (calendar.get(Calendar.MILLISECOND)==999));
How to get the unix epoch seconds without the date component i.e.how to get the milliseconds in UTC zone /rather than as give zoneid. Above code runs find if zoneId=UTC
tl;dr
Duration.ofHours( 11L )
.plusMinutes( 29L )
.plusSeconds( 54L )
.plusMillis( 999L )
.toMillis()
41394999
Span-of-time versus Time-of-day
Your Question is confused. A time-of-day without a date makes no sense in comparison to UTC. A count of milliseconds since the Unix epoch reference date of 1970-01-01T00:00:00Z is for tracking the date and the time-of-day.
I suspect you are actually dealing with a span of time, and mishandling that as a time-of-day. One is meant for the timeline, the other is not.
Duration
The java.time classes bundled with Java 8 and later include Duration for handling such spans of time unattached to the timeline.
These methods take long data type, hence the trailing L.
Duration d = Duration.ofHours( 11L ).plusMinutes( 29L ).plusSeconds( 54L ).plusMillis( 999L ) ;
Count of milliseconds
You asked for a count of milliseconds, so here you go. Beware of data loss, as a Duration carries a finer resolution of nanoseconds, so you would be lopping off any finer fraction of a second when converting to milliseconds.
long millis = d.toMillis() ; // Converts this duration to the total length in milliseconds.
41394999
But I suggest you not represent spans of time nor moments on the timeline using a count-of-milliseconds. Better to use objects or standardized text; read on.
ISO 8601
The ISO 8601 standard defines practical unambiguous formats for representing date-time values as text.
This includes representation of durations. The format is PnYnMnDTnHnMnS where the P marks the beginning while the T separates any years-months-days portion from any hours-minutes-seconds portion.
The java.time classes use the standard formats by default in their parse and toString methods.
String output = d.toString() ;
PT11H29M54.999S
See this code run live at IdeOne.com.
You can directly parse such strings in java.time.
Duration d = Duration.parse( "PT11H29M54.999S" ) ;
I suggest using this format whenever possible, certainly when exchanging data between systems.
While working inside Java, pass Duration objects around rather than mere text.
Timeline
You can perform date-time math with the Duration objects. For example, take the current moment in your particular time zone, and add the eleven and a half hours.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;
ZonedDateTime later = now.plus( d ) ;
now.toString(): 2017-09-27T07:23:31.651+13:00[Pacific/Auckland]
later.toString(): 2017-09-27T18:53:26.650+13:00[Pacific/Auckland]
For UTC values, call toInstant. The Instant class represents a moment on the timeline in UTC with resolution of nanoseconds (finer than milliseconds).
Instant instant = later.toInstant() ;
How to get maximum time value of the current date in miliseconds in Java ?
E.g. 18th July 23.59 in epoch miliseconds where current time would be anything of 18th July
Half-Open
Seems like your Question involves determining the last moment of the day. Such a goal is ill-advised.
The last moment of the day is infinitely divisible as a fraction of a second, such as 2017-01-23T23:59:59.999Z. But different software uses different granularities when resolving such date-time values. The old legacy date-time classes is Java use milliseconds, or 3 decimal places. The new java.time classes use nanoseconds, or 9 decimal places. Other software such as the Postgres database use microseconds, for 6 decimal places. Other software uses other resolutions such as 5 decimal places. So you will be getting different values in different scenarios for the same date.
A better approach to defining spans of time is commonly used in date-time work, and avoids this ambiguity of last-moment-of-the-day: Half-Open. In this approach the beginning is inclusive while the ending is exclusive. So a single full day starts at the first moment of one date and runs up to, but does not include, the first moment of the following day. For UTC, that would be 2017-01-23T00:00:00Z to 2017-01-24T00:00:00Z.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
ZonedDateTime todayStart = today.atStartOfDay( z ) ;
long secondsSinceEpoch = todayStart.toEpochSecond() ; // Whole seconds since epoch of 1970-01-01T00:00:00Z.
long millisecondsSinceEpoch = todayStart.toInstant().toEpochMilli() ; // Milliseconds since epoch of 1970-01-01T00:00:00Z.
See this code run live at IdeOne.com.
todayStart: 2017-07-19T00:00-04:00[America/Montreal]
millisecondsSinceEpoch: 1500436800000
For the following day (tomorrow), add one day to the LocalDate.
LocalDate tomorrow = today.plusDays( 1 ) ;
ZonedDateTime tomorrowStart = tomorrow.atStartOfDay( z ) ;
There’s room for a bit of interpretation in your question. I suggest:
ZoneId zone = ZoneId.systemDefault();
long endOfDay = LocalDate.now(zone)
.plusDays(1)
.atStartOfDay(zone)
.toInstant()
.minusMillis(1)
.toEpochMilli();
System.out.println(endOfDay);
On my computer it just printed
1500501599999
This corresponds to a ZonedDateTime of 2017-07-19T23:59:59.999+02:00[Europe/Berlin].
Please note that the end of the day is time zone dependent, so you need to decide a time zone for the operation. Please fill in your desired time zone instead of ZoneId.systemDefault().
Since Java doesn’t include an “end of the day” operation I opted for adding one day, taking the beginning of the day in the time zone in question and then subtracting 1 millisecond (because you asked for milliseconds since the epoch). If you want, you may instead subtract a nanosecond, a second or a minute, for example. If you want to subtract a whole minute, the simplest is to use .minusMinutes(1) before toInstant().
The code should be safe even on a day and in a time zone where a summer time transition (DST changeover) happens at midnight.
I'm not entirely sure how the specific date plays into this, but if you want to find the last millisecond of the day, I would use LocalTime.MAX.toNanoOfDay()/1000000. This takes the maximum nanosecond of the day, then divides by 1000000 to convert to milliseconds. If you wanted to combine this with a date, I would combine this value with a LocalDate or LocalDateTime value.
I have a timestamp that is similar to POSIX Time with the sole exception that it is not reckoned in UTC.
Instead, it is the number of milliseconds that have elapsed since midnight, Jan 1 1970 in a particular local time zone. In order to make this value into an Instant, I must first know its offset (in milliseconds) to UTC/GMT.
So the problem is this: knowing the local time zone id, eg. "America/Chicago" and a count of milliseconds since the local Epoch, how do I make an Instant (which must be constructed with milliseconds since the POSIX Epoch)?
It does not seem that any of the java.time API constructors accept a millisecond parameter in a local Epoch.
I have a solution in which I first convert the local millisecond date-time into the local Gregorian calendar date-time (from which I can then construct a LocalDateTime and get the offset to UTC), but this seems like a lot of churning for what seems like it ought to be pretty simple.
Calculate the instant of your modified epoch:
ZoneId tz = ZoneId.of("America/Chicago");
Instant modifiedEpoch = ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, tz).toInstant();
Then add your millis:
Instant instant = modifiedEpoch.plusMillis(millis);
Wrong Way To Track Date-Time
First I have to say this use of count-from-epoch integers for date-time values in various time zones rather than in UTC is a really, really bad idea. I’ve seen some bad ways to handle date-time including inventing one or two bad ways myself. But this one is the worst. Whoever thought this up should be sentenced to a year of daily readings of StackOverflow answers marked "java", "date", and "Jon Skeet".
Using count-from-epoch to handle date-time in your app code is like using bit arrays to handle text. We have classes/interfaces such as CharSequence, String, StringBuilder, Printer, Reader and so on to handle the nitty-gritty complicated details of text, characters, character encoding, collations, and such for us to make writing apps easier. Imagine trying to debug, troubleshoot, and log textual data as bit arrays. Crazy, right? Trying to debug, troubleshoot, and log date-time data as long integers is crazy too.
Ditto for date-time, where we had Joda-Time and now have its successor java.time (Tutorial) built into Java 8 and later.
Secondly, implicitly adjusting a count-from-epoch into a time zone and then losing that fact makes a bad practice even worse.
Fix
The way to fix this is to get that count-from-epoch in some arbitrary time zone translated into a local date and local time where local means the wall-clock time as seen by people in than time zone.
With that local date-time in hand, we create a date-time object that has the assigned time zone, a ZonedDateTime. A ZonedDateTime is basically an Instant (a point on the timeline in UTC) plus a ZoneId (a time zone).
Since the author of the Question failed to supply any sample data, let's create a value in this screwy fashion. Get the current moment in Chicago time zone. Get a legitimate count-from-epoch, adjusting from nanosecond resolution to millisecond. Then arbitrarily add/subtract the offset from UTC for that time zone.
In this example we use the time zone America/Chicago. It's offset for our sample, with Daylight Saving Time, is -05:00. In milliseconds, 5 * 60 * 60 * 1,000 = 18,000,000.
// First, create sample data, a count-from-epoch but not in UTC, instead adjusted for the time zone’s offset.
ZoneId zoneId = ZoneId.of( "America/Chicago" );
// 2015-09-19T12:34:56.000-05:00[America/Chicago]
ZonedDateTime zdtTemp = ZonedDateTime.of( 2015 , 9 , 19 , 12 , 34 , 56 , 0 , zoneId );
long millisecondsFromEpoch = zdtTemp.toInstant().toEpochMilli(); // Loosing data, goin from nanosecond
long offsetInMillisecondsForChicagoInDaylightSavingTime = 18_000_000L; // Offset of `-05:00` is in milliseconds, 5 * 60 * 60 * 1,000 = 18,000,000.
long input = ( millisecondsFromEpoch - offsetInMillisecondsForChicagoInDaylightSavingTime );
Dump to console.
System.out.println( "zoneId : " + zoneId );
System.out.println( "zdtTemp : " + zdtTemp );
System.out.println( "millisecondsFromEpoch : " + millisecondsFromEpoch );
System.out.println( "offsetInMillisecondsForChicagoInDaylightSavingTime : " + offsetInMillisecondsForChicagoInDaylightSavingTime );
System.out.println( "input : " + input );
Now, do the job. Take that screwy input number, pretending it is in UTC even though we know it is not, to produce an Instant. From the Instant, get a LocalDateTime. Now push that LocalDateTime into a time zone to get what we finally want, a ZonedDateTime.
// With example data in hand, proceed to convert to a valid date-time object.
Instant instantPretendingToBeInUtcButNotReally = Instant.ofEpochMilli( input );
LocalDateTime localDateTimeOfPretendInstant = LocalDateTime.ofInstant( instantPretendingToBeInUtcButNotReally , ZoneOffset.UTC );
ZonedDateTime zdt = localDateTimeOfPretendInstant.atZone( zoneId );
Dump to console.
System.out.println( "instantPretendingToBeInUtcButNotReally : " + instantPretendingToBeInUtcButNotReally );
System.out.println( "localDateTimeOfPretendInstant : " + localDateTimeOfPretendInstant );
System.out.println( "zdt : " + zdt );
When run.
zoneId : America/Chicago
zdtTemp : 2015-09-19T12:34:56-05:00[America/Chicago]
millisecondsFromEpoch : 1442684096000
offsetInMillisecondsForChicagoInDaylightSavingTime : 18000000
input : 1442666096000
instantPretendingToBeInUtcButNotReally : 2015-09-19T12:34:56Z
localDateTimeOfPretendInstant : 2015-09-19T12:34:56
zdt : 2015-09-19T12:34:56-05:00[America/Chicago]
CAVEAT I did this in rush. Please comment or fix any errors.
Because chronological time units are interconvertible, at first blush it might seem that you could have a local date-time in the following double precision format:
57272.5
where...
57272 is the day number reckoned from the modified Julian day number epoch (Nov 17, 1858).
0.5 is local time expressed as a fraction of one day, e.g. 0.5 = 12:00 noon local time.
There is nothing wrong with expressing a local date-time in this manner. However, numbers are numbers and so instead of a count of days since the modified Julian day number epoch, one can convert this to a count of milliseconds since the POSIX epoch (seemingly) very simply as:
localMillis = ( dayNumber - POSIX_EPOCH_AS_MJD) / (86400.0 * 1000.0);
This is where the notion of "milliseconds since the local epoch" has come from in this case. The mistake here, though, is that there IS NOT a simple one-to-one correspondence between POSIX Epoch millis and "local" epoch millis (the definition of POSIX Time requires that the count be milliseconds from the Epoch in UTC). This is because the local number contains one or more local offsets from UTC that are not guaranteed to be historically consistent (depending on legislation, etc).
These "local" millis can be used as a local time stamp, but they need to be adjusted for historical daylight savings and time zone offsets with the same care that any other time stamp should be. So why use them? I can't think of a reason. Having a time stamp in this format was a mistake.
The solution to this problem that has been employed:
Convert the "local millis" to a modified Julian day number with the local time expressed as a fraction of one day
Transform the modified Julian day number to a local Gregorian calendar date and time (algorithm adapted from "Astrological Algorithms", 2nd Ed. by J. Meeus).
Create a LocalDateTime instance from the local calendar date-time obtained above
Combine the LocalDateTime with the local ZoneId to contruct a ZonedDateTime, from which an Instant is obtained
POSIX time as UTC milliseconds from the POSIX Epoch is obtained from the Instant
A code example for this procedure follows:
public static long epochMillisFromLocalMillis(ZoneId tz, long millis) {
double dayNum = (millis / (86400.0 * 1000.0)) + POSIX_EPOCH_AS_MJD;
int[] ymd_hmsm = toVectorFromDayNumber(dayNum);
LocalDateTime ldt = LocalDateTime.of (
ymd_hmsm[MJD.YEAR],
ymd_hmsm[MJD.MONTH],
ymd_hmsm[MJD.DAY],
ymd_hmsm[MJD.HOURS],
ymd_hmsm[MJD.MINUTES],
ymd_hmsm[MJD.SECONDS],
ymd_hmsm[MJD.MILLIS] * 1000000);
long utcMillis = ZonedDateTime
.of(ldt, tz)
.toInstant()
.toEpochMilli();
return utcMillis;
}
Thanks to Basil Bourque and assylias for their insights on this peculiar problem.
I am developing a weekly event, but I need to get the milliseconds (unix timestamp) by next Saturday. How can I do that?
1 create a calendar
Calendar calNow = Calendar.getInstance();
2 create another calendar, set it to midnight and move day by day until you hit Saturday
Calendar calNextSat = Calendar.getInstance();
calNextSat.set(Calendar.HOUR, 0);
calNextSat.set(Calendar.MINUTE, 0);
calNextSat.set(Calendar.SECOND, 0);
while(calNextSat.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY){
calNextSat.add(Calendar.DATE, 1);
}
System.out.println(calNextSat.getTimeInMillis() - calNow.getTimeInMillis());
handle the scenario if it is already Saturday you would get <=0 result
I am developing a weekly event
Using milliseconds for this kind of date-time tracking will probably lead you astray. For example, because of Daylight Saving Time (DST) and other anomalies, a day is not always 24-hours long and therefore a week is not always ( ( 1000L * 60 * 60 * 24 ) * 7 ) milliseconds long.
Joda-Time or java.time
I suggest learning how to use a sophisticated date-time library. In Java that means either:
Joda-Time
java.time (built into Java 8, inspired by Joda-Time).
Time Zone
The time zone is crucial in determining the day and day-of-week. Use proper time zone names, never the 3 or 4 letter codes.
Example Code To Get Next Day-Of-Week
Here is example code using Joda-Time 2.7.
Get the time zone you desire/expect. If working in UTC, use the constant DateTimeZone.UTC.
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
Get the date-time value you need. Here I am using the current moment.
DateTime dateTime = DateTime.now( zone );
Specify the future day-of-week you want. Note that Joda-Time uses the sensible # 1 for first day of week, rather than zero-based counting found in java.util.Calendar. First day of week is Monday, per international norms and standards (not Sunday as is common in United States).
int dayOfWeek = DateTimeConstants.SATURDAY;
The withDayOfWeek command may go back in time. So we use a ternary operator (?:) to make sure we go forwards in time by adding a week as needed.
DateTime future = ( dateTime.getDayOfWeek() < dayOfWeek )
? dateTime.withDayOfWeek( dayOfWeek )
: dateTime.plusWeeks( 1 ).withDayOfWeek( dayOfWeek );
You may want to adjust the time-of-day to the first moment of the day to emphasize the focus on the day rather than a particular moment within the day.
future = future.withTimeAtStartOfDay(); // Adjust time-of-day to first moment of the day to stress the focus on the entire day rather than a specific moment within the day. Or use `LocalDate` class.
Dump to console.
System.out.println( "Next day # " + dayOfWeek + " after " + dateTime + " is " + future );
When run.
Next day # 6 after 2015-04-18T16:03:36.146-04:00 is 2015-04-25T00:00:00.000-04:00
Until Then
The code above gives us the desired future point in time (next Saturday).
If all you really want is the number of milliseconds between now and then, subtract between each one’s internal count-from-epoch in milliseconds. Note the use of 64-bit long rather than 32-bit int when tracking times as milliseconds.
long elapsedMilliseconds = ( future.getMillis() - dateTime.getMillis() );
Note that if you are doing this work in java.time rather Joda-Time, be aware that internally java.time uses nanoseconds rather than milliseconds. You can find milliseconds-savvy methods as I recall. Or divide nanoseconds by a million (yes, million not thousand, as microseconds are in between.
You may want to more intelligently represent the span of time between now and then. Joad-Time offers three classes for representing a span of time in various manners:
Interval (a pair of fixed points on the time line)
Period (a number of months, days, hours, and such)
Duration (a number of milliseconds).
Example code, again Joda-Time 2.7.
Interval interval = new Interval( dateTime , future );
Period period = interval.toPeriod();
Dump to console.
System.out.println( "interval: " + interval );
System.out.println( "period: " + period );
When run.
interval: 2015-04-18T16:17:45.109-04:00/2015-04-25T00:00:00.000-04:00
period: P6DT7H42M14.891S
Notice the String representation format used by default for the Period value. That format is standard, part of ISO 8601, called a duration in their terminology. That format is PnYnMnDTnHnMnS where the P marks the beginning and the T separates the date portion from the time portion.
Both Joda-Time and java.time use ISO 8601 as their defaults in both parsing and generating string representations of date-time values.
I would use a Calendar to get the current day of the week. And you could subtract it like,
public static int daysUntilSaturday(Date d) {
Calendar cal = Calendar.getInstance();
cal.setTime(d);
return 7 - cal.get(Calendar.DAY_OF_WEEK);
}
Then you can perform simple arithmetic like
/*
* 1000 milliseconds in a second, 60 seconds in a minute, 60 minutes in
* an hour, 24 hours in a day.
*/
final long millisecondsPerDay = 1000L * 60 * 60 * 24;
System.out.println((daysUntilSaturday(new Date()) * millisecondsPerDay)
+ System.currentTimeMillis());
I have due_date = 2014-05-09 11:36:41.816.
I want to check condition that if today date is same as due_date or 1 day less then due_date then user can renew other wise have to show message that too early to renew.
means if I renew on date 8 then user can do but if user do it on date 7 then he is not allowed and display message.
I know that to check for same day means date 9, i can use :
Timestamp t = new Timestamp(new Date().getTime());
if (t.compareTo(due_date)==0){
//renew book
}
but i don't know that how to do for 1 day before calculation.
So any guidance to do for that.
Decent Date-Time Library
You should be using either Joda-Time or the new java.time in Java 8, as the old java.util.Date and .Calendar classes are notoriously troublesome.
Time Zone
You should not ignore the issue of time zone. Omitting time zone means your JVM's (host computer's) default time zone will apply. Your results will vary.
The definition of a "day" and "yesterday" depends on your particular time zone.
Use a proper time zone name (mostly continent slash city). Avoid the 3 or 4 letter codes as they are neither standardized nor unique.
If your input string has no time zone offset, meaning it is in UTC, then specify using the built-in constant DateTimeZone.UTC.
Interval
Joda-Time offers the Interval class to define a span of time. In your case the span is two days, the due date's day plus the day before. (By the way, both your posted questions and your programming will improve if you work harder at focusing and simplifying your problem as I just did in that preceding sentence.)
Half-Open
Usually in date-time work we use the "half-open" approach to define a span. That means the beginning is inclusive and the ending in exclusive for purposes of comparison. So for your purpose we want to run from the first moment of the day before due date up to, but not including, the first moment of the day *after* due date.
ISO 8601
Your input string is nearly in ISO 8601 standard format. Just replace the SPACE with a T. Joda-Time has built-in parsers for ISO 8601 formats.
Example Code
Example code in Joda-Time 2.3.
String inputDueDateRaw = "2014-05-09 11:36:41.816"
String inputDueDate = inputDueDateRaw.replace( " ", "T" );
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime due = new DateTime( inputDueDate, timeZone ); // Note the time zone by which to interpret the parsing of the string.
DateTime dayBeforeDue = due.withTimeAtStartOfDay().minusDays( 1 ).withTimeAtStartOfDay();
DateTime dayAfterDue = due.withTimeAtStartOfDay().plusDays( 1 ).withTimeAtStartOfDay(); // Half-open. Up to but not including day after.
Interval renewalInterval = new Interval( dayBeforeDue, dayAfterDue );
Test if the current moment is within that interval, using half-open approach to comparison.
boolean isNowEligibleForRenewal = renewalInterval.contains( DateTime.now() );
The actual value a.compareTo(b) returns is meaningless. The only thing you can trust is that if it's positive a is "larger" than b, and if it's negative, a is "smaller". You can't count on its absolute value to determine the difference between the two.
You could, however, just compare the unix time representation of both dates:
TimeStamp due_date = ...;
long dueDateMillis = due_date.getTime();
long t = System.currTimeMillis();
long threshold = 24L * 60L * 60L * 1000L; // One day in milliseconds
if (dueDateMillis - t <= threshold) {
// Renew book
}
Another way to do this is using the Calendar object:
Calendar today = Calendar.getInstance();
today.setTimeInMillis(System.currentTimeMillis()); // time today
Timestamp dueDateTs = new Timestamp(...);
Calendar dueDate = Calendar.getInstance();
dueDate.setTimeInMillis(dueDateTs.getTime());
dueDate.roll(Calendar.DAY_OF_YEAR, false); // to subtract 1 day
if(today.after(dueDate)) {
// do your magic
}