Java Date constructor unexpected behaviour - java

I am just providing a value of 2160000000 (which is 1000 * 60 * 60 * 24 * 25 - just 25 days) to Date's class constructor. I expected to see that here will be 1970-01-26 00:00:00, but what I received is 1970-01-26 03:00:00 (additional three hours)! I haven't found any points that this constructor also depend on JVM locale settings, and all I have found is info about leap second. But leap second is NOT three hours in bounds of the single month of the same year. But anyway I've changed default locale (to US one. I'm located in Europe) in a test method just for experiment, but nothing changed.
I have received this just by this (what I have explained just ok earlier ya know):
Date date = new Date(1000* 60 * 60 * 24 * 25);
(this is just for example purposes). I saw actual values just using debugger, that's all:

You are getting the Date you expected, a Date of 1970-01-26 00:00:00 UTC. This point in time is equivalent to 1970-01-26 03:00:00 at UTC offset +03:00.
In your debugger you are looking into the private fields of the Date object. These are not documented for clients (that’s the point), so don’t expect any particular values.
I believe that you would find Instant.ofEpochMilli(1000L * 60 * 60 * 24 * 25) less confusing. Or still better, Instant.EPOCH.plus(Duration.ofDays(25)). java.time, the modern Java date and time API, is much nicer to work with. If you do need a Date for a legacy API that you don’t want to change just now, I recommend getting an Instant first and then using Date.from(yourInstant) so you minimize your use of (and dependence on) the outdated and confusing Date class.
Finally, changing locale makes no difference. While time zone and UTC offset are closely connected (to a degree where some think it’s the same :-) locale hasn’t really got anything to do with them. Instead the locale deals with the language and cultural norms of a group of users — it doesn’t even need to be tied to a geographical location.
Link: All about java.util.Date

Do you think the hour difference you're seeing is being equal to your home country's time zone (GMT+3) is a coincidence? I think not.
SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = dateFormat.parse("/*TimeToParse*/");
This would definitely help.
Edit: If you check the zoneOffset and ZoneInfo values in your debug screenshot, you'll understand better.

tl;dr
Instant.ofEpochMilli( 2_160_000_000L )
java.time
The Answer by Acar is likely correct: You are confused by the unfortunate design of Date::toString to dynamically apply your JVM’s current default time zone while generating a string. One of many reasons to never use the troublesome Date class, now supplanted by the java.time classes.
To represent a moment on the timeline in UTC with a resolution of nanoseconds, use Instant.
Instant instant = Instant.ofEpochMilli( 2_160_000_000L ) ;
If your real intent is to represent 25 whole days as a span of time unattached to the timeline, use a Period.
LocalDate today = LocalDate.now( ZoneId.of( “Africa/Tunis” ) ) ;
Period p = Period.ofDays( 25 ) ;
LocalDate later = today.plus( p ) ;

Related

Java.sql.date storing previous date instead of given date

I am trying to store 2019-07-27 in sql DB but it stores 2019-07-26. Can anyone help me in this.
I am using Java.sql.Date here. I also tried with Java.util.Date and Java.sql.Timestamp, all gives same result.
Time zones, and wrong class
You failed to provide enough info for a definite answer.
But I suspect your issue is due to time zones. The java.sql.Date class is a terrible hack, pretending to represent a date-only but actually hiding a time-of-day and time zone too. Never use this class.
You are using terrible date-time classes that were supplanted years ago with the adoption of JSR 310. Use only classes from the java.time package.
If you want to store a date-only, use a column with a data type akin to the SQL-standard type DATE.
In Java, use LocalDate with JDBC 4.2 or later. This class has only a date, without time-of-day and without time zone.
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
To write to the database:
LocalDate ld = LocalDate.of( 2019 , 1 , 23 ) ;
…
myPreparedStatement.setObject( … , ld ) ;
To capture the current date, specify your desired/expected time zone. For any given moment, the date varies around the globe by time zone.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
LocalDate ld = LocalDate.now( z ) ;
Have a look at the time zone of your JVM and your database. And have a look at the documentation on the method(s) you use to create your java.sql.Date objects.
The JavaDoc for the constructor java.sql.Date(long date) e.g. states (emphasis mine):
Constructs a Date object using the given milliseconds time value. If
the given milliseconds value contains time information, the driver
will set the time components to the time in the default time zone (the
time zone of the Java virtual machine running the application) that
corresponds to zero GMT.
In other words, if you set the time to midnight in your time zone, the constructor will set it to midnight GMT with the same date. But midnight GMT might be another day in your time zone.
That's the best answer I can give without seeing any code and any info about the db used...
Please add more info about the solution for the next person finding your question if my answer helped or give us some code if my answer doesn't lead you to a solution.
The answer on Question 14693148: JPA TemporalType.Date giving wrong date is a bit more elaborate and recommends using GMT/UTC everywhere.
The second answer on Question 21174634: JDBC ResultSet: I need a getDateTime, but there is only getDate and getTimeStamp recommends using the newer date/time classes when reading via JDBC. This might also be applicable to writing.
There are two chances :
If your DB and APP server are in different time zones try Adjusting the time of the day based on the Time difference.
This happens with LEAP years. In this case save the date with time as 12:00 instead of 0:00.
long hours = 12L * 60L * 60L * 1000L;
Date d = new Date(d1.getTime() + hours);

Java ZonedDateTime.toInstant() behavior

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”.

Number of days between two epoch days in scala

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.

How to check if 2 dates are on the same day in Java

I have 2 Date variables, Date1 and Date2.
I want to check if Date 1 fall on the same date as Date2 (but they are allowed to have different times).
How do i do this?
It looks like a really easy thing to do, but i'm struggling.
EDIT: I want to avoid external libraries and stuff
EDIT:
My orgional idea was to remove the hour, min, sec but those features are marked as depreciated in Java. So what should I use????
Although given answers based on date component parts of a java.util.Date are sufficient in many parts, I would stress the point that a java.util.Date is NOT a date but a kind of UNIX-timestamp measured in milliseconds. What is the consequence of that?
Date-only comparisons of Date-timestamps will depend on the time zone of the context. For example in UTC time zone the date-only comparison is straight-forward and will finally just compare year, month and day component, see other answers (I don't need to repeat).
But consider for example the case of Western Samoa crossing the international dateline in 2011. You can have valid timestamps of type java.util.Date, but if you consider their date parts in Samoa you can even get an invalid date (2011-12-30 never existed in Samoa locally) so a comparison of just the date part can fail. Furthermore, depending on the time zone the date component can generally differ from local date in UTC zone by one day, ahead or behind, in worst case there are even two days difference.
So following extension of solution is slightly more precise:
SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
fmt.setTimeZone(...); // your time zone
return fmt.format(date1).equals(fmt.format(date2));
Similar extension also exists for the more programmatic approach to first convert the j.u.Date-timestamp into a java.util.GregorianCalendar, then setting the time zone and then compare the date components.
Why don't you simply compare the year, month and day? You can write your method for doing it something like:
private boolean isDateSame(Calendar c1, Calendar c2) {
return (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) &&
c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH) &&
c1.get(Calendar.DAY_OF_MONTH) == c2.get(Calendar.DAY_OF_MONTH));
}
Today = Span Of Time
While the other answers may be correct, I prefer the approach where we recognize that "today" is actually a span of time.
Because of anomalies such as Daylight Saving Time (DST), days vary in length, not always 24 hours long. Here in the United States, some days are 23 hours long, some 25.
Half-Open
Commonly in data-time work, we use the "Half-Open" strategy where the beginning of a span is inclusive and the ending is exclusive. So that means "today" spans from the first moment of today up to, but not including, the first moment of tomorrow.
Time Zones
Time zones are critical, as explained in the correct answer by Meno Hochschild. The first moment of a day depends on its time zone rules.
Joda-Time
The Joda-Time library has nice classes for handling spans of time: Period, Duration, and Interval.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime now = new DateTime( timeZone );
Interval today = new Interval( now.withTimeAtStartOfDay(), now.plusDays(1).withTimeAtStartOfDay() );
DateTime dateTimeInQuestion = new DateTime( date ); // Convert java.util.Date.
boolean happensToday = today.contains( dateTimeInQuestion );
Benefits
This approach using a span of time has multiple benefits:
Avoids Daylight Saving Time (DST) issues
Lets you compare date-time values from other time zones
Flexible, so you can use the same kind of code for other spans (multiple days, months, etc.)
Gets your mind shifted away from calendar dates (a layered abstraction) and onto date-times as points on a flowing timeline (the underlying truth).
Java 8 has a new java.time package built-in. These new classes are modeled after Joda-Time but are entirely re-architected. This same kind of code can be written using java.time.
When you use the toString() method what do you get? Is it only the year/month/day or time too? If it is then you could simply compare the strings of the two objects. (date1.toString().equals(date2.toString()));

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