I just want to calculate time difference in minutes, hopefully there is already a class which does it correctly.
So the values which I get from the website are only Hours and Minutes (for instance: event starts at: 20:30 and ends at 03:30).
When I use 'Duration.between' I get incorrect values - it is happening when the first value is greater than second or second is past midnight.
I think I would be able to do this with 'ifs' and 'elses' but I am sure that there is already a class or a method which would solve the issue in more elegant way, but I can't find it.
Here is my code: it works only when the second value is greater than first:
LocalTime eventStarts = LocalTime.now();
LocalTime eventEnds = LocalTime.now();
eventStarts = eventStarts.withHour(22).withMinute(00);
eventEnds = eventEnds.withHour(03).withMinute(00);
Duration durationBetweenEvents = Duration.between(eventStarts, eventEnds);
System.out.println(durationBetweenEvents.toMinutes());
in this case i get '-1140'
Just add the following to your code.
if (durationBetweenEvents.isNegative()) {
durationBetweenEvents = durationBetweenEvents.plusDays(1);
}
You have to be a little careful with daylight savings. Your calculation can be an hour out, if daylight savings time starts or ends between the events. But without knowing date or timezone information, there's no way to deal with that.
Need dates & time zone
LocalTime has no notion of dates or days. So it is limited to a single generic 24-hour day. Going from an evening time to a morning time is viewed as going backwards in time, not wrapping around to another day as no days exist.
To know the duration of an actual event you need dates and time zone.
Getting the current date requires a time zone. For any given moment, the date varies around the globe by zone.
Once you have dates, apply a ZoneId to get ZonedDateTime objects. From there you can get a Duration that takes into account anomalies such as Daylight Saving Time (DST).
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
LocalDate tomorrow = today.plusDays( 1 );
ZonedDateTime zdtStart =
ZonedDateTime.of( today , LocalTime.parse( "20:30" ) , z ) ;
ZonedDateTime zdtStop =
ZonedDateTime.of( tomorrow , LocalTime.parse( "03:30" ) , z ) ;
Duration d = Duration.between( zdtStart , zdtStop ) ;
long totalMinutes = d.toMinutes() ;
zdtStart.toString(): 2017-04-13T20:30-04:00[America/Montreal]
zdtStop.toString(): 2017-04-14T03:30-04:00[America/Montreal]
d.toString(): PT7H
totalMinutes: 420
See this code run live at IdeOne.com.
Related
I need to append 23 Hrs and 59 mins in the date using the Java calendar class.
e.g. 17/03/2022 - has java Date as a datatype - mapped to Date in Oracle
need to be stored in the database as 17/03/2022 23.59.00 - has Timestamp as data type.
I got the following function which works in most cases, but sometimes the date goes to the next day with the timestamp of 00.00.00 .
public Date addHoursToJavaUtilDate(Date date, int hours,int mins) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.HOUR_OF_DAY, hours); //hours = 23
calendar.add(Calendar.MINUTE, mins); //mins = 59
return (Date) calendar.getTime();
}
Why does it works in most of the cases but not all the time? Will reducing the number of mins to 30 will help me?
Do you not have the chance to use java.time.* classes?
I know you specified Calendar usage, but notice how much simplicity you're missing: (written in Kotlin for easier readability)
val yourDate: LocalDateTime = ... // (or if you have TimeZone info, it would be `ZonedDateTime`)
val newDate = yourDate.plusHours(23).plusMinutes(59)
that's it.
You are using terrible date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310.
Calendar, actually GregorianCalendar, was replaced by ZonedDateTime.
Data and time
Capturing the current moment requires a time zone. For any given moment the date and the time can vary around the globe by time zone.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
You want to set the time of day to 23:59:00. We can produce a new ZonedDateTime object based on the old one but with a different time of day. Be aware that your specified time of day will be altered if not valid on that date in that zone, because of anomalies such as Daylight Saving Time (DST).
LocalTime lt = LocalTime.of( 23 , 59 ) ;
ZonedDateTime zdt2359 = zdt.with( lt ) ;
Alternatively, you could capture the current date only. Then assemble a ZonedDateTime from the three parts of date, time, and zone.
LocalDate ld = LocalDate.now ( z ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
Database access
For database access, do not use legacy class Timestamp. Use OffsetDateTime to record a moment in SQL databases.
Write this value to a database column of a type akin to the SQL-standard type TIMESTAMP WITH TIME ZONE.
OffsetDateTime odt = zdt2359.toOffsetDateTime() ;
myPreparedStatement.setObject( … , odt ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Caveat: If you are trying to represent the end of a day, your 23:59 is the wrong approach. You are missing the last minute of the day. And some dates in some zones are not 24 hours long. Instead, learn about tracking time with Half-Open approach.
Could somebody please shed some light on how can I get a period of the day (AM/PM) from the milliseconds timestamp value?
This is currently being done by the following code:
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(prevDate));
assertEquals(cal.get(Calendar.AM_PM), Calendar.PM));
I just need to get rid of java.util.Calendar.
My only idea is to convert long value to LocalDateTime and then to access DateTimeFormatter.ofPattern("a");.
Perhaps somebody could suggest another approach?
You mentioned the formatting code, so it's not clear whether you are looking for a (localized?) string representation of AM/PM, but given a Clock in the appropriate zone, this will indicate the status:
boolean am = LocalTime.now(clock).isBefore(LocalTime.NOON);
If you have a specific Unix time as a number of milliseconds since the epoch, you'll need to specify the local time zone or offset in which you are interested to complete the conversion:
LocalTime when = Instant.ofEpochMilli(prevDate).atZone(zoneId).toLocalTime();
int meridiem = when.isBefore(LocalTime.NOON) ? Calendar.AM : Calendar.PM;
Assert.assertEquals(meridiem, Calendar.PM);
AmPm enum
I suggest you add the ThreeTen-Extra library to your project. This gives you a AmPm class to represent the AM or PM value that you seek. That AmPm class is an enum, defining two objects, one for AM and one for PM. The class carries methods, including the from method to determine the AM or PM of a given moment.
Using an object here makes your code more self-documenting, provides type-safety, and ensures valid values.
Note that a time zone is crucial here. For any given moment, the time-of-day (and even the date) varies around the globe by zone. So while a moment may be morning in Tokyo Japan, it may still be evening in Toledo Ohio US.
ZoneId z = ZoneId.of( "Africa/Tunis" );
ZonedDateTime zdt = ZonedDateTime.now( z );
AmPm amPm = AmPm.from( zdt );
You could then proceed to branch on which enum object was obtained.
switch ( amPm )
{
case AM:
System.out.println( "Good morning." );
break ;
case PM:
System.out.println( "Good day." );
break ;
default:
System.out.println( "ERROR Should never reach this point." );
}
I'm running the below expressions on December 7th, 2018.
I'm seeing a discrepancy whereby this:
ZonedDateTime.now(ZoneId.of("America/New_York")).minusDays(30)
returns (correctly):
2018-11-07T22:44:11.242576-05:00[America/New_York]
whereas conversion to an instant:
ZonedDateTime.now(ZoneId.of("America/New_York")).minusDays(30).toInstant()
seems to mess up the result by adding an extra day to it:
2018-11-08T03:58:01.724728Z
I need an instant conversion to use its result in the following code as Date:
... = Date.from(t.toInstant())
An equivalent Python code (Django) works correctly:
datetime.datetime.now('America/New_York')+datetime.timedelta(days=-30)
evaluating to: datetime: 2018-11-07 20:13:55.063888-05:00
What's causing the discrepancy?
What should I use so that Java conversion to Date resulted in the November 7th being returned, just like in Python's case? Basically, I'm looking to an equivalent translation of that Python code into Java, or in pseudocode:
`datetime.X = datetime.now(deployment_zone) - (N_days)`,
where `deployment_zone` is configurable (i.e. `America/New_York`)
`N_days` is configurable (i.e. 30)
Update for #Basil Bourque:
When I formulated the original question, I (per SO rules) tried to simplify it to a digestible form which probably destroyed most of the necessary context making it vague. Let me try again.
As I explained in the comments, I'm converting the existing Python code (which is more actively maintained and which client wants to keep intact) to existing Java code (legacy that has not been properly maintained and strayed away from the Python's logic some time back). Both code bases need to be functionally on par with each other. Java needs to do what Python is already doing.
Python code is as follows (I'm lumping all into one place for succinctness, in reality it's distributed across a couple of files):
analytics.time_zone=America/New_York
TIME_ZONE = props.getProperty('analytics.time_zone', 'UTC')
TZ = pytz.timezone(TIME_ZONE)
def days_back(num_days=0):
adjusted_datetime = datetime.datetime.now(TZ)+datetime.timedelta(days=-num_days)
return DateRangeUtil.get_start_of_day(adjusted_datetime)
class DateRangeUtil():
#staticmethod
def get_start_of_day(date):
return date.astimezone(TZ).replace(hour=0, minute=0, second=0, microsecond=0)
which basically takes the configured time zone, in which it obtains the current instant, subtracts a specified number of days from it, converts it to the beginning of that date and thus receives the lower bound of the range to use while querying the DB, something like Start time: datetime: 2018-11-07 20:13:55.063888-05:00
When I started on the Java side, it had:
public final static DateRange parse(String dateRange) {
//.....
int days = ...
return new DateRange(toBeginningOfDay(daysBack(days)), toEndOfDay(daysBack(0)));
private final static Date daysBack(int days) {
return toDate(LocalDateTime.now().minusDays(days));
}
private final static Date toBeginningOfDay(Date d)
{
Calendar c=Calendar.getInstance();
c.setTime(d);
c.set(HOUR_OF_DAY,0);
c.set(MINUTE,0);
c.set(SECOND,0);
c.set(MILLISECOND, 0);
return c.getTime();
}
private final static Date toDate(LocalDateTime t) {
return Date.from(t.atZone(ZoneId.systemDefault()).toInstant());
}
That code didn't work and introduced the discrepancy which I describe in my original question. I started experimenting and introduced ZonedDateTime into the picture. While investigating, I found that it's the call to .toInstant() that seems to be a culprit and wanted to understand what's behind it in more depth.
In his answer, #ernest_k suggested a solution which seemed to have worked, but I still didn't quite understood which is clear from questions in the comments to his response.
The changes I made based on #ernest_k response are as follows:
private final static Date daysBack(int days) {
return toDate(ZonedDateTime.now(ZoneId.of("America/New_York")).minusDays(days).toLocalDateTime());
private final static Date toDate(LocalDateTime t) {
return Date.from(t.toInstant(ZoneOffset.UTC));
}
This seems to produce the desired outcome: However conversion from local to zoned and then back again seemed too much, so I experimented a bit more and found that simply the LocalDateTime does the trick as well:
private final static Date toDate(LocalDateTime t) {
return Date.from(t.toInstant(ZoneOffset.UTC));
}
private final static Date daysBack(int days) {
return toDate(LocalDateTime.now().minusDays(days));
}
I can see that LocalDate (and perhaps LocalDateTime) has a convenient atStartOfDay() which seems to be a fitting candidate for elimination of Dates out of the picture while replacing the legacy toBeginningOfDay(Date d) method above. Not sure it's doing the same thing - I haven't yet experimented with that idea, so the suggestions are most welcome.
So, with all of the tribulations above, my question started around toInstant() behavior, and when it's passed a zone id, whether it converts TO an instant in that zone, or FROM it, or what?
I guess for the situation I'm describing we only care that the lower time bound in the DB query is formed by comparing some consistent marker of current time (its upper bound) to what it was in the same place (time zone?) in the past N days, so comparing it with UTC should server the purpose.
Does that then make passing the zone in unnecessary?
Now, that a solution seems to have been found, the question revolves around the soundness of the approach described above and the solution that's been stumbled upon - is it the most optimal one, best practices around Java timing libs, etc. The code needs to work for any time zone in which the code bases will end up being deployed, that's why the zone is passed in via configuration.
Also, I wonder if things change when/if the DB itself is deployed off-premise from the rest of the codebase and is configured to persist data in some other time zone. But that might be another question.
tl;dr
ZonedDateTime.toInstant() adjusts a moment from a time zone to UTC. You end up with the same moment, different wall-clock time, and possibly a different date for the same simultaneous point on the timeline. What you are seeing is not a problem, not a discrepancy.
Your problem is not with subtracting 30 days. The real problems:
Not understanding that time zone affects the date
Conflating dates with days
Furthermore, your Question is vague. Saying “30 days ago” can mean at least three different things:
30 * 24 hours
A range from 22:44 thirty calendar days ago in New York time zone to 22:44 now in New York time
The entire day today as seen in New York and the entire days going back 30 days on the calendar as seen in New York.
All three possibilities are covered below, with example code, labeled with ➥.
⑦🕥 🇺🇸📞 ↔ 📞🇮🇸 ⑧🕞
On the 7th of December, shortly before midnight (22:44), Alice in her New York apartment decides to call her friend Bob in Reykjavík, Iceland. Bob can't believe his phone is ringing, and looking over at the clock on his bedside table sees the time is almost 4 AM (03:44). And Bob's fancy digital clock shows the date as the 8th of December, not the 7th. Same simultaneous moment, same point on the timeline, different wall-clock time, different date.
The people of Iceland use UTC as their time zone, year-round. New York is five hours behind UTC in December 2018, and so five hours behind Iceland. In New York it is “yesterday” the 7th while in Iceland it is “tomorrow” the 8th. Different dates, same moment.
So forget about subtracting the thirty days. Any time you take a moment in New York that is close to midnight, and then adjust to UTC, you will be moving the date forward.
No discrepancy, no extra day added. For any given moment, the date varies around the globe by time zone. With a range in time zones of about 26-27 hours, it is always “tomorrow” and “yesterday” somewhere.
Another Answer suggests involving LocalDateTime into this problem. That is ill-advised. That class purposely lacks any concept of time zone or offset-from-UTC. That means a LocalDateTime cannot represent a moment. A LocalDateTime represents potential moments along the range of 26-27 hours mentioned above. Makes no sense to involve that class here.
Instead, use OffsetDateTime for a moment viewed with an offset-from-UTC, versus [ZonedDateTime][2] which uses a time zone.
What is the difference between an offset and zone? An offset is merely a number of hours-minutes-seconds, nothing more, nothing less. A zone, in contrast, is much more. A zone is a history of the past, present, and future changes to the offset used by the people of particular region. So a time zone is always preferable to a mere offset, as it brings more information. If you want UTC specifically, you need only an offset, an offset of zero hours-minutes-seconds.
OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ; // Adjust from a time zone to UTC.
The zdt and odt seen here both represent the same moment, the same point on the timeline, different wall-clock time, like Alice and Bob example above.
Days != Dates
If you want to query for a range of thirty days ago, you must define what you mean by “days”.
Days
➥ Do you mean 30 chunks of 24-hour long spans of time? If so, work with Instant. This class represents a moment in UTC, always in UTC.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNow = ZonedDateTime.now( z ) ;
Instant instantNow = zdt.toInstant() ; // Adjust from time zone to UTC. Same moment, different wall-clock time.
Instant instantThirtyDaysAgo = instantNow.minus( 30 , ChronoUnit.DAYS ) ; // Subtract ( 30 * 24 hours ) without regard for dates.
You may be able to exchange an Instant with your database via your JDBC driver. But Instant is optional, while support for OffsetDateTime is required by JDBC 4.2 and later. If that is the case, let's re-write that code.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNow = ZonedDateTime.now( z ) ;
OffsetDateTime odtNow = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ; // Adjust from time zone to UTC. Same moment, different wall-clock time.
OffsetDateTime odtThirtyDaysAgo = odtNow.minusDays( 30 ) ;
Your SQL might be something like the following.
Note what we are using the Half-Open approach to defining a span-of-time, where the beginning is inclusive while the ending is exclusive. This is generally best practice, as it avoid the problem of finding the infinitely divisible last moment, and it provides for neatly abutting spans without gaps. So we do not use the SQL command BETWEEN, being fully-closed (inclusive on both ends).
SELECT * FROM event_ WHERE when_ >= ? AND when_ < ? ;
Set values for the placeholders in your prepared statement.
myPreparedStatement.setObject( 1 , odtThirtyDaysAgo ) ;
myPreparedStatement.setObject( 2 , odtNow ) ;
Dates
➥ If by “30 days ago” you meant 30 boxes on the calendar hanging on the wall in a New York office, that is a very different problem.
Same time-of-day
And if so, do you mean from the current moment and moving back 30 days to the same time-of-day?
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNow = ZonedDateTime.now( z ) ;
ZonedDateTime zdtThirtyDaysAgo = zdtNow.minusDays( 30 ) ; // `ZonedDateTime` will try to keep the same time-of-day but will adjust if that time on that date in that zone is not valid.
With the code seen above, the ZonedDateTime class will try to use the same time-of-day on the earlier date. But that time may not be valid on that date in that zone, because of anomalies such as Daylight Saving Time (DST) cutover. In such an anomaly, the ZonedDateTime class adjusts to a valid time. Be sure to study the JavaDoc to understand the algorithm and to see if it suits your business rules.
Pass to your prepared statement.
myPreparedStatement.setObject( 1 , zdtThirtyDaysAgo ) ;
myPreparedStatement.setObject( 2 , zdtNow ) ;
Entire day
➥ Or by “30 days ago” do you mean dates, and by dates you mean all-day-long?
If so, we need to focus on the date-only value, by using LocalDate class, without a time-of-day and without a time zone.
ZoneId z = ZoneId.of( "America/New_York" ) ;
LocalDate today = LocalDate.now( z ) ;
LocalDate tomorrow = today.plusDays( 1 ) ;
LocalDate thirtyDaysAgo = tomorrow.minusDays( 30 ) ;
Now we need to go from the date to a specific moment by assigning a time-of-day and a time zone. We want the time to be the first moment of the day. Do not assume that means 00:00. Because of anomalies such as DST, the day may start at another time such as 01:00. Let java.time determine the first moment of the day on that date in that zone.
ZonedDateTime zdtStart = thirtyDaysAgo.atStartOfDay( z ) ;
ZonedDateTime zdtStop = tomorrow.atStartOfDay( z ) ;
Pass to your prepared statement.
myPreparedStatement.setObject( 1 , zdtStart ) ;
myPreparedStatement.setObject( 2 , zdtStop ) ;
That "extra day" is not really an extra day. 2018-11-07T22:44:11 in New York is equivalent to 2018-11-08T03:58:01 in UTC (it's the same point in time). The difference is just 5 hours, not a day (and when I google this, I see New York is GMT-5).
ZonedDateTime#toInstant returns an Instant instance representing the same point in time (in UTC):
Converts this date-time to an Instant.
This returns an Instant representing the same point on the time-line as this date-time. The calculation combines the local date-time and offset.
If you want to not use the offset when converting to instant, then you should perhaps use LocalDateTime:
ZonedDateTime.now(ZoneId.of("America/New_York"))
.toLocalDateTime()
.toInstant(ZoneOffset.UTC)
This tells it to convert as though it were already UTC time (but a warning is appropriate here: this changes the date/time value)
First, avoid the need for an old-fashioned Date if you can. java.time, the modern Java date and time API, gives you all the functionality you need.
Sometimes we do need a Date for a legacy API that we cannot change or don’t want to upgrade just now. Java is giving you what I think you want. Demonstration:
ZonedDateTime nov7 = ZonedDateTime.of(2018, 11, 7, 22, 44, 0, 0,
ZoneId.of("America/New_York"));
Instant inst = nov7.toInstant();
System.out.println("As Instant: " + inst);
Date oldFashionedDate = Date.from(inst);
System.out.println("As Date: " + oldFashionedDate);
Output from this was:
As Instant: 2018-11-08T03:44:00Z
As Date: Wed Nov 07 22:44:00 EST 2018
Admitted, to get this output I had to change my JVM’s default time zone to America/New_York first.
Date and Instant are roughly equivalent but print differently. Meaning their toString methods behave differently, which may be confusing. Each is a point in time, none of them is a date (despite the name of one of them). It is never the same date in all time zones.
Date.toString picks up your JVM’s time zone setting and uses it for generating the string it returns. Instant.toString on the other hand always uses UTC for this purpose. This is why the same point in time is printed with different date and time. Fortunately they both also print a bit of time zone information so the difference is at least visible. Date prints EST, which, albeit ambiguous, in this case means Eastern Standard Time. Instant prints Z for offset zero from UTC or “Zulu time”.
sample:
Long timeStamp = 1466058808;
Time time = new Time(timeStamp );
DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
System.out.println(format.format(time));
print is: 2016-05-31 08:19:07
How can I get expected results is : 2016-05-31 00:00:00
Thanks!
And finally get the time stamp of 2016-05-31 00:00:00 This is what i want
So anyone know how to make it?
Simple, use:
DateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
Or if you want a long (and have java 8):
LocalDateTime.ofEpochSecond(1466058808, 0, ZoneOffset.UTC).toLocalDate().atStartOfDay().toEpochSecond(ZoneOffset.UTC)
java.time
The Answer by krzyk is close but ignores the crucial issue of time zone. Let's try that again using the java.time framework built into Java 8 and later. Much of java.time functionality is back-ported to Java 6 & 7 (ThreeTen-Backport) and further adapted to Android (ThreeTenABP).
Count of seconds from epoch
You do not say so in the Question, but we assume the Long of 1466058808 is a number of whole seconds from the epoch of first moment of 1970 in UTC.
Instant
First we convert that to an Instant, a moment on the timeline in UTC.
Instant instant = Instant.ofEpochSecond( 1466058808L );
Time Zone
Determining a date, and the start of the day, depends on a time zone. For any given moment, the date can vary around the world by time zone. A few moments after midnight in Paris is still “yesterday” in Montréal.
ZonedDateTime
You can make wide use of Instant in your code. Generally best practice is to perform business logic, data storage, logging, and so on in UTC. Apply a time zone only where required such as display to a user. Apply a ZoneId to get a ZonedDateTime.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Using LocalDate for start-of-day
To get the start of the day we need to go through the LocalDate class. Note that we should always pass the optional time zone argument. If omitted, the JVM’s current default time zone is implicitly applied. That default can change at any time, even during runtime, as any code in any app of the JVM can make a call to TimeZone.setDefault. Better to be specific.
LocalDate localDate = zdt.toLocalDate();
ZonedDateTime startOfDay = localDate.atStartOfDay( zoneId );
Note that you should not assume the day starts at 00:00:00.0. Daylight Saving Time (DST) may mean the day starts at a different wall-clock time.
One-liner
I do not recommend doing so, but you can combine all this into a single line.
ZonedDateTime startOfDay = ZonedDateTime.ofInstant( Instant.ofEpochSecond( 1466058808L ) , ZoneId.of( "America/Montreal" ) ).toLocalDate().atStartOfDay( ZoneId.of( "America/Montreal" ) );
use a Calendar, so you can extract date properties:
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(millis);
//getting the desired properties
cal.get(Calendar.YEAR);
cal.get(Calendar.MONTH);
cal.get(Calendar.DAY_OF_MONTH);
Hello
I wanna create app that has different behaviors if it is morning, noon, afternoon, evening.
Now i wanna set some variables with the time for each
For example noon = 12:00
Now i wanna compare current time with them and see if it is morning for example, and to calculate how much till noon 12:00 - current time.
Now I've seen several examples with different dates, but i want to compare only by hour.
Calendar cal=GregorianCalendar.getInstance();
int hour = cal.get(Calendar.HOUR);
Then compare the hour.
This will work for your local time zone
You can use the joda time hoursBetween or you can use Java calendar class. I would recommend using JodaTime.
Using the Java Calendar class:
Calendar future = Calendar.getInstance(); //future time
future.set(Calendar.YEAR, 2011);
future.set(Calendar.MONTH, 0);
future.set(Calendar.DATE,27);
future.set(Calendar.HOUR_OF_DAY,17);
//get current time
Calendar now = Calendar.getInstance();
//time difference between now and future in hours
long hoursDiff = (future.getTimeInMillis() - now.getTimeInMillis())/(60 * 60 * 1000);
System.out.println("Difference in hours is ="+hoursDiff);//prints 2 since it's 3 pm here
This does not factor in day light savings and compares against your LOCAL time zone.
Using Joda Time hoursBetween:
DateTime futureDate = new DateTime(future.getTime());
DateTime current = new DateTime(now.getTime());
int difference = Hours.hoursBetween(current,futureDate).getHours();
System.out.println("Difference in hours is ="+difference);
Also look at this question and this question.
tl;dr
if (
LocalTime.now( ZoneId.of( "Africa/Tunis” ) )
.isBefore( LocalTime.of( 12 , 0 ) )
) {
… // Do morning stuff.
}
java.time
The other answers were correct but use outmoded classes. The java.util.Date/.Calendar classes have been supplanted by the java.time framework built into Java 8 and later.
The LocalTime class represents a time-of-day without a date and without a time zone.
Make some constants for your definition of "morning", "afternoon", and so on. In real work I would use an enum. But I'll use a simple variable here for the demo.
LocalTime noon = LocalTime.of( 12 , 0 );
Time zone is crucial to interpreting time-of-day. A time-of-day only has meaning in the context of a particular time zone. If not specified, your JVM’s current default time zone will automatically be applied silently. I strongly recommend you instead always explicitly specify the desired/expected time zone. You can think of a ZonedDateTime as being the combination of an Instant plus a time zone (ZoneId).
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now( zoneId );
We can extract a LocalTime from the ZonedDateTime according to its assigned time zone.
LocalTime nowLocalTime = now.toLocalTime();
Compare to the target time.
Boolean isMorning = nowLocalTime.isBefore( noon );
Use the Duration class to represent a span of time as a total number of seconds plus a fraction of a second in nanoseconds.
ZonedDateTime todayNoon = now.adjustInto( noon );
Duration untilNoon = Duration.between( now , todayNoon );
The default output of Duration::toString is a string in a format defined by ISO 8601. Example PT38M2S which thirty-eight minutes and two seconds. You can also ask for number of minutes, etc.
By getting a Duration from ZonedDateTime objects we will get an accurate result accounting for anomalies such as Daylight Saving Time (DST). If you would rather use a generic 24-hour day calculation, pass the LocalTime objects to Duration.between.
You can use GregorianCalendar to do this. Create a new GregorianCalendar and set the month, day, and year to some constant value. Set the hour to whatever time you're interested in, ie 12:00 noon. Now just getTimeInMillis() and store that value. Later, you can create another GregorianCalendar with the no-arg version to get the current time. Set the month, day, and year to the same constant value as your benchmark value, and then just compare the getTimeInMillis() again to see if it is before, equal to, or after the reference time of day.