I have a database in which I have users with their info etc. One field is named "maeindat" and there is stored the date of the entry (creation) of that entitiy ( user )
Now I want to compare if current time is "smaller" than input date and if it is set current date into the field, but if date of entry is bigger than current date set date of entry into the field
current date < date of entry --> set current date into the field
current date > date of entry --> set date of entry in field
Bellow is the code I'm trying out...
String maeindat = rs.getString("MAEINDAT");
LocalDateTime currTime = LocalDateTime.now();
if(currTime.isBefore(maeindat)) {
currTime = maeindat;
}
else if(currTime.isAfter(maeindat)) {
maeindat = maeindat;
}
UPDATE:
String maeindat = rs.getString("MAEINDAT");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYYMMDDHH24MI");
LocalDateTime maeindatDate = LocalDateTime.parse(maeindat, formatter);
LocalDateTime currTime = LocalDateTime.now();
if(currTime.isBefore(maeindatDate)) {
currTime = maeindatDate;
}
else if (currTime.isAfter(maeindatDate)) {
maeindatDate = maeindatDate;
}
tl;dr
Comparing a LocalDateTime with current moment makes no sense logically.
myResultSet.getObject(
… ,
Instant.class // Retrieve from database column of type similar to SQL-standard `TIMESTAMP WITH TIME ZONE`.
).isBefore( Instant.now() ) // Or `isAfter` or `equals` or combine with `!` (meaning NOT before/after).
Apples & Oranges
You cannot compare strings to date-time objects. Parse your strings into date-time objects, and then you may compare.
LocalDateTime
The LocalDateTime class lacks any concept of time zone or offset-from-UTC. Use this class only if using a column in your database of a type similar to SQL-standard TIMESTAMP WITHOUT TIME ZONE.
This type is not intended to represent actual moments, specific points on the timeline. Instead this type is only a rough idea of potential moments spread over a range of about 26-27 hours.
If we say "Santa delivers the toys just after midnight on December 25th", do we mean just after midnight in Auckland, New Zealand or do we mean midnight in Kolkata India which occurs hours later? Or Paris France even more hours later? "Midnight" has no real meaning until you specify Auckland, Kolkata, or Paris.
Comparing a LocalDateTime to the current moment makes no sense! The LocalDateTime has no real meaning without the context of a time zone or offset. If you know for certain of an appropriate time zone for that value, apply a ZoneId to get a ZonedDateTime. At that point, you have an actual moment, a point on the timeline.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = myLocalDateTime.atZone( z ) ; // Converting vague idea about potential moments into an actual moment, a specific point on the timeline.
Instant
If you intend to represent actual moments, use SQL-standard type TIMESTAMP WITH TIME ZONE and Java type Instant (UTC) or possibly ZonedDateTime.
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 instant = myResultSet.getObject( … , Instant.class ) ;
Capture the current moment in UTC.
Instant instantNow = Instant.now() ; // Current moment in UTC.
Compare using isBefore, isAfter, equals.
boolean targetPassed = instant.isAfter( instantNow ) ;
Smart objects, not dumb strings.
With a JDBC driver complying with JDBC 4.2 and later, you may directly exchange java.time objects with your database. No need for converting to/from strings.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ; // For database column of type like `TIMESTAMP WITHOUT TIME ZONE`.
Or…
Instant instant = myResultSet.getObject( … , Instant.class ) ; // For database column of type like `TIMESTAMP WITH TIME ZONE`.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, 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, 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.
Related
java.sql.Date date = java.sql.Date.valueOf("1900-01-01");
//-2209017600000
System.out.println(date.getTime());
java.sql.Timestamp timestamp = new Timestamp(date.getTime());
System.out.println(timestamp);
if directly running in unit test, the result will be 1900-01-01 00:00:00.0
if running with debug in unit test, the result will be 1970-01-01 07:30:00.0
How does it output 1900-01-01 00:00:00.0? Where is it stored?
Why not output 1970-01-01 00:00:00.0 ? becase I saw the comment of Timestamp constructor says milliseconds since January 1, 1970, 00:00:00 GMT. A negative number is the number of milliseconds before January 1, 1970, 00:00:00 GMT.
tl;dr
Avoid the terrible old date-time classes. Use java.time. Poof, all the bizarre behavior you are seeing is gone, and your question is moot.
LocalDate // A class to represent a date-only value, without time-of-day, without time zone. Replaces `java.sql.Date` which only pretends to be date-only but actually has both a time-of-day and a time zone.
.parse( "1900-01-01" ) // Standard ISO 8601 formatted strings are parsed directly by the *java.time* classes.
.atStartOfDay( // Let java.time determine the first moment of a day.
ZoneId.of( "Pacific/Auckland" )
) // Returns a `ZonedDateTime` object.
.toString() // Generates a `String` with text in standard ISO 8601 format, wisely extended by appending the name of the time zone in square brackets.
1900-01-01T00:00+11:30[Pacific/Auckland]
You are torturing yourself with these Questions about the legacy date-time classes. Sun, Oracle, and the JCP community all gave up on those classes years ago when adopting JSR 310. I suggest you do the same.
Never use java.sql.Date
This class is part of the terrible old date-time classes that were supplanted years ago by java.time classes. This java.sql.Date in particular is especially badly designed. It extends java.util.Date while the documentation tells us to ignore the fact of that inheritance. As a subclass, it pretends to be a date-only value but actually has a time-of-day inherited from the other Date, which in turn is misnamed having both a date and a time-of-day. In addition, a time zone lurks deep within these classes, though inaccessible without any getter or setter method. Confusing? Yes, an awful mess. Never use java.sql.Date.
Instead, use java.time.LocalDate.
LocalDate ld = LocalDate.parse( "1900-01-01" ) ;
ld.toString(): 1900-01-01
Never use java.sql.Timestamp
As with java.sql.Date, the java.sql.Timestamp class was replaced years ago. Use java.time.Instant. If handed a Timestamp, immediately convert using the new conversion methods added to the old classes.
If you want the first moment of the day for a particular date, let LocalDate determine that. The first moment is not always 00:00:00, so never assume that. Specify the time zone of the region whose people use the particular wall-clock time you care about.
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 as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;
To see the same moment in UTC, extract a Instant. 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 instant = zdt.toInstant() ;
If you wanted the first moment of the day in UTC, use OffsetDateTime.
OffsetDateTime odt = ld.atOffset( ZoneOffset.UTC ) ;
Conversion
If you must interoperate with old code not yet updated to java.time classes, you can convert back-and-forth. Call new methods added to the old classes.
java.sql.Timestamp ts = Timestamp.from( instant ) ;
…and…
Instant instant = ts.toInstant() ;
Ditto for date.
java.sql.Date d = java.sql.Date.valueOf( ld ) ;
…and…
LocalDate ld = d.toLocalDate() ;
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, Java SE 11, and later - 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
Most 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.
I have a timestamp in epoch milliseconds and I want to check if it is between two LocalDateTime stamps. What's the best way to do this in java?
One way to do it is to convert the milliseconds to LocalDateTime
LocalDateTime date = Instant.ofEpochMilli(milliseconds)
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
LocalDateTime start = LocalDateTime.now().minusMinutes(1);
LocalDateTime end = LocalDateTime.now().plusMinutes(1);
if (date.isAfter(start) && date.isBefore(end)) {
// date is between start and end
}
tl;dr
You cannot compare a LocalDateTime to a moment until assigning a time zone (or offset-from-UTC).
org.threeten.extra.Interval // Represents a span-of-time attached to the timeline, as a pair of `Instant` objects, a pair of moments in UTC.
.of (
myLocalDateTimeStart
.atZone( ZoneId.of( "Pacific/Auckland" ) ) // Determine a moment by assigning an time zone to a `LocalDateTime` to produce a `ZonedDateTime`, from which we extract an `Instant` to adjust into UTC.
.toInstant() ,
myLocalDateTimeStop
.atZone( ZoneId.of( "Pacific/Auckland" ) ) // Returns a `ZonedDateTime` object.
.toInstant() // From the `ZonedDateTime`, extract a `Instant` object.
) // Returns `Interval` object.
.contains(
Instant.ofEpochMilli( 1_532_463_173_752L ) // Parse a count of milliseconds since 1970-01-01T00:00:00Z as a moment in UTC, a `Instant` object.
) // Returns a boolean.
Details
Comparing time in java between epoch milliseconds and LocalDateTime
You cannot. That comparison is illogical.
A LocalDateTime does not represent a moment, is not a point on the timeline. A LocalDateTime represents potential moments along a range of about 26-27 hours, the range of time zones around the world.
As such it has no real meaning until you place it in the context of a time zone. If that particular date and time were invalid in that zone, such as during a Daylight Saving Time (DST) cut-over, or during some other such anomaly, the ZonedDateTime class adjusts.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = myLocalDateTime.atZone( z ) ;
For comparisons, we will adjust into UTC by extracting an Instant object from your start and stop ZonedDateTime objects.
Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;
Now parse your count of milliseconds since the epoch reference of first moment of 1970 as a Instant. Instant has an even finer resolution, nanoseconds.
Instant instant = Instant.ofEpochMilli( 1_532_463_173_752L ) ;
Compare to see if your epoch-milliseconds represent a moment in between our stop and start Instant objects. Usually in date-time work, the Half-Open approach is best, where the beginning is inclusive while the ending is exclusive.
Tip: A shorter way of saying “is equal to or is after” is to say “is not before”.
boolean inRange = ( ! instant.isBefore( start ) ) && instant.isBefore( stop ) ;
To make this work easier, add the ThreeTen-Extra library to your project. Use the Interval class.
Interval interval = Interval.of( start , stop ) ;
boolean inRange = interval.contains( instant ) ; // Uses Half-Open approach to comparisons.
Tip: If you had intended to be tracking moments, you should not have been using LocalDateTime class at all. Instead, use the Instant, OffsetDateTime, and ZonedDateTime classes.
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.
When comparing an Instant (time-since-Epoch) with a LocalDateTime, you always need to consider the timezone of the local times. Here's an example:
Instant now = Instant.now();
LocalDateTime start = LocalDateTime.of(2018, 7, 24, 0, 0);
LocalDateTime end = LocalDateTime.of(2018, 7, 24, 23, 59);
final ZoneId myLocalZone = ZoneId.of("Europe/Paris");
if (now.isAfter(start.atZone(myLocalZone).toInstant())
&& now.isBefore(end.atZone(myLocalZone).toInstant())) {
// the instant is between the local date-times
}
I have a timestamp encoded as a String—for example, "2012-02-12T09:08:13.123456-0400", coming from an Oracle database.
The only way that I can think of reading this timestamp, is by using Timestamp.valueOf(), and that requires a format of yyyy-[m]m-[d]d hh:mm:ss[.f...]
I am convinced that this is the only way to read time without losing precision because other ways do not support nanosecond precision included in the example above (".123456").
With that in mind, I can simply trim the needed values, to fit the required format. Hence, the original string would be transformed:
Before: "2012-02-12T09:08:13.123456-0400"
After: "2012-02-12 09:08:13.123456"
If I do this, I remove the "-0400" timezone offset. This comes as a red flag to me, until I saw this post. One of the proposed answers states,
I think the correct answer should be java.sql.Timestamp is NOT timezone specific. Timestamp is a composite of java.util.Date and a separate nanoseconds value. There is no timezone information in this class. Thus just as Date this class simply holds the number of milliseconds since January 1, 1970, 00:00:00 GMT + nanos.
To prove to myself that the offset is not needed, I wrote a simple integration test.
Insert this timestamp into the database: "2015-09-08 11:11:12.123457". Read the database using Java, and print out the details. I get "2015-09-08 11:11:12.123457", which is the same value. This happens to be ok, since my JVM and the Oracle DB are running on the same machine.
Is it a fact that a timezone is not factor in java.sql.Timestamp?
Is there a better way to read that entire timestamp, without losing any precision in Java 7?
tl;dr
org.threeten.bp.OffsetDateTime odt =
OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
org.threeten.bp.format.DateTimeFormatter.ofPattern( "yyyy-MM-dd'T'HH:mm:ssZ" ) // Specify pattern as workaround for Java 8 bug in failing to parse if optional colon is not present.
)
;
Using java.time
Rather than receiving a String from your database, you should retrieve an object, a date-time object, specifically a java.time object.
The java.time classes supplant the troublesome old date-time classes including java.sql.Timestamp. If your JDBC driver supports JDBC 4.2 and later, you can pass and receive java.time objects directly.
Instant
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). So this is equivalent to java.sql.Timestamp including support for the six digits of microseconds of your input data, so no precision lost per the requirements of your Question.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
instant.toString(): 2012-02-12T13:08:13.123456Z
ZonedDateTime
If you want to see that same moment through the lens of a particular region's wall-clock time, apply a ZoneId to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "America/St_Thomas" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2012-02-12T09:08:13.123456-04:00[America/St_Thomas]
OffsetDateTime
As for your direct Question of how to make sense of the string 2012-02-12T09:08:13.123456-0400 as a date-time value, parse as an OffsetDateTime.
A time zone has a name in the format of continent/region, and represents a history of past, present, and future changes to a region’s offset caused by anomalies such as Daylight Saving Time (DST). We have clue as to the time zone with your string, so we use OffsetDateTime rather than ZonedDateTime.
OffsetDateTime odt = OffsetDateTime.parse( "2012-02-12T09:08:13.123456-0400" ) ;
Well, that line of code above should have worked, but in Java 8 there is a small bug in parsing the offset lacking the optional COLON character between the hours and minutes. So -04:00 in Java 8 will parse but not -0400. Bug fixed in Java 9. Your String is indeed compliant with the ISO 8601 standard for date-time formats used by default in the java.time classes. Tip: Generally best to always format your offsets with the colon, and both hours/minutes and with a padding zero – I've seen other protocols and libraries expect only such full format.
Until you move to Java 9, specify the formatting pattern explicitly rather than rely on the implicit default pattern, as a workaround for this bug.
OffsetDateTime odt =
OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
DateTimeFormatter.ofPattern( "yyyy-MM-dd'T'HH:mm:ssZ" ) // Specify pattern as workaround for Java 8 bug in failing to parse if optional colon is not present.
)
;
Converting
If your JDBC driver is not yet compliant with JDBC 4.2, retrieve a java.sql.Timestamp object, for use only briefly. Immediately convert to java.time using new methods added to the old date-time classes.
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
Instant instant = ts.toInstant();
Proceed to do your business logic in java.time classes. To send a date-time back to the database convert from Instant to java.sql.Timestamp.
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) ) ;
Java 6 & 7
In Java 6 & 7, the above concepts still apply, but java.time is not built-in. Use the ThreeTen-Backport library instead. To obtain, see bullets below.
In Java 7, you cannot use JDBC 4.2 features. So we cannot directly access java.time objects from the database through the JDBC driver. As seen above, we must convert briefly into java.sql.Timestamp from Instant. Call the utility methods DateTimeUtils.toInstant(Timestamp sqlTimestamp) & DateTimeUtils.toSqlTimestamp(Instant instant).
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
Instant instant = DateTimeUtils.toInstant( ts ) ;
…and…
java.sql.Timestamp ts = DateTimeUtils.toSqlTimestamp( instant ) ;
myPreparedStatement.setTimestamp( … , ts ) ;
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, 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
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
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.
java.sql.Timestamp.valueOf(String) parses the provided time in the current timezone. You can check this by looking at the implementation, which in the end simply calls Timestamp(int year, int month, int date, int hour, int minute, int second, int nano) which calls public Date(int year, int month, int date, int hrs, int min, int sec), which says (emphasis mine):
Allocates a Date object and initializes it so that it represents the instant at the start of the second specified by the year, month, date, hrs, min, and sec arguments, in the local time zone.
It is true that Timestamp doesn't have time zone information (it is just a wrapper with number of seconds since the GMT epoch + nanoseconds), but when loading or storing a Timestamp, JDBC will use the local (default) timezone, unless explicitly declared otherwise.
This means that a Timestamp at 10:00 in your local timezone will end up in the database as an SQL TIMESTAMP at 10:00, and not at - for example - 08:00 if your timezone is 2 hours ahead of GMT; and the reverse when loading.
You are correct that java.sql.Timestamp has no timezone information. Under the covers it is just an instant that is milliseconds since the epoch and the epoch itself is defined with essentially a 0 offset, January 1, 1970, 00:00:00 GMT.
That being said, when working with times, offset always matters and this will lead you into the hell, er, "dynamic world" that is ISO-8601 in Java 8 java.time. The offset matters a lot, unless you are standing in Greenwich, England. If you try to just ignore it you may sometimes guess the day wrong; it is Monday in Greenwich 8 hours earlier than it is Monday in Seattle, for example. I don't think Java8 has a built in DateTimeFormatter for the -0000 variants of ISO-8601, but if you are sure your format is "stable", this would work.
public void java8TimeWTF() {
OffsetDateTime odt = OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nZ"));
Instant i = odt.toInstant();
System.out.printf("odt: %s, i: %s\n", odt, i);
}
Outputs odt: 2012-02-12T09:08:13.000123456-04:00, i: 2012-02-12T13:08:13.000123456Z
Here's what we had to do to deal with all the variant's of ISO-8601 coming out of our clients
import org.testng.annotations.Test;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import static org.testng.Assert.assertEquals;
public class Java8Time8601 {
private final long EXPECTED_MILLIS = 1493397412000L;
public Instant iso8601ToInstant(String s) {
DateTimeFormatter[] dateTimeFormatters = {
DateTimeFormatter.ISO_INSTANT,
DateTimeFormatter.ISO_OFFSET_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")
};
for (DateTimeFormatter dtf : dateTimeFormatters) {
try {
OffsetDateTime odt = OffsetDateTime.parse(s, dtf);
Instant i = odt.toInstant();
return i;
} catch (DateTimeParseException dtpe) {
;
}
}
throw new IllegalArgumentException(String.format("failed to parse %s", s));
}
#Test
public void testInstantParse8601_Z() throws Exception {
String[] candidates = {
"2017-04-28T16:36:52.000Z",
"2017-04-28T16:36:52.00Z",
"2017-04-28T16:36:52.0Z",
"2017-04-28T16:36:52Z",
"2017-04-28T16:36:52+00:00",
"2017-04-28T16:36:52-00:00",
"2017-04-28T09:36:52-07:00",
"2017-04-28T09:36:52-0700",
};
for (String candidate : candidates) {
Instant i = iso8601ToInstant(candidate);
assertEquals(i.toEpochMilli(), EXPECTED_MILLIS, String.format("failed candidate %s", candidate));
System.out.println(i.toString());
}
}
}
There has got to be a better way.
I have a java application in which I would like the time in UTC. Currently, the code uses a mix of java.util.Date and java.sql.Timestamp. To get the time in UTC, the programmer before me used:
For Date:
Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();
For Timestamp:
Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
However I have run multiple tests myself with this code and both of these lines return the current date/time(in my current timezone). From everything I have read it appears that Date/Timestamp does not have a zoneOffset value, but I cannot find a concrete statement of this.
Is there anyway to keep the timeZone (UTC) within the Date or Timestamp objects, or do I need to do some refactoring and use the actual ZonedDateTime object throughout my application? Also will this ZonedDateTime object be compatible with the current Timestamp object for sql?
Example:
public static void main (String args[])
{
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
Date date = Date.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
System.out.println("ZonedDateTime: " + zonedDateTime);
System.out.println("Timestamp: " + timestamp);
System.out.println("Date: " + date);
}
Output:
ZonedDateTime: 2017-04-06T15:46:33.099Z
Timestamp: 2017-04-06 10:46:33.109
Date: Thu Apr 06 10:46:33 CDT 2017
tl;dr
Instant.now() // Capture the current moment in UTC with a resolution up to nanoseconds.
Use only java.time classes. Avoid the troublesome old legacy date-time classes added before Java 8.
Using java.time
The programmer before you was making use of the new modern java.time classes that now supplant the notoriously troublesome old legacy date-time classes such as Date, Calendar, Timestamp.
Instant
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). To get the current moment in UTC is utterly simple: Instant.now.
Instant instant = Instant.now();
Converting
You should stick to the java.time classes, and avoid the legacy classes. But if absolutely necessary such as interfacing with old code not yet updated for java.time, you may convert to/from java.time. Look to new methods on old classes. The legacy class java.util.Date equivalent is Instant.
java.util.Date d = java.util.Date.from( myInstant); // To legacy from modern.
Instant instant = myJavaUtilDate.toInstant(); // To modern from legacy.
JDBC
Avoid the legacy date-time classes. Use java.time classes instead.
Your JDBC 4.2 compliant driver may be able to directly address java.time types by calling PreparedStatement::setObject and ResultSet::getObject.
myPreparedStatement.setObject( … , instant ) ;
… and …
Instant instant = myResultSet.getObject( … , Instant.class ) ;
If not, fall back to using the java.sql types, but as briefly as possible. Use new conversion methods added to the old classes.
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) ) ;
… and …
Instant instant = myResultSet.getTimestamp( … ).toInstant() ;
No need for ZonedDateTime
Notice that we had no need for your mentioned ZonedDateTime as you said you were only interested in UTC. The Instant objects are always in UTC. That means that original code you quoted:
Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();
…could have simply been shortened to:
Date.from( Instant.now() ) ;
Note that java.util.Date is always in UTC as well. However, its toString unfortunately applies the JVM’ current default time zone implicitly while generating the String. This anti-feature creates no end of confusion as you can see by searching on Stack Overflow.
If you want to see your Instant object’s UTC value through the lens of a region’s wall-clock time, assign a time zone ZoneId to get a ZoneDateTime.
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 CDT or EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Chicago" );
ZonedDateTime zdt = instant.atZone( z );
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, Java SE 11, and later - 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.
In Java, Date represents a point in time. It's not related to timestamp. When you call toString() method of a Date object, it converts that time to Platform's default Timestamp, e.g. Following will print date/time in UTC (as it sets default timezone to UTC):
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
Date date = Date.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
System.out.println("ZonedDateTime: " + zonedDateTime);
System.out.println("Timestamp: " + timestamp);
System.out.println("Date: " + date);
I am using JodaTime 1.6.2.
I have a LocalDate that I need to convert to either a (Joda) LocalDateTime, or a java.sqlTimestamp for ormapping.
The reason for this is I have figured out how to convert between a LocalDateTime and a java.sql.Timestamp:
LocalDateTime ldt = new LocalDateTime();
DateTimeFormatter dtf = DateTimeFormatter.forPattern("yyyy-MM-dd HH:mm:ss");
Timestamp ts = Timestamp.valueOf(ldt.toString(dtf));
So, if I can just convert between LocalDate and LocalDateTime, then I can make the continued conversion to java.sql.Timestamp. Thanks for any nudges in the right direction!
JodaTime
To convert JodaTime's org.joda.time.LocalDate to java.sql.Timestamp, just do
Timestamp timestamp = new Timestamp(localDate.toDateTimeAtStartOfDay().getMillis());
To convert JodaTime's org.joda.time.LocalDateTime to java.sql.Timestamp, just do
Timestamp timestamp = new Timestamp(localDateTime.toDateTime().getMillis());
JavaTime
To convert Java8's java.time.LocalDate to java.sql.Timestamp, just do
Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay());
To convert Java8's java.time.LocalDateTime to java.sql.Timestamp, just do
Timestamp timestamp = Timestamp.valueOf(localDateTime);
The best way use Java 8 time API:
LocalDateTime ldt = timeStamp.toLocalDateTime();
Timestamp ts = Timestamp.valueOf(ldt);
For use with JPA put in with your model (https://weblogs.java.net/blog/montanajava/archive/2014/06/17/using-java-8-datetime-classes-jpa):
#Converter(autoApply = true)
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
#Override
public Timestamp convertToDatabaseColumn(LocalDateTime ldt) {
return Timestamp.valueOf(ldt);
}
#Override
public LocalDateTime convertToEntityAttribute(Timestamp ts) {
return ts.toLocalDateTime();
}
}
So now it is relative timezone independent time.
Additionally it is easy do:
LocalDate ld = ldt.toLocalDate();
LocalTime lt = ldt.toLocalTime();
Formatting:
DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
String str = ldt.format(DATE_TME_FORMATTER);
ldt = LocalDateTime.parse(str, DATE_TME_FORMATTER);
UPDATE: postgres 9.4.1208, HSQLDB 2.4.0 etc understand Java 8 Time API without any conversations!
tl;dr
The Joda-Time project is in maintenance-mode, now supplanted by java.time classes.
Just use java.time.Instant class.
No need for:
LocalDateTime
java.sql.Timestamp
Strings
Capture current moment in UTC.
Instant.now()
To store that moment in database:
myPreparedStatement.setObject( … , Instant.now() ) // Writes an `Instant` to database.
To retrieve that moment from datbase:
myResultSet.getObject( … , Instant.class ) // Instantiates a `Instant`
To adjust the wall-clock time to that of a particular time zone.
instant.atZone( z ) // Instantiates a `ZonedDateTime`
LocalDateTime is the wrong class
Other Answers are correct, but they fail to point out that LocalDateTime is the wrong class for your purpose.
In both java.time and Joda-Time, a LocalDateTime purposely lacks any concept of time zone or offset-from-UTC. As such, it does not represent a moment, and is not a point on the timeline. A LocalDateTime represents a rough idea about potential moments along a range of about 26-27 hours.
Use a LocalDateTime for either when the zone/offset is unknown (not a good situation), or when the zone-offset is indeterminate. For example, “Christmas starts at first moment of December 25, 2018” would be represented as a LocalDateTime.
Use a ZonedDateTime to represent a moment in a particular time zone. For example, Christmas starting in any particular zone such as Pacific/Auckland or America/Montreal would be represented with a ZonedDateTime object.
For a moment always in UTC, use Instant.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
Apply a time zone. Same moment, same point on the timeline, but viewed with a different wall-clock time.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, different wall-clock time.
So, if I can just convert between LocalDate and LocalDateTime,
No, wrong strategy. If you have a date-only value, and you want a date-time value, you must specify a time-of-day. That time-of-day may not be valid on that date for a particular zone – in which case ZonedDateTime class automatically adjusts the time-of-day as needed.
LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 14 , 0 ) ; // 14:00 = 2 PM.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
If you want the first moment of the day as your time-of-day, let java.time determine that moment. Do not assume the day starts at 00:00:00. Anomalies such as Daylight Saving Time (DST) mean the day may start at another time such as 01:00:00.
ZonedDateTime zdt = ld.atStartOfDay( z ) ;
java.sql.Timestamp is the wrong class
The java.sql.Timestamp is part of the troublesome old date-time classes that are now legacy, supplanted entirely by the java.time classes. That class was used to represent a moment in UTC with a resolution of nanoseconds. That purpose is now served with java.time.Instant.
JDBC 4.2 with getObject/setObject
As of JDBC 4.2 and later, your JDBC driver can directly exchange java.time objects with the database by calling:
PreparedStatement::setObject
ResultSet::getObject
For example:
myPreparedStatement.setObject( … , instant ) ;
… and …
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Convert legacy ⬌ modern
If you must interface with old code not yet updated to java.time, convert back and forth using new methods added to the old classes.
Instant instant = myJavaSqlTimestamp.toInstant() ; // Going from legacy class to modern class.
…and…
java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from( instant ) ; // Going from modern class to legacy class.
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, 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.
function call asStartOfDay() on java.time.LocalDate object returns a java.time.LocalDateTime object
Depending on your timezone, you may lose a few minutes (1650-01-01 00:00:00 becomes 1649-12-31 23:52:58)
Use the following code to avoid that
new Timestamp(localDateTime.getYear() - 1900, localDateTime.getMonthOfYear() - 1, localDateTime.getDayOfMonth(), localDateTime.getHourOfDay(), localDateTime.getMinuteOfHour(), localDateTime.getSecondOfMinute(), fractional);
Since Joda is getting faded, someone might want to convert LocaltDate to LocalDateTime in Java 8. In Java 8 LocalDateTime it will give a way to create a LocalDateTime instance using a LocalDate and LocalTime. Check here.
public static LocalDateTime of(LocalDate date,
LocalTime time)
Sample would be,
// just to create a sample LocalDate
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate ld = LocalDate.parse("20180306", dtf);
// convert ld into a LocalDateTime
// We need to specify the LocalTime component here as well, it can be any accepted value
LocalDateTime ldt = LocalDateTime.of(ld, LocalTime.of(0,0)); // 2018-03-06T00:00
Just for reference, For getting the epoch seconds below can be used,
ZoneId zoneId = ZoneId.systemDefault();
long epoch = ldt.atZone(zoneId).toEpochSecond();
// If you only care about UTC
long epochUTC = ldt.toEpochSecond(ZoneOffset.UTC);
Java8 +
import java.time.Instant;
Instant.now().getEpochSecond(); //timestamp in seconds format (int)
Instant.now().toEpochMilli(); // timestamp in milliseconds format (long)