Elapsed time format HH:mm:ss - java

It's a simple problem but I'm not getting it to work.
I'm incrementing a variable each second and setting it in a GregorianCalendar in miliseconds.
And I'm using this format HH:mmss to present the elpased time.
The problem is that the hour starts showing 01 instead of 00. For instance, after 1 minute and 35 seconds what is shown is: 01:01:35 instead of 00:01:35.
Where could be the problem?
There is the important code:
GregorianCalendar timeIntervalDone = new GregorianCalendar(TimeZone.getTimeZone("GMT-1")); //initially I didn't have the TimeZone set, but no difference
SimpleDateFormat dateTimeIntervalFormat = new SimpleDateFormat("HH:mm:ss");
public String getTimeIntervalDoneAsString() {
timeIntervalDone.setTimeInMillis(mTimeIntervalDone); //mTimeIntervalDone is the counter: 3seccond -> mTimeIntervalDone = 3000
return dateTimeIntervalFormat.format(timeIntervalDone.getTime());
}

I think the reason is you set the time zone to GMT-1, but the output is utc. Please try it without that time zone and it should work.

I finally got it:
GregorianCalendar timeIntervalDone = new GregorianCalendar();
SimpleDateFormat dateTimeIntervalFormat = new SimpleDateFormat("HH:mm:ss");
dateTimeIntervalFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

Your approach is a hack, trying to use a date-time moment class (GregorianCalendar) to represent a span of time. Plus your format is ambiguous, looking like a time-of-day rather than a duration.
ISO 8601
An alternative is to use the ISO 8601 standard way of describing a duration: PnYnMnDTnHnMnS where the P marks the beginning and the T separates the year-month-day portion from hour-minute-second portion.
java.time
The java.time framework in Java 8 and later supplants the old java.util.Date/.Calendar classes. The old classes have proven to be troublesome, confusing, and flawed. Avoid them.
The java.time framework is inspired by the highly-successful Joda-Time library, defined by JSR 310, extended by the ThreeTen-Extra project, and explained in the Tutorial.
The java.time framework does use ISO 8601 as its defaults, this otherwise excellent set of classes lacks a class to represent an entire period of years-months-days-hours-minutes-seconds. Instead it breaks the concept into two. The Period class handles years-months-days while the Duration class handles hours-minutes-seconds.
Instant now = Instant.now ();
Instant later = now.plusSeconds ( 60 + 35 ); // One minute and 35 seconds later.
Duration duration = Duration.between ( now , later );
String output = duration.toString ();
Dump to console.
System.out.println ( "output: " + output );
output: PT1M35S

Related

Converting from Joda to Java time

I need to convert joda time to Java time but having some issues
My joda time code :
p.s method is a long type (long argDateString)
DateTime istime = new DateTime(argDateString*1000);
DateTime NormalTime = istime.withZone(DateTimeZone.forID("UTC"));
return normalTime.toString();
My Java code :
Date istime = new date(argDateString*1000);
DateFormat normalTime = DateFormat.getDateTimeInstance(DateFormat.Full, DateFormat.Full);
Return normalTime.format(istime);
With Joda I was getting
1970-01-15T05:45:05.000Z
With Java I am getting
15 January 1970 05:45:05 o'clock UTC
So is there a way to get what i was getting with Joda time ?
Thanks
tl;dr
java.time.Instant
.ofEpochSecond(
Long.parseLong( input )
)
.toString()
Details
Never use Date and DateFormat classes. These are terribly flawed, and are now legacy. They were supplanted by the modern java.time classes defined in JSR 310. The java.time framework is the official successor to the Joda-Time project, both being led by the same man, Stephen Colebourne.
Your first bit of code makes no sense: argDateString*1000. Strings cannot be multiplied.
I suspect your text holds a number of seconds since the first moment of 1970 as seen in UTC. If so, use Long class to parse to a long primitive.
long seconds = Long.parseLong( input ) ; // Parse text into a number.
Pass that number to a static factory method for Instant.
Instant instant = Instant.ofEpochSecond( seconds ) ;
Now you have an object whose value represents a moment, a point on the timeline, as seen in UTC.
To generate text in your desired standard ISO 8601 format, merely call toString. The java.time classes use the ISO 8601 formats by default when generating/parsing text.
String output = instant.toString() ;
All this has been covered many times on Stack Overflow. Search to learn more.

Java XMLGregorianCalendar is changing the time - Strange behavior

I have a date as input = 2021-03-12T10:42:01.000Z.... and I want to transform into this format:
String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";
public String getDate(XMLGregorianCalendar input) {
DateFormat f = new SimpleDateFormat(pattern);
input.toGregorianCalendar().setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));
String output = f.format(input.toGregorianCalendar().getTime());
System.out.println(output);
}
2021-03-12T12:42:01+0200
Basically, it's adding 2hs more. Maybe it's related with the time zone, I didn't test it in another computer. I have 2 questions:
Why this is happening
What can I do to avoid it? It's a legacy app so I don't want to do a big change
Thanks
Basically, it's adding 2hs more
Not really. It's giving you the output for the same instant in time, but in your system local time zone - because you're creating a SimpleDateFormat without specifying a time zone (or a culture):
DateFormat f = new SimpleDateFormat(pattern);
Personally I'd recommend avoiding using java.text.SimpleDateFormat entirely, preferring the java.time types and formatters. But if you definitely want to use SimpleDateFormat, just make sure you set the time zone to UTC (assuming you always want UTC) and ideally set the culture as well (e.g. to Locale.ROOT).
The Answer by Jon Skeet is correct, and smart. You appear to be seeing simply a time zone adjustment. Your two strings 2021-03-12T10:42:01.000Z & 2021-03-12T12:42:01+0200 represent the very same moment. The 12 noon hour, if two hours ahead of UTC, is the same as 10 AM hour with an offset-from-UTC of zero hours-minutes-seconds.
And, as mentioned in that other Answer, you really should avoid using the terrible date-time classes bundled with the earliest versions of Java.
tl;dr
myXMLGregorianCalendar // Legacy class, representing a moment as seen in some time zone.
.toGregorianCalendar() // Another legacy class, also representing a moment as seen in some time zone.
.toZonedDateTime() // A modern *java.time* class, representing a moment as seen in some time zone.
.toInstant() // Another *java.time* class, for representing a moment as seen in UTC.
.truncatedTo( // Lopping off some smaller part of the date-time value.
ChronoUnit.SECONDS // Specifying whole seconds as our granularity of truncation, so lopping off any fractional second.
) // Returns another `Instant` object, rather than altering (mutating) the original, per immutable objects pattern.
.toString() // Generating text representing the content of our `Instant` object, using standard ISO 8601 format.
java.time
The modern approach uses the java.time classes that years ago supplanted SimpleDateFormat, XMLGregorianCalendar , GregorianCalendar, and such.
Convert legacy <——> modern
You can easily convert from the legacy types to java.time. Look for new to/from methods on the old classes.
ZonedDateTime zdt = myXMLGregorianCalendar.toGregorianCalendar().toZonedDateTime() ;
Adjust to offset of zero
Adjust from whatever time zone to UTC by extracting an Instant. This class represents a moment as seen in UTC, always in UTC.
Instant instant = zdt.toInstant() ;
Understand that zdt and instant both represent the same moment, the same point on the timeline, but differ in their wall-clock time.
Truncation
Given the formatting pattern seen in your Question, you seem want to work with a granularity of whole seconds. To lop off any fractional second, truncate to seconds.
Instant truncated = instant.truncatedTo( ChronoUnit.SECONDS ) ;
ISO 8601
Your desired text format is defined in the ISO 8601 standard. That standard is used by default in java.time for parsing/generating strings. So no need to specify any formatting pattern.
String output = truncated.toString() ;

Java Calculate time until event from current time

I am trying to calculate the amount of time until the start of a soccer game.
This is what I know:
I have the time of an event:2016-08-16T19:45:00Z
I know the string format of it is "yyyy-M-dd'T'h:m:s'Z'"
I know the timezone is "CET".
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.
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);
tl;dr
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" ) )
);
Define “days”
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.
Calendar-based days by dateApply the intended time zone to determine the dates of the start and the the stop. A date is determined by zone, as for any given moment the date varies around the globe being “tomorrow” towards the east while “yesterday” to the west depending where you sit. For example a few minutes after midnight in Paris France a new day while still “yesterday” in Montréal Québec.
24-hour chunks of timeIf you consider only generic days of 24-hour chunks of time while ignoring anomalies such as Daylight Saving Time (DST), then you get the total number of seconds between the beginning and ending moment and divide that by 24-hours. In this approach we ignore the calendar and its dates.
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.
Avoid legacy date-time classes
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-days
Duration for hours-minutes-seconds
The 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()
About java.time
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?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
Try doing/ using TimeUnit:
Example:
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
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;
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.
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);
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.

In Java, How to check if time is within two Date objects

I am trying to create a method in Java that returns true if the current time of day is between a set interval (startTime and endTime).
The date is irrelevant. What is the best way to do this?
Here is my attempt it doesn't work:
public boolean isNowBetweenDateTime()
{
final Date now = new Date();
return now.after(startTime) && now.before(endTime);
}
What is the best way (in java) to check if time is within two Date objects, ignoring year, month day?
Your code looks good. Just set the date of now, startTime and endTime to some hard coded value.
tl;dr
Interval.of( start.toInstant() , stop.toInstant() ).contains( Instant.now() )
Half-Open
In date-time handling, the Half-Open approach is commonly used for defining a span of time. The beginning is inclusive while the ending is exclusive. So a week is defined as starting at the first moment of a Monday and running up to, but not including, the first moment of the following Monday. We sometimes use this Half-Open approach intuitively, where a lunch period of 12 to 1 means start at the stroke of noon but be back at your job or class before the clock strikes 1 PM. Using Half-Open consistently throughout your date-time work will make the logic and programming cleaner, clearer, and simpler.
So your logic should be, “Is now not before beginning AND now is before ending”. Notice that “not before” is a compact way of saying “is equal to OR is after”.
boolean isNowBetweenDateTime = ( ! now.before(startTime) ) && now.before(endTime) ; // Not before start AND is before stop.
ZonedDateTime
The Question and other Answers use troublesome old legacy date-time classes now supplanted by the java.time classes.
The ZonedDateTime class represents a moment on the timeline with an assigned time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now( z );
ZonedDateTime start = now.minusWeeks( 1 ); // Simulating input.
ZonedDateTime stop = now.plusWeeks( 2 ); // Simulating input.
You could write the logic yourself to test if now is between.
Boolean isBetween = ( ! now.isBefore( start ) ) && stop.isBefore( stop );
Interval
If doing more of this kind of work, look at the ThreeTen-Extra project. This library extends the java.time classes with additional functionality. Specifically the Interval class will be helpful, representing a pair of moments on the timeline. Implements a variety of comparison methods such as contains, encloses, abuts, and overlaps.
Instantiate a Interval with a pair of Instant objects. Instant represents a moment on the timeline in UTC. We can extract an Instant object from each ZonedDateTime object.
Interval interval = Interval.of( start.toInstant() , stop.toInstant() );
Boolean isBetween = interval.contains( now.toInstant() ); // Or pass `Instant.now()`.
You can also get the current moment as an Instant with a call to Instant.now().
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
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.
First of all, I would recommend to use Calendar instead of Date. I had some problems before, using date.
And I would use the time in milliseconds to compare dates, this is the safest way. The code wuoul be sth like:
Date now = new Date();
long startTimeInMillis = startTime.getTime();
long endTimeInMillis = endTime.getTime();
return now.getTime >= startTimeInMillis && now.getTime < endTimeInMillis;
If you want to ignore the Date and only consider the time of day, consider using Joda-Time's LocalTime, which is designed specifically to hold only the time portion.
Here is an example:
java.util.Date startTime = ... ;
java.util.Date endTime = ... ;
public boolean isNowBetweenDateTime()
{
// get current time
final LocalTime now = new LocalTime();
// convert the java.util.Dates to LocalTimes and then compare
return now.isAfter(LocalTime.fromDateFields(startTime)) &&
now.isBefore(LocalTime.fromDateFields(endTime));
}
This java function returns true if the current time is between two other times. It ignores the year/month/day.
import java.text.*;
import java.util.Date;
public static boolean isNowBetweenHours() throws ParseException
{
String leftBoundaryHours = "01:00:00"; //01:00 hours, military time.(1AM)
String rightBoundaryHours = "14:00:00"; //14:00 hours, military time.(2PM)
//returns true if current time is between
//leftBoundaryHours and rightBoundaryHours.
//This formatter converts a bare string to a date.
DateFormat formatter = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
//add the hand specified time to 1970-01-01 to create left/right boundaries.
Date leftTimeBoundary = formatter.parse("1970-01-01 " + leftBoundaryHours);
Date rightTimeBoundary = formatter.parse("1970-01-01 " + rightBoundaryHours);
//extract only the hours, minutes and seconds from the current Date.
DateFormat extract_time_formatter = new SimpleDateFormat("HH:mm:ss");
//Get the current time, put that into a string, add the 1970-01-01,
Date now = formatter.parse("1970-01-01 " +
extract_time_formatter.format(new Date()));
//So it is easy now, with the year, month and day forced as 1970-01-01
//all you do is make sure now is after left, and now is before right.
if (now.after(leftTimeBoundary) && now.before(rightTimeBoundary))
return true;
else
return false;
}
Invoke the function like this:
try {
System.out.println(isNowBetweenHours());
} catch (ParseException e) {
}
If the current time is after 01:00 hours but before 14:00 hours, it returns true. Else it returns false.

Getting the Time component of a Java Date or Calendar

Is there a simple or elegant way to grab only the time of day (hours/minutes/seconds/milliseconds) part of a Java Date (or Calendar, it really doesn't matter to me)? I'm looking for a nice way to separately consider the date (year/month/day) and the time-of-day parts, but as far as I can tell, I'm stuck with accessing each field separately.
I know I could write my own method to individually grab the fields I'm interested, but I'd be doing it as a static utility method, which is ugly. Also, I know that Date and Calendar objects have millisecond precision, but I don't see a way to access the milliseconds component in either case.
Edit: I wasn't clear about this: using one of the Date::getTime() or Calendar::getTimeInMillis is not terribly useful to me, since those return the number of milliseconds since the epoch (represented by that Date or Calendar), which does not actually separate the time of day from the rest of the information.
#Jherico's answer is the closest thing, I think, but definitely is something I'd still have to roll into a method I write myself. It's not exactly what I'm going for, since it still includes hours, minutes, and seconds in the returned millisecond value - though I could probably make it work for my purposes.
I still think of each component as separate, although of course, they're not. You can write a time as the number of milliseconds since an arbitrary reference date, or you could write the exact same time as year/month/day hours:minutes:seconds.milliseconds.
This is not for display purposes. I know how to use a DateFormat to make pretty date strings.
Edit 2: My original question arose from a small set of utility functions I found myself writing - for instance:
Checking whether two Dates represent a date-time on the same day;
Checking whether a date is within a range specified by two other dates, but sometimes checking inclusively, and sometimes not, depending on the time component.
Does Joda Time have this type of functionality?
Edit 3: #Jon's question regarding my second requirement, just to clarify: The second requirement is a result of using my Dates to sometimes represent entire days - where the time component doesn't matter at all - and sometimes represent a date-time (which is, IMO, the most accurate word for something that contains year/month/day and hours:minutes:seconds:...).
When a Date represents an entire day, its time parts are zero (e.g. the Date's "time component" is midnight) but the semantics dictate that the range check is done inclusively on the end date. Because I just leave this check up to Date::before and Date::after, I have to add 1 day to the end date - hence the special-casing for when the time-of-day component of a Date is zero.
Hope that didn't make things less clear.
Okay, I know this is a predictable answer, but... use Joda Time. That has separate representations for "a date", "an instant", "a time of day" etc. It's a richer API and a generally saner one than the built-in classes, IMO.
If this is the only bit of date/time manipulation you're interested in then it may be overkill... but if you're using the built-in date/time API for anything significant, I'd strongly recommend that you move away from it to Joda as soon as you possibly can.
As an aside, you should consider what time zone you're interested in. A Calendar has an associated time zone, but a Date doesn't (it just represents an instant in time, measured in milliseconds from the Unix epoch).
Extracting the time portion of the day should be a matter of getting the remainder number of milliseconds when you divide by the number of milliseconds per day.
long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
Date now = Calendar.getInstance().getTime();
long timePortion = now.getTime() % MILLIS_PER_DAY;
Alternatively, consider using joda-time, a more fully featured time library.
Using Calendar API -
Solution 1-
Calendar c = Calendar.getInstance();
String timeComp = c.get(Calendar.HOUR_OF_DAY)+":"+c.get(Calendar.MINUTE)+":"+c.get(Calendar.SECOND)+":"+c.get(Calendar.MILLISECOND);
System.out.println(timeComp);
output - 13:24:54:212
Solution 2-
SimpleDateFormat time_format = new SimpleDateFormat("HH:mm:ss.SSS");
String timeComp = time_format.format(Calendar.getInstance().getTime());
output - 15:57:25.518
To answer part of it, accessing the millisecond component is done like this:
long mill = Calendar.getInstance().getTime();
I don't know what you want to do with the specifics, but you could use the java.text.SimpleDateFormat class if it is for text output.
You can call the getTimeInMillis() function on a Calendar object to get the time in milliseconds. You can call get(Calendar.MILLISECOND) on a calendar object to get the milliseconds of the second. If you want to display the time from a Date or Calendar object, use the DateFormat class. Example: DateFormat.getTimeInstance().format(now). There is also a SimpleDateFormat class that you can use.
To get just the time using Joda-Time, use the org.joda.time.LocalTime class as described in this question, Joda-Time, Time without date.
As for comparing dates only while effectively ignoring time, in Joda-Time call the withTimeAtStartOfDay() method on each DateTime instance to set an identical time value. Here is some example code using Joda-Time 2.3, similar to what I posted on another answer today.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classes bundled with Java 7 and earlier.
// http://www.joda.org/joda-time/
// Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8.
// JSR 310 was inspired by Joda-Time but is not directly based on it.
// http://jcp.org/en/jsr/detail?id=310
// By default, Joda-Time produces strings in the standard ISO 8601 format.
// https://en.wikipedia.org/wiki/ISO_8601
// Capture one moment in time.
org.joda.time.DateTime now = new org.joda.time.DateTime();
System.out.println("Now: " + now);
// Calculate approximately same time yesterday.
org.joda.time.DateTime yesterday = now.minusDays(1);
System.out.println("Yesterday: " + yesterday);
// Compare dates. A DateTime includes time (hence the name).
// So effectively eliminate the time by setting to start of day.
Boolean isTodaySameDateAsYesterday = now.withTimeAtStartOfDay().isEqual(yesterday.withTimeAtStartOfDay());
System.out.println("Is today same date as yesterday: " + isTodaySameDateAsYesterday);
org.joda.time.DateTime halloweenInUnitedStates = new org.joda.time.DateTime(2013, 10, 31, 0, 0);
Boolean isFirstMomentSameDateAsHalloween = now.withTimeAtStartOfDay().isEqual(halloweenInUnitedStates.withTimeAtStartOfDay());
System.out.println("Is now the same date as Halloween in the US: " + isFirstMomentSameDateAsHalloween);
If all you're worried about is getting it into a String for display or saving, then just create a SimpleDateFormat that only displays the time portion, like new SimpleDateFormat("HH:mm:ss"). The date is still in the Date object, of course, but you don't care.
If you want to do arithmetic on it, like take two Date objects and find how many seconds apart they are while ignoring the date portion, so that "2009-09-01 11:00:00" minus "1941-12-07 09:00:00" equals 2 hours, then I think you need to use a solution like Jherico's: get the long time and take it module 1 day.
Why do you want to separate them? If you mean to do any arithmetic with the time portion, you will quickly get into trouble. If you pull out 11:59pm and add a minute, now that your time and day are separate, you've screwed yourself--you'll have an invalid time and an incorrect date.
If you just want to display them, then applying various simple date format's should get you exactly what you want.
If you want to manipulate the date, I suggest you get the long values and base everything off of that. At any point you can take that long and apply a format to get the minutes/hours/seconds to display pretty easily.
But I'm just a little concerned with the concept of manipulating day and time separately, seems like opening a can o' worms. (Not to even mention time zone problems!).
I'm fairly sure this is why Java doesn't have an easy way to do this.
Find below a solution which employs Joda Time and supports time zones.
So, you will obtain date and time (into currentDate and currentTime) in the currently configured timezone in the JVM.
Please notice that Joda Time does not support leap seconds. So, you can be some 26 or 27 seconds off the true value. This probably will only be solved in the next 50 years, when the accumulated error will be closer to 1 min and people will start to care about it.
See also: https://en.wikipedia.org/wiki/Leap_second
/**
* This class splits the current date/time (now!) and an informed date/time into their components:
* <lu>
* <li>schedulable: if the informed date/time is in the present (now!) or in future.</li>
* <li>informedDate: the date (only) part of the informed date/time</li>
* <li>informedTime: the time (only) part of the informed date/time</li>
* <li>currentDate: the date (only) part of the current date/time (now!)</li>
* <li>currentTime: the time (only) part of the current date/time (now!)</li>
* </lu>
*/
public class ScheduleDateTime {
public final boolean schedulable;
public final long millis;
public final java.util.Date informedDate;
public final java.util.Date informedTime;
public final java.util.Date currentDate;
public final java.util.Date currentTime;
public ScheduleDateTime(long millis) {
final long now = System.currentTimeMillis();
this.schedulable = (millis > -1L) && (millis >= now);
final TimeZoneUtils tz = new TimeZoneUtils();
final java.util.Date dmillis = new java.util.Date( (millis > -1L) ? millis : now );
final java.time.ZonedDateTime zdtmillis = java.time.ZonedDateTime.ofInstant(dmillis.toInstant(), java.time.ZoneId.systemDefault());
final java.util.Date zdmillis = java.util.Date.from(tz.tzdate(zdtmillis));
final java.util.Date ztmillis = new java.util.Date(tz.tztime(zdtmillis));
final java.util.Date dnow = new java.util.Date(now);
final java.time.ZonedDateTime zdtnow = java.time.ZonedDateTime.ofInstant(dnow.toInstant(), java.time.ZoneId.systemDefault());
final java.util.Date zdnow = java.util.Date.from(tz.tzdate(zdtnow));
final java.util.Date ztnow = new java.util.Date(tz.tztime(zdtnow));
this.millis = millis;
this.informedDate = zdmillis;
this.informedTime = ztmillis;
this.currentDate = zdnow;
this.currentTime = ztnow;
}
}
public class TimeZoneUtils {
public java.time.Instant tzdate() {
final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
return tzdate(zdtime);
}
public java.time.Instant tzdate(java.time.ZonedDateTime zdtime) {
final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
final java.time.Instant instant = zddate.toInstant();
return instant;
}
public long tztime() {
final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
return tztime(zdtime);
}
public long tztime(java.time.ZonedDateTime zdtime) {
final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
final long millis = zddate.until(zdtime, java.time.temporal.ChronoUnit.MILLIS);
return millis;
}
}
tl;dr
LocalTime lt = myUtilDate.toInstant().atZone( ZoneId.of( "America/Montreal" ) ).toLocalTime() ;
Avoid old date-time classes
You are using old legacy date-time classes. They are troublesome and confusing; avoid them.
Instead use java.time classes. These supplant the old classes as well as the Joda-Time library.
Convert
Convert your java.util.Date to an Instant.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = myUtilDate.toInstant();
Time Zone
Apply a time zone. Time zone is crucial. For any given moment the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while also being “yesterday” in Montréal Québec.
Apply a ZoneId to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Local… types
The LocalDate class represents a date-only value without time-of-day and without time zone. Likewise, the LocalTime represents a time-of-day without a date and without a time zone. You can think of these as two components which along with a ZoneId make up a ZonedDateTime. You can extract these from a ZonedDateTime.
LocalDate ld = zdt.toLocalDate();
LocalTime lt = zdt.toLocalTime();
Strings
If your goal is merely generating Strings for presentation to the user, no need for the Local… types. Instead, use DateTimeFormatter to generate strings representing only the date-portion or the time-portion. That class is smart enough to automatically localize while generating the String.
Specify a Locale to determine (a) the human language used for translating name of day, name of month, and such, and (b) the cultural norms for deciding issues such as abbreviation, capitalization, punctuation, and such.
Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter fDate = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM ).withLocale( locale );
String outputDate = zdt.format( fDate );
DateTimeFormatter fTime = DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM ).withLocale( locale );
String outputTime = zdt.format( fTime );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time.

Categories

Resources