Reputation: 579
I am trying to calculate the amount of time until the start of a soccer game.
This is what I know:
I want to be able to calculate the difference from the current time to this date in days.
This is what I have tried:
String gameDate = "2016-03-19T19:45:00'Z'"
DateFormat apiFormat = new SimpleDateFormat("yyyy-M-dd'T'h:m:s'Z'");
apiFormat.setTimeZone(TimeZone.getTimeZone("CET"));
Date dateOfGame = apiFormat.parse(gameDate);
DateFormat currentDateFormat = new SimpleDateFormat("yyyy-M-dd'T'h:m:s'Z'");
currentDateFormat.setTimeZone(TimeZone.getTimeZone(userTimezone));
Date currentDate = apiFormat.parse(currentDateFormat.format(new Date()));
long lGameDate = dateOfGame.getTime();
long lcurrDate = currentDate.getTime();
long difference = lGameDate - lcurrDate;
Date timeDifference = new Date(difference);
String daysAway = new SimpleDateFormat("d").format(timeDifference);
Integer intDaysAway = Integer.parseInt(daysAway);
You are probably wondering why I don't just get the date of the game (8) and subtract the current date (19). I don't do that in the edge case that the current date is the 29th and the game date is the 3rd of the next month.
Upvotes: 6
Views: 12429
Reputation: 338835
ChronoUnit.DAYS.between(
Instant.parse( "2016-08-16T19:45:00Z" ).atZone( ZoneId.of( "Europe/Paris" ) ),
Instant.parse( "2016-08-23T12:34:00Z" ).atZone( ZoneId.of( "Europe/Paris" ) )
);
There are two ways to count a number of days. Your Question is not quite clear which you intended. This Answer shows example code for both ways.
Example of the differences: Start late Monday night, an hour before midnight. Stop an hour after midnight on Wednesday morning. For 24-hour chunks that total of 26 hours is a single day. But by calendar dates that would two elapsed days, having touched three calendar days.
Why two days if we touched three? Date-time work commonly uses the Half-Open approach where the beginning is inclusive while the ending is exclusive.
The modern way to do this work is with the java.time classes rather than the troublesome old legacy date-time classes (Date
, Calendar
, etc.).
The Answer by dcsohl is correct but could be shorter. No need to be explicit about the DateTimeFormatter
as the input string is in one of the standard ISO 8601 formats used by default.
I know the string format of it is "yyyy-M-dd'T'h:m:s'Z'"
As part of the ISO 8601 standard, the Z
on the end is short for Zulu
and means UTC.
String startInput = "2016-08-16T19:45:00Z" ;
String stopInput = "2016-08-23T12:34:00Z" ;
Parse as Instant
objects. The Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant start = Instant.parse( startInput );
Instant stop = Instant.parse( stopInput );
I know the timezone is "CET".
Time zone is irrelevant to parsing the strings. But time zone does matter in terms of calculating elapsed days if counting by calendar dates rather than by 24-hours per generic day.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 3-4 letter abbreviation such as EST
or IST
or CET
as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Europe/Paris" );
Adjust both our start and stop moments into that time zone.
ZonedDateTime zdtStart = start.atZone( z );
ZonedDateTime zdtStop = stop.atZone( z );
The java.time framework provides two classes for spans of time:
Period
for years-months-daysDuration
for hours-minutes-secondsThe Period
class takes a pair of LocalDate
objects, date-only values without time-of-day and without time zone. We can extract LocalDate
objecs from our ZonedDateTime
objects. Remember that date is determined by zone. So it is crucial that we adjusted our UTC values into ZonedDateTime
objects.
Period p = Period.between( zdtStart.toLocalDate() , zdtStop.toLocalDate() );
You can interrogate that Period
for the number of years and months and days of that span of time.
If you want a total number of days, use the ChronoUnit
enum.
long days = ChronoUnit.DAYS.between( zdtStart , zdtStop );
The above is for calendar date-based counting of days.
If you want to count by generic chuncks of 24-hour periods, use the Duration
class as shown in the Answer by dcsohl.
Duration.between( start , stop ).toDays()
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Upvotes: 4
Reputation: 9648
First of all your date format is wrong. It should be yyyy-MM-dd'T'HH:mm:ss'Z'
instead of yyyy-M-dd'T'h:m:s'Z'
.
Also, your gameDate
String should end in Z
and not 'Z'
.
You can easily get the difference in days by just calling the getTime()
function on current and given dates. You don't even have to format the current date.
Here is the code snippet:
public static void main (String[] args) throws Exception
{
String gameDate = "2016-03-19T19:45:00Z";
DateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
apiFormat.setTimeZone(TimeZone.getTimeZone("CET"));
Date dateOfGame = apiFormat.parse(gameDate);
long difference = new Date().getTime() - dateOfGame.getTime();
System.out.println((double)difference / (3600000d * 24d));
}
You can do the rounding on the result if you want.
Upvotes: 0
Reputation: 48278
Try doing/ using TimeUnit
:
final String gameDate = "2016-03-19T19:45:00Z";
final SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
apiFormat.setTimeZone(TimeZone.getTimeZone("CET"));
final Date dateOfGame = apiFormat.parse(gameDate);
final long millis = dateOfGame.getTime() - System.currentTimeMillis();
System.out.println(dateOfGame.getTime() - System.currentTimeMillis());
final String hms = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
System.out.println(hms);
This will print the output:
72:57:34
72 hours, 57 minutes and 34 seconds from now until gameDate
Upvotes: 3
Reputation: 7406
Nobody has yet provided a Java 8 java.time
answer...
String eventStr = "2016-08-16T19:45:00Z";
DateTimeFormatter fmt = DateTimeFormatter.ISO_ZONED_DATE_TIME;
Instant event = fmt.parse(eventStr, Instant::from);
Instant now = Instant.now();
Duration diff = Duration.between(now, event);
long days = diff.toDays();
System.out.println(days);
Upvotes: 7
Reputation: 442
This is what you need:
public static void main (String[] args) throws Exception
{
String gameDate = "2016-03-19T19:45:00Z";
DateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
apiFormat.setTimeZone(TimeZone.getTimeZone("CET"));
Date dateOfGame = apiFormat.parse(gameDate);
long now = new Date().getTime() / (3600000 * 24);
long game = dateOfGame.getTime() / (3600000 * 24);
System.out.println(now - game);
}
This will work because you are getting number of full days since epoch for date of game and now and just need to find difference. Other solutions will have errors in border cases.
Upvotes: 1
Reputation: 937
Your variable difference
contains the time difference in milliseconds. To convert those milliseconds to days, hours, minutes, seconds I recommend you to use the java.util.concurrent.TimeUnit
class.
Example:
final long durationMinutes = TimeUnit.MILLISECONDS.toMinutes(difference);
final long durationSeconds = TimeUnit.MILLISECONDS.toSeconds(difference)
- TimeUnit.MINUTES.toSeconds(durationMinutes);
final long durationMillis = difference- TimeUnit.MINUTES.toMillis(durationMinutes)
- TimeUnit.SECONDS.toMillis(durationSeconds);
final String durationString = String.format("%d min, %d s, %d ms", durationMinutes, durationSeconds, durationMillis);
Upvotes: 0
Reputation: 6274
You could simply take the result from long difference = lGameDate - lcurrDate;
, which is the difference in milliseconds, and convert to whatever unit you like.
For example, in days: int days = difference/1000/3600/24
;
Upvotes: 1