Get milliseconds by next Saturday - java

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());

Related

Bug retrieving current time on Android with a given timezone

In my application I retrieve from a webservice an unix timestamp (between 0 and 15minutes in the future) and I display a countdown to that time in the form of XXm-XXs.
So I simply do System.currentTimeMillis() - timestamp and I convert the result in a human readable date.
Everything works fine but it seems that with certain timezones, my timer is 30 minutes off, because System.currentTimeMillis() return a value 1800000 millis lower than expected because Calendar returns wrong value of minutes when I request minutes with it.
The timezone is the GMT+8 of Kuala Lumpur (Malasya). Using another GMT+8 timezone works normally.
Example:
long till = requestTimeFromWebService()
long now=System.currentTimeMillis();
long remaining_time = till - now;
Calendar c=Calendar.getInstance();
c.setTimeInMillis(remaining_time);
int minutes=c.get(Calendar.MINUTE);
System.out.println(""+minutes+"m");
int seconds=c.get(Calendar.SECOND);
System.out.println(""+seconds+"s");
With this code System.out.println(""+minutes+"m"); prints (e.g) 5m if GMT+2 Rome Timezone is set and 35m if GMT+8 Kuala Lumpur Timezone is set.
Is this a known bug?
I found this: http://www.objectdb.com/database/forum/363 that seems to confirm an issue.
I also found this: https://en.wikipedia.org/wiki/Time_in_Malaysia
Blockquote At 2330 hrs local time of 31 December 1981, people in Peninsular Malaysia adjusted their clocks and watches ahead by 30 minutes to become 00:00 hours local time of 1 January 1982, to match the time in use in East Malaysia, which is UTC+08:00.
This could explain where the bug comes off.
Any advice?
A date-time != span-of-time
You are abusing the date-time class java.util.Calendar (or java.util.Date) to inappropriately track a span of time. That class tracks time as a count of milliseconds since the epoch of start of 1970 in UTC (1970-01-01T00:00:00Z) plus an assigned time zone.
So when you instantiate with a count of milliseconds of 5 minutes, you are actually creating a date-time of 5 minutes after start of 1970, 1970-01-01T00:05:00Z for a java.util.Date and adding a time zone for java.util.Calendar.
When you applied a time zone for Malaysia you end up getting the old-style Malaysia time rules for 1970, not today’s post-1981 Malaysia rules.
So, no bugs, just a misuse of features.
Lesson learned: Do not use a date-time value to represent a span-of-time.
java.time
Another problem: You are using the notoriously troublesome old legacy date-time classes, now supplanted by the java.time classes.
If by “unix timestamp” you meant a count of milliseconds from an epoch of 1970 in UTC such as 1_473_738_754_764L, then use the Instant class. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
First, we simulate some input data as described in Question as being in the future up to 15 minutes.
Instant instantNow = Instant.now ();
long seconds = TimeUnit.MINUTES.toSeconds ( 10 );
String input = Long.toString ( instantNow.plusSeconds ( seconds ).toEpochMilli () ); // 10 minutes in the future.
To process that String input, we convert to a long primitive value, and feed it to a Instant factory method.
Instant instantLater = Instant.ofEpochMilli ( Long.valueOf ( input ) );
Span-of-time
To capture the elapsed time, use the Duration class.
Duration duration = Duration.between ( instantNow , instantLater );
System.out.println ( "instantNow: " + instantNow + " | instantLater: " + instantLater + " | duration: " + duration );
When run. Note the standard ISO 8601 format for a duration PnYnMnDTnHnMnS where P marks the beginning and the T separates the years-months-days portion from the hours-minutes-seconds portion. So PT10M is “ten minutes”. Always use this format for textual representation of elapsed time rather than ambiguous clock-style (HH:MM:SS). The Duration and Period classes in java.time can parse and generate such strings directly with no need to specify a formatting pattern.
instantNow: 2016-09-13T19:16:33.913Z | instantLater: 2016-09-13T19:26:33.913Z | duration: PT10M
Note that none of the above code cared about time zones. All the values were in UTC. Much of your business logic, data storage, and data exchange should be in UTC. Only use zoned values where necessary or for presentation to the user.
Zoned
Your Questions asked about zoned values for Rome and for Malaysia. Apply a ZoneId to get a ZonedDateTime. Specify a proper time zone name. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId zMontreal = ZoneId.of ( "America/Montreal" );
ZoneId zRome = ZoneId.of ( "Europe/Rome" );
ZoneId zKualaLumpur = ZoneId.of ( "Asia/Kuala_Lumpur" );
ZonedDateTime zdtMontreal = instantNow.atZone ( zMontreal );
ZonedDateTime zdtRome = instantNow.atZone ( zRome );
ZonedDateTime zdtKualaLumpur = instantNow.atZone ( zKualaLumpur );
System.out.println ( "instantNow: " + instantNow + " | zdtMontreal: " + zdtMontreal + " | zdtRome: " + zdtRome + " | zdtKualaLumpur: " + zdtKualaLumpur );
instantNow: 2016-09-13T20:23:34.280Z | zdtMontreal: 2016-09-13T16:23:34.280-04:00[America/Montreal] | zdtRome: 2016-09-13T22:23:34.280+02:00[Europe/Rome] | zdtKualaLumpur: 2016-09-14T04:23:34.280+08:00[Asia/Kuala_Lumpur]
While I still don't know why the original code doesn't work, I can resolve my specific problem simply using
Calendar c=Calendar.getInstance(TimeZone.getTimeZone("GMT"));
instead than
Calendar c=Calendar.getInstance();
So I can always compare timestamp with the UTC TimeZone that is what I'm interested in.
Btw, Calendar should work in my case even setting the locale timezone (that is what happens when no argument is passed to getInstance()), and it does for most of the timezones, but apparently not for everyone.

How to retrieve minutes from string date?

I have stored date in a string. Now I want to get minutes from the date string. How can I convert it into minutes?
Here is how I stored in a class:
public String fromDate;
public String toDate;
I have set getter and setter methods. I have saved the date value now I want to retrive the value and convert to minutes.
Retriving Like this:
Calendar c = Calendar.getInstance();
String datefrom = eventData.getFromDate();
I tried using this calendar instance:
c.set(Calendar.HOUR, hour);
c.set(Calendar.MINUTE, minute);
c.set(Calendar.DATE,day);
Date datefrom = c.getTime();
startTime = String.valueOf(datefrom);
int hour = c.get(Calendar.HOUR);
int totalMinutes = hour * 60;
But this I can get from Date object. I have stored date in String format. How can I convert this?
Use Joda-Time:
String fromDate;
String toDate;
DateTimeFormatter format = new DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime fromDT = format.parseDateTime(fromDate);
DateTime toDT = format.parseDateTime(toDate);
Duration duration = new Duration(fromDT, toDT);
int minutes = duration.getStandardMinutes();
To import in Android Studio, update your build.gradle file:
apply plugin: 'android'
dependencies {
compile 'joda-time:joda-time:2.4'
compile 'joda-time:joda-time:2.2'
}
To convert a String to Date in Java you would have to use the DateFormat like the sample below:
String string = "January 26, 2016";
DateFormat format = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
Date date = format.parse(string);
System.out.println(date); // Tue Jan 26 00:00:00 GMT 2016
then you can go ahead with your Calendar implementation.
Usually i'd suggest to parse the time with a SimpleDateFormat, but I think in this case (since the dates seem to have a defined form and there might be problems with the timezones) i'll suggest to retrieve the information yourself:
String date = "Wed Jan 27 07:25:29 GMT+05:30 2016";
String[] times = date.substring(11, 16).split(":");
int minutes = Integer.parseInt(times[0]) * 60 + Integer.parseInt(times[1]);
System.out.println(minutes);
The part date.substring(11, 16) extracts the hours and minutes part from the string ("07:25").
The part .split(":"); splits the string "07:25" into two strings: "07" and "25".
after that you just parse those numbers to integers with Integer.parseInt(...) and calculate the number of minutes!
To get the minutes from a String is possible to use a DateFormat to convert the string to a Date and after use your code.
Your Question is really two questions:
How to parse a String to get a date-time object
How to get number of minutes since start-of-day from a date-time object
The first one, parsing a String into a date-time, has been covered at least 1,845 times on Stack Overflow, so I will skip it. The second Question is addressed below.
Please try to make your questions more clear. And focus on a single topic as narrowly as possible, as that is the intention for Stack Overflow.
Minutes-Of-Day
What you seem to want is called “Minutes-Of-Day”, the number of minutes since the start of the day.
Be careful and thoughtful here as there are two different definitions for minutes-of-day. You can get the actual number of minutes for a specific day in a specific time zone. Or you can calculate for a generic 24-hour day. Because of Daylight Saving Time (DST) and other anomalies, a day is not necessarily 24 hours long. For example, in most of the United States the use of DST means a day may be 23, 24, or 25 hours long.
The Question’s code and other Answers ignore the crucial issue of time zone (a common mistake in date-time work). If you do not specify a time zone, your JVM’s current default time zone is silently applied. Not good… that default can change at any moment, even during runtime! Better to always specify the time zone you expect/desire.
Avoid Old Date-Time Classes
The old date-time classes bundled with the earliest versions of Java are notoriously troublesome. Avoid them. Instead use the java.time framework built into Java 8 and later (see Tutorial). If that technology is not available to you, use the Joda-Time library (which inspired java.time). Examples below are in java.time in Java 8 Update 66.
java.time
Let’s look at March 3rd, 2015. This day was the "Spring ahead" DST changeover day for most of the United States. The clock jumped from 2 AM to 3 AM. So 03:00:00.0 on this day meant two hours (120 minutes) actually elapsed since the start of the day. If we treat this as a generic 24-hour day, we would say three hours (180 minutes) elapsed. The java.time classes can calculate minutes-of-day in both definitions.
First we get 3 AM on that changeover day. We use one of the time zones which recognized DST.
ZoneId zoneId = ZoneId.of ( "America/Los_Angeles" );
ZonedDateTime zdt = ZonedDateTime.of ( 2015 , 3 , 8 , 3 , 0 , 0 , 0 , zoneId );
Generic 24-Hour Day
Next we get the minutes since start of day assuming a generic 24-hour day. The ChronoField enum provides many ways to access TemporalField values such as MINUTE_OF_DAY.
long minutesOfDayForGeneric24HourDay = zdt.get ( ChronoField.MINUTE_OF_DAY );
Actual Day
To get the actual number of minutes elapsed since the start of this particular day for this particular time zone in which DST was changing over, we must do a bit more work. We have to determine the first moment of the day from which we can calculate elapsed time. To get that first moment, we must go through the LocalDate class which is a date-only value without time-of-day nor time zone. On that LocalDate object we call atStartOfDay to adjust back into a date-time value (a ZonedDateTime). You might think you could skip this by assuming the day starts at 00:00:00.0 but that is not always true.
ZonedDateTime zdtStart = zdt.toLocalDate ().atStartOfDay ( zoneId );
Now calculate elapsed time. The Duration class represents a span of time as hours, minutes, and seconds. From that Duration we can ask the total number of minutes, converting hours to minutes.
Duration duration = Duration.between ( zdtStart , zdt );
long minutesOfDayForActualDay = duration.toMinutes ();
Dump to console. Note how the generic ChronoField approach says 180 minutes while the actual Duration approach yields 120 minutes.
System.out.println ( "zdt: " + zdt + " | minutesOfDayForGeneric24HourDay: " + minutesOfDayForGeneric24HourDay + " | duration: " + duration + " | minutesOfDayForActualDay: " + minutesOfDayForActualDay );
zdt: 2015-03-08T03:00-07:00[America/Los_Angeles] | minutesOfDayForGeneric24HourDay: 180 | duration: PT2H | minutesOfDayForActualDay: 120

How do I get POSIX time (UTC) from a serial value local date-time with the Java 8 DateTime API

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.

Date comparison confusion

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
}

Best way to convert months into Milliseconds

I'm trying to convert a no of months into milliseconds
For example:
6 months = X milliseconds
There's no fixed answer to that, because it depends on which months those are - and indeed which year it is. Also potentially which time zone you're in, if you want to take account of that. (I'm assuming you mean the Gregorian calendar, by the way - different calendar systems have different month lengths.)
You could get some sort of "reasonable approximation" by assuming 365.25 days in a year, and saying that 6 months is half of that, then find out that many days in milliseconds. But it would only be an approximation.
For "how many milliseconds does it take to get from date/time X to 6 months later" you'd use an API (even Calendar would work for this particular case, although I'd recommend Joda Time or java.time in Java 8):
Set your start date/time, in the appropriate calendar and time zone
Fetch the "milliseconds since the Unix epoch" (which is easy enough to retrieve in any API) and remember it
Add 6 months
Fetch the "milliseconds since the Unix epoch" again, and subtract the earlier value from it
If you know exactly from when to when those 6 months reach, you can use a variety of ways to calculate the duration, using java.util.Calendar, JodaTime, or the JDK1.8 time API.
But if you don't have particular dates in mind, you can take an average duration for your month.
No API in the world can change that fact.
For example, the JDK1.8 time API uses this for the duration of a month in seconds: (from java.time.temporal.ChronoUnit)
MONTHS("Months", Duration.ofSeconds(31556952L / 12)),
31,556,952 is the number of a seconds in a year, based on a year that lasts 365.2425 days.
You can use the same number directly and get the same result as with the time API:
long months = 6;
long seconds = months * 31556952L / 12;
long milliseconds = seconds * 1000;
Result:
15,778,476,000
Calendar today = Calendar.getInstance();
Calendar sixMonthsAhead = Calendar.getInstance();
sixMonthsAhead.add(Calendar.MONTH, 6);
long differenceInMilis = sixMonthsAhead.getTimeInMillis() - today.getTimeInMillis();
You could also use...
sixMonthsAhead.add(Calendar.DATE, 180);
// or 183 days because 365 / 2 is approximately 183.
instead of...
sixMonthsAhead.add(Calendar.MONTH, 6);
for a more accurate result. But like Jon has mentioned, it will always vary depending on what day of the year it is.
The answer by Jon Skeet is correct.
Joda-Time
Assuming you could specify a pair of beginning and ending points on a time line, here is some example code using the Joda-Time 2.3 library.
This code grabs the current moment, adjusts to first of the month, and adjusts to first moment of that day. Then it adds 6 months. Joda-Time is smart about adding the months, taking into account leap year and various lengths of months. This span of 6 months is then represented as an Interval instance. From that we calculate the number of milliseconds. Note that count of milliseconds needs to be a long (64-bit) rather than an int (32-bit) we Java programmers more commonly use. Lastly, for fun, we see what this span of time looks like when formatted in the ISO 8601 standard’s "Duration" format.
DateTimeZone dateTimeZone = DateTimeZone.forID( "Europe/Paris" ); // Better to specify a time zone than rely on JVM’s default.
DateTime start = new DateTime( dateTimeZone ).withDayOfMonth( 1 ).withTimeAtStartOfDay();
DateTime stop = start.plusMonths( 6 );
Interval interval = new Interval( start, stop );
long milliseconds = interval.toDurationMillis(); // A long, not an int.
Period period = interval.toPeriod(); // For fun… ISO 8601 standard's Duration format.
Dump to console…
System.out.println("start: " + start );
System.out.println("stop: " + stop );
System.out.println("interval: " + interval );
System.out.println("milliseconds: " + milliseconds );
System.out.println("period: " + period );
When run…
start: 2014-04-01T00:00:00.000+02:00
stop: 2014-10-01T00:00:00.000+02:00
interval: 2014-04-01T00:00:00.000+02:00/2014-10-01T00:00:00.000+02:00
milliseconds: 15811200000
period: P6M

Categories