In my application, it saves a preference which is an integer that is the number of days since the epoch. (not relevant but it is used to create backups every x days)
Given this value, how can I reliably create an instance of joda DateTime?
I'm tempted to convert it to milliseconds by doing the multiplication value * 24 * 60 * 60 * 1000 but this will be wrong due to astronomy / solar time?
Multiplying number of days into the number of milliseconds might be more readable if you use a library function. I highly recommend using Joda. :)
You have a number of days since epoch (GMT), and you want a DateTime (date + time + timezone). At a bare minimum, before you get further, you'll need to specify how you want to treat the time and timezone calculation.
The simplest way (which might not be what you intend) would be to create an instant in the local timezone representing the beginning of epoch, and then use plusDays to add the right number of days:
// in class - note that this will cache the current default timezone
private static final DateTime EPOCH_START_INSTANT = new DateTime(0);
// West of Greenwich, this will actually represent the "day" before.
// Day 0 will be Dec 31, 1969, local time.
DateTime localTime = EPOCH_START_INSTANT.plusDays(yourDayCount);
For the purpose of creating a backup every X days, you might instead want a LocalDate initialized at epoch (January 1, 1970), plus the number of days you want. That could then be changed to a specified local time relatively easily.
// in class
private static final EPOCH_LOCALDATE = new LocalDate(1970, 1, 1);
private static final THREE_AM = new LocalTime(3, 0);
LocalDate localDate = EPOCH_LOCALDATE.plusDays(yourDayCount);
// Midnight (or closest valid time thereto) in the default time zone
DateTime startOfDay = localDate.toDateTimeAtStartOfDay();
// 3 AM in the default time zone
DateTime threeAM = localDate.toDateTime(THREE_AM);
The answer by Jeff Bowman is correct.
I'll show the same idea in the java.time framework, intended to succeed Joda-Time.
java.time
Java 8 and later has the new java.time framework built-in. These new classes supplant the old java.util.Date/.Calendar classes. They are inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.
I am assuming your count-of-day-from-epoch is in UTC. So we can use the Instant class, basically a count of nanoseconds from the first moment of 1970 in UTC.
long myCountOfDays = 16_721L;
Instant instant = Instant.EPOCH.plus ( myCountOfDays , ChronoUnit.DAYS );
Let's adjust into a time zone. Choosing Montreal arbitrarily. Use a proper time zone name, never the 3-4 letter codes like "EST" or "IST".
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
Dump to console.
System.out.println ( "myCountOfDays: " + myCountOfDays + " from epoch: " + Instant.EPOCH + " in UTC is: " + instant + " and in Montréal is: " + zdt + "." );
When run.
myCountOfDays: 16721 from epoch: 1970-01-01T00:00:00Z in UTC is: 2015-10-13T00:00:00Z and in Montréal is: 2015-10-12T20:00-04:00[America/Montreal].
According to the FAQ:
Joda-Time does not support leap seconds. Leap seconds can be supported by writing a new, specialized chronology, or by making a few enhancements to the existing ZonedChronology class. In either case, future versions of Joda-Time will not enable leap seconds by default. Most applications have no need for it, and it might have additional performance costs.
That suggests to me that you need not worry about that aspect.
But rather than doing the math, I would use DateTime#plusDays or MutableDateTime#addDays instead, using The Epoch as your starting point.
I assume, though, that your "days since The Epoch" is allowing for leap days (and that you're using the Gregorian chronology so JodaTime is, too).
Related
I have two epoch timestamps, I am trying to find the number of days between the two timestamps.
This is what I have now:
dateFrom = inputEntry.getValue(inputFields(0).get).asInstanceOf[String].toLong
dateTo =inputEntry.getValue(inputFields(1).get).asInstanceOf[String].toLong
Example:
dateFrom dateTo result
1501583232 1501641000 1
1501583232 1501986600 5
I am starting with two epoch dates here
tl;dr
ChronoUnit.DAYS.between( … , … )
Details
This has been covered many times already on Stack Overflow. So briefly here…
For date-time values, use date-time objects. Use java.time classes only, avoid the troublesome legacy date-time classes ( Date, Calendar, etc).
Do you mean a difference of dates or a difference of 24-hour chunks of time?
I'll go with dates here.
First, translate what appears to be number of whole seconds since an epoch reference date of 1970-01-01T00:00:00Z into a point in the timeline in UTC.
Note the L on the end of numeric literal to indicate a long rather than int.
Instant instant = Instant.ofEpochSecond( 1_501_583_232L ) ;
Assign time zone for which you want to consider dates.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z );
Convert to a date-only.
LocalDate ld = zdt.toLocalDate() ;
Get difference.
long days = ChronoUnit.DAYS.between( ld , ld2 ) ;
To get the results you want, you must define how you're going to calculate the difference.
Taking your first example (difference between 1501583232 and 1501641000 should be 1 day):
The epochs 1501583232 and 1501641000 are the number of seconds since 1970-01-01T00:00Z, so they are equivalent to the following UTC dates:
1501583232: 2017-08-01T10:27:12Z
1501641000: 2017-08-02T02:30:00Z
Note that the difference between them is 16 hours, 2 minutes and 48 seconds (so, less than a day). If you get the difference in days, technically it will be zero.
But if you consider only the dates (2017-08-01 and 2017-08-02) and ignore the time (hour/minute/second), then the difference can be either zero or 1, depending on the timezone you are.
If you consider only the UTC dates (2017-08-01 and 2017-08-02), the difference is 1 day.
But if you take the same UTC dates above in America/Los_Angeles timezone, you'll get:
1501583232: 2017-08-01T03:27:12-07:00
1501641000: 2017-08-01T19:30-07:00
Now the difference is zero days, no matter if you consider only the date (both are 2017-08-01), or the date and time (the difference in hours will be 16, less than a day).
So, you must define how you're going to calculate the difference (consider only the date, or both date and time, and what timezone will be used).
In your case, it seems that you're considering only the date and ignoring the time, but it's not clear what timezone it's using. Anyway, you can use JDK's 8 new java.time API for that (for JDK <= 7 you can use the ThreeTen Backport - The code below works for both. The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same).
The code is basically the same of #BasilBourque's answer, because it's very straighforward with the new API (I just wanted to add the insights above).
First you create the Instant's from the epoch values:
Instant instant1 = Instant.ofEpochSecond(1501583232L);
Instant instant2 = Instant.ofEpochSecond(1501641000L);
If you want the difference considering the date and time, you can use:
ChronoUnit.DAYS.between(instant1, instant2);
The result will be zero.
If you want to consider only the dates in UTC (and ignore the time), just do:
// convert to UTC and get just the date (day/month/year)
LocalDate d1 = instant1.atZone(ZoneOffset.UTC).toLocalDate();
LocalDate d2 = instant2.atZone(ZoneOffset.UTC).toLocalDate();
long days = ChronoUnit.DAYS.between(d1, d2);
The result will be 1.
To convert to a different timezone (instead of UTC), use the ZoneId class:
// use a specific timezone
ZoneId zone = ZoneId.of("Asia/Kolkata");
// convert the Instant to a timezone and get only the date
LocalDate d1 = instant1.atZone(zone).toLocalDate();
LocalDate d2 = instant2.atZone(zone).toLocalDate();
long days = ChronoUnit.DAYS.between(d1, d2);
In this case, the difference is 1, but as I said above, different timezones can produce different results (can be either zero or 1 - for example, changing the code above to ZoneId.of("America/Los_Angeles"), the result is zero).
Note that the API uses IANA timezones names (always in the format Region/City, like Asia/Kolkata or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or IST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
You can also use the system's default timezone with ZoneId.systemDefault(), but this can be changed without notice, even at runtime, so it's better to explicity use a specific one.
Date d = new Date(today.getTimeInMillis());
Date d1 = new Date(dueDate.getTimeInMillis());
int daysUntil = (int) ((d1.getTime() - d.getTime())/ (1000 * 60 * 60 * 24));
Using the above code, where today is a calendar set to 00:00 on the current day, and dueDate is set to 00:00 on the date I am comparing today to, my results from this differ.
There is something in this which varies, making my output either x or x+1 where x is the correct answer.
What is the issue here, and what can I do to make it more stable?
Vague Question
You do not provide actual values, so we cannot determine precisely the problem. We do not know what the today and dueDate variables are.
Outmoded
The question is now outmoded, as the troublesome old date-time classes including java.util.Date/.Calendar have been supplanted by the new java.time framework. See Tutorial. Defined by JSR 310, inspired by Joda-Time, and extended by the ThreeTen-Extra project.
In java.time:
An Instant is a moment on the timeline in UTC.
A ZoneId represents a time zone. Use proper time zone names, never the 3-4 letter codes like "EST" or "IST" as they are neither standardized nor unique.
Conceptually, ZonedDateTime = Instant + ZoneId.
ThreeTen-Extra
Unfortunately, java.time does not include a facility for calculating days elapsed between date-time values. We can use the ThreeTen-Extra project and its Days class with between method to provide that calculation. The ThreeTen-Extra project is a collection of features deemed non-essential for java.time during the JSR process.
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime then = now.minusDays ( 4 );
ZonedDateTime due = now.plusDays ( 3 );
Integer days = org.threeten.extra.Days.between ( then , due ).getAmount ();
Dump to console.
System.out.println ( "From then: " + then + " to due: " + due + " = days: " + days );
From then: 2015-10-31T16:01:13.082-04:00[America/Montreal] to due: 2015-11-07T16:01:13.082-05:00[America/Montreal] = days: 7
Joda-Time
For Android or older versions of Java, use the excellent Joda-Time library.
The Days class is smart and handles anomalies such as Daylight Saving Time (DST).
Note that unlike java.util.Date, a Joda-Time DateTime object knows its own time zone.
// Specify a time zone rather than rely on default.
DateTimeZone timeZone = DateTimeZone.forID( "America/Regina" ); // Or "Europe/London".
DateTime now = new DateTime( timeZone );
DateTime startOfToday = now.withTimeAtStartOfDay();
DateTime fewDaysFromNow = now.plusDays( 3 );
DateTime startOfAnotherDay = fewDaysFromNow.withTimeAtStartOfDay();
Days days = Days.daysBetween( startOfToday, startOfAnotherDay );
Dump to console…
System.out.println( days.getDays() + " days between " + startOfToday + " and " + startOfAnotherDay + "." );
When run…
3 days between 2014-01-21T00:00:00.000-06:00 and 2014-01-24T00:00:00.000-06:00.
There are mainly two reasons why your code is broken:
second parts or millisecond fractions (you might have overlooked)
daylight saving effects
I demonstrate and explain the second reason.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = sdf.parse("2016-03-20");
Date d2 = sdf.parse("2016-03-28");
int daysUntil = (int) ((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
System.out.println(daysUntil); // 7 (should be 8)
The code was run in timezone "Europe/Berlin". Due to the change from winter time to summer time causing a jump of clocks by one hour forward on 2016-03-27 at 2 am, there is one hour missing. One day has only 23 hours so the division by 24 yields zero resulting in counting one day less.
What can you do else?
Your workaround adding 1000 milliseconds to dueDate sounds as if you have overlooked possible millisecond deltas in your input. This might solve a special case but will usually not be sufficient to solve the daylight saving problem, too. Whatever you choose on base of java.util.Date it is a more or less an evil hack.
The best I have in mind (within the scope of Android-built-in stuff) is to construct an instance of java.util.GregorianCalendar and to add successively one day after one until you have passed the due-date, and then count how many days you have added. Not elegant and errorprone because varying millisecond parts can easily be overlooked here, too.
Otherwise you can try various external libraries for this task. There are four available on Android which can calculate elapsed days in an easy way.
Date4J (main advantage: very small but else limited features)
Threeten-ABP (uses backport of Java-8)
Joda-Time-Android (based on Joda-Time)
Time4A (my own library for Android)
I need some help or a pointer in the right direction.
I am trying to get the difference between 2 times. I am in UK on GMT with timezone set to adjust for daylight saving automatically.
When I preform the following it is always 1 hour out unless, I switch off automatically adjust for daylight saving.
String strDate = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date().getTime() - oldDate.getTime());
If I run the following there is not the 1 hour difference the 2.
System.out.println("Current time " + Formats.HOURMIN.formatValue(new Date().getTime()));
System.out.println("Old time " + Formats.HOURMIN.formatValue(oldDate.getTime()));
Any assistance would be appreciated.
The cardinal rule for calculating time intervals when different timezones are involved is to make sure to convert the times to UTC before subtracting.
Each time, no matter what zone and DST offset is in effect at the time (pun somewhat intended), converts to a unique UTC instant. Once you have the times in UTC, calculating the difference is a simple subtraction. The result is time-zone-independent.
The java.util.Date class has no time zone attached to it yet confusingly uses your default time zone when rendering a string. I'm guessing this may be your problem. One of many reasons to avoid java.util.Date/Calendar classes.
The Joda-Time 2.3 library makes this kind of work easier. Look at the Period, Duration, and Interval classes.
In contrast to a java.util.Date, in Joda-Time a DateTime instance does indeed know its assigned time zone.
The ISO 8601 standard defines a way to describe durations as hours, minutes, and such in a PnYnMnDTnHnMnS format. I use that in my example code below. Joda-Time offers other ways as well.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
DateTimeZone timeZone = DateTimeZone.forID( "Europe/London" );
DateTime dateTimeNew = new DateTime( timeZone );
DateTime dateTimeOld = dateTimeNew.minusHours( 2 );
Period period = new Period( dateTimeOld, dateTimeNew );
Dump to console…
System.out.println( "dateTimeNew: " + dateTimeNew );
System.out.println( "dateTimeOld: " + dateTimeOld );
System.out.println( "period: " + period );
When run…
dateTimeNew: 2014-01-02T23:19:45.021Z
dateTimeOld: 2014-01-02T21:19:45.021Z
period: PT2H
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.
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.