Java Spring MySQL String Timezone column between two milliseconds - java

I got a stored Timezone date as String on a MySQL Column with the next format:
2018-07-23T20:54:37.242Z --> start_date
What I want to do is a Between two milliseconds(or dates) like this:
SELECT * FROM activity_entity WHERE start_date BETWEEN 1532322000000 AND 1532408399000
Else, I'm using Java Spring Repository as backend where I send the parameters like this:
Date since = new Date(accessRepPOSTInDto.getSince()); //1532322000000 gives Mon Jul 23 00:00:00 CDT 2018
Date to = new Date(accessRepPOSTInDto.getTo());//1532408399000 gives Mon Jul 23 23:59:59 CDT 2018
#Query(value = "SELECT * FROM activity_entity WHERE start_date BETWEEN :since AND :too , nativeQuery = true)
ActivityEntity findBetweenDates(#Param("since") Date since, #Param("too") Date too);
Doing this returns null;
I thought MySQL can automatically format the two dates and the String column to do the Between but it looks like it doesn't.
Any help will be really grateful. Regards.

In your native query, you need to explicitly cast the value of your varchar column to the proper date/timestamp to be evaluated by the between operator. This is how your native query should look like:
SELECT * FROM activity_entity WHERE STR_TO_DATE(start_date, '%Y-%c-%eT%H:%i:%s.%fZ') BETWEEN :since AND :too

tl;dr
SQL:
SELECT * FROM tbl WHERE event >= ? AND event < ? ; -- Using Half-Open approach where beginning is *inclusive* while the ending is *exclusive*.
Java:
myPreparedStatement.setString( 1 , Instant.ofEpochMilli( 1_532_322_000_000L ).toString() ) ;
myPreparedStatement.setString( 2 , Instant.ofEpochMilli( 1_532_408_399_000L ).toString() ) ;
ISO 8601
2018-07-23T20:54:37.242Z
Text in this format is abiding by the ISO 8601 standard. That standard is the best way to represent date-time values as text. But in a database you should be using a purpose-built data type, defining a column of type akin to the SQL-standard TIMESTAMP WITH TIME ZONE. Search Stack Overflow for much more info.
The java.time classes use ISO 8601 formats by default when parsing/generating strings. So no need to specify a formatting pattern.
Instant instant = Instant.parse( "2018-07-23T20:54:37.242Z" ) ;
Count-from-epoch
You can convert your count of milliseconds since the epoch reference of first moment of 1970 in UTC using the Instant class.
Instant start = Instant.ofEpochMilli( 1_532_322_000_000L ) ;
Instant stop = Instant.ofEpochMilli( 1_532_408_399_000L ) ;
Generate strings in standard ISO 8601 format used in your database column.
String startStr = start.toString() ;
String stopStr = stop.toString() ;
Avoid legacy date-time classes
The old date-time classes that were bundled with the earliest versions of Java are bloody awful. Never use them. They have been supplanted entirely by the java.time classes.
Half-Open
What I want to do is a Between
The BETWEEN command in SQL should generally not be used with date-time values. That command is fully “closed” meaning both the beginning and the ending are inclusive.
Instead, for date-time work, it is generally best to define a span-of-time as Half-Open. In this approach the beginning is inclusive while the ending is exclusive. For example, students dismissed for lunch break from noon to 1 PM are expected back in their seats before the clock strikes 1 and the bell rings. Another example, a week starts on a Monday and runs up to, but does not include, the following Monday.
In SQL code, this means a query uses >=, AND, and <.
SELECT *
FROM tbl
WHERE event >= ?
AND event < ?
;
Since ISO 8601 format with the Z is chronological when sorted alphabetically, you can make this work with your ISO 8601 strings.
myPreparedStatement.setString( 1 , startStr ) ;
myPreparedStatement.setString( 2 , stopStr ) ;
If you had used a TIMESTAMP WITH TIME ZONE column type as discussed above, you would simply pass the Instant objects.
myPreparedStatement.setObject( 1 , start ) ;
myPreparedStatement.setObject( 2 , stop ) ;
If you really must use fully-closed approach, adjust the query operators >=, AND, and <=. Or call BETWEEN.
I am not a Spring user, cannot help you there.
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.

Related

Add some hours/mins to current datetime and get the future datetime

I need to get the get the future timestamp value for a particular time. I will have to add a string value to the current datetime timestamp and get the future timestamp value.
I am fetching current timestamp as below:
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
I have a string value as "02:00:00", so basically I need to add 2 hrs to this time and get the future timestamp value that needs to be inserted.
For example if current timestamp is: 2019-04-29 16:59:21.43
and String is "02:00:00".
I need output as 2019-04-29 18:59:21.43.
Can someone please help
You can do something like this
Instant now = Instant.now();
Duration diff = Duration.between(
LocalTime.MIN,
LocalTime.parse("02:00:00")
);
Instant res = now.plus(diff);
System.out.println("res = " + Timestamp.from(res));
You can use the MySQL function TIMESTAMP to add a given time string to your timestamp value:
TIMESTAMP(expr), TIMESTAMP(expr1,expr2)
With a single argument, this function returns the date or datetime
expression expr as a datetime value. With two arguments, it adds the
time expression expr2 to the date or datetime expression expr1 and
returns the result as a datetime value.
mysql> SELECT TIMESTAMP('2003-12-31 12:00:00','12:00:00');
-> '2004-01-01 00:00:00'
Reference
tl;dr
Insert a moment two hours from now.
myPreparedStatement // Use a `PreparedStatement` to exchange data with your database, to avoid SQL-injection risk. Use JDBC 4.2 or later for *java.time* support.
.setObject( // Fill a placeholder `?` in your SQL statement.
… , // Specify which placeholder.
OffsetDateTime // Use `OffsetDateTime` to specify a moment in JDBC 4.2. Optionally, your JDBC might support `Instant` or `ZonedDateTime` types, while support for `OffsetDateTime` is required.
.now( // Capture the current moment.
ZoneOffset.UTC // Set the offset-from-UTC to zero. We do not need to account for any time zone in this particular business scenario.
) // Returns an `OffsetDateTime` object.
.plus( // Adds a span-of-time to the moment held in the `OffsetDateTime` object.
Duration.parse( "PT2H" ) // Specify the span-of-time using standard ISO 8601 format for a duration.
) // Per Immutable Objects pattern, returns a new `OffsetDateTime` rather than changing ("mutating") the original.
)
Details
I have a string value as "02:00:00", so basically I need to add 2 hrs to this time and get the future timestamp value that needs to be inserted
That is a poor way to communicate a span-of-time unattached to the timeline.
The standard way is PnYnMnDTnHnMnS where the P marks the beginning, and the T separates the years-months-days from the hours-minutes-seconds. So 2 hours is PT2H.
To parse such a string, use Duration class for hours-minutes-seconds (or Period for years-months-days).
String input = "PT2H" ;
Duration d = Duration.parse( input ) ;
You can generate such a string.
String output = Duration.ofHours( 2 ).toString() ; // Yields "PT2H" string.
Capture the current moment in UTC.
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
Add a duration of two hours using standard ISO 8601 notation.
Duration d = Duration.parse( "PT2H" ) ;
ZonedDateTime odtLater = odt.plus( d ) ; // Add 2 hours to the current moment.
Submit that to your database using JDBC 4.2 or later.
myPreparedStatement.setObject( … , odtLater ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.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.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
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 like to consider my timestamps as unsigned ints. It becomes quite silple to modify them : in your case, try to get an uint representation and just add 2 * 3600 * 1000 to the timestamp, then format it tonthe output you want.

Postgres convert date time difference into HH:MM:SS

Ex:
startTime-EndTime
Diff is 0 years 0 months 5 days 20 hours 6 minutes 30 seconds. I want to convert this into HH:MM:SS format : 120:06:30.
tl;dr
Duration // Represent a span-of-time in terms of total number of whole seconds plus a fractional second in nanos.
.between( // Calculate elapsed time.
myResultSet.getObject( … , OffsetDateTime.class ) , // Start
myResultSet.getObject( … , OffsetDateTime.class ) , // Stop
) // Returns a `Duration` object.
.toString() // Generate text in standard ISO 8601 format of `PnYnMnDTnHnMnS`.
java.time
Doing it on the Java side is simple with a column of a data type akin to the SQL-standard TIMESTAMP WITH TIME ZONE and driver compliant with JDBC 4.2 or later (for support of the modern java.time classes).
OffsetDateTime
Retrieve your moments as OffsetDateTime objects, per JDBC 4.2 spec.
OffsetDateTime start = myResultSet.getObject( … , OffsetDateTime.class ) ;
OffsetDateTime stop = myResultSet.getObject( … , OffsetDateTime.class ) ;
Duration
Calculate elapsed time as a Duration object.
Duration d = Duration.between( start , stop ) ;
ISO 8601
Generate a standard ISO 8601 string of the format PnYnMnDTnHnMnS where the P marks the beginning (probably stands for “period” – no standardized terms in date-time handling unfortunately), and the T separates years-months-days from hours-minutes-seconds. So an hour and a half would be PT1H30M. Your example of 5 days 20hours 6minutes 30 seconds would be P5DT20H6M30S.
The java.time classes use the ISO 8601 format by default. So you generate text by simply calling toString. No need to specify a formatting pattern.
String output = d.toString() ;
P5DT20H6M30S
To parse, call parse.
Duration d = Duration.parse( "P5DT20H6M30S" ) ;
Note that Duration counts days as 24-hour chunks of time, without regard for the calendar. If you want calendar-based dates, use Period class. If you want both concepts together, use PeriodDuration class from the ThreeTen-Extra, but think twice as mixing the two concepts is usually unwise and impractical.
I strongly advise you not represent a span-of-time using the clock notation as shown in your Question. Doing so is ambiguous, error-prone with people misinterpreting the text, as I have personally seen happen in business scenarios. The standard format is much wiser.
Duration::to…Part
But if you insist on the clock-formatting, create a string by calling the to…Part methods on Duration.
String output = d.toDaysPart() + ":" + d.toHoursPart() + ":" + d.toMinutesPart() + ":" + d.toSecondsPart() + "." + d.toNanosPart() ;
toHours versus toHoursPart
If want all the days reported as hours, get total number of hours across entire span-of-time by calling toHours rather than toHoursPart. Then get the parts of minutes and seconds.
Duration d = Duration.between( start , stop ) ;
String output = d.toHours() + ":" + d.toMinutesPart() + ":" + d.toSecondsPart() ;
120:06:30
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.
This can be achieved using postgresql.
To compute the difference between two timestamps as a number of seconds, use :
EXTRACT(EPOCH FROM (startTime - endTime))
Then you tun this value back to a timestamp with function TO_TIMESTAMP, and format this as a time using function TO_CHAR.
The hour part is tricky as you want to display values greater than 24 (which, as you would expect, is the maximum allowed in postgres): you need to use a little arithmetics to compute it.
SELECT CONCAT(
EXTRACT(EPOCH FROM (startTime - endTime))/60/60,
':',
TO_CHAR(TO_TIMESTAMP(
EXTRACT(EPOCH FROM (startTime - endTime))
), 'MI:SS')
)
FROM my_table

SimpleDateFormat not parsing milliseconds and MySql is rounding Date

I'm using SimpleDateFormat to parse string to Date.
After the parse, I'm loading this date to mysql. The problem is that milliseconds is not being parsed to Date and when I insert the object on Mysql its getting rounded.
myStringDate = "2018-02-02 23:59:59.700"
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.SSS");
myObject.setDate(fmt.parse(myStringDate );
When I debug the code I can see the Date as Sun Feb 02 23:59:59 BRST 2018 (its not storing milliseconds)
The data is stored on mysql as '2017-02-03 00:00:00'
My model is mapped as :
import javax.persistence.*;
import java.util.Date;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "date")
private Date date;
And column on MySqls is TYPE DATETIME.
I think the milliseconds are actually being parsed, you just aren't seeing them with the default formatting that you're getting when you're displaying the date for debugging purposes.
Using this code:
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String myStringDate = "2018-02-02 23:59:59.700";
Date date = fmt.parse(myStringDate);
System.out.println(date);
System.out.println(fmt.format(date));
I get this output:
Fri Feb 02 23:59:59 EST 2018
2018-02-02 23:59:59.700
Update: Make sure you use capital MM for the month, not mm.
tl;dr
myPreparedStatement.setObject(
… ,
LocalDateTime.parse(
"2017-02-03 00:00:00".replace( " " , "T" )
)
)
Smart types, not dumb strings
The data is stored on mysql as '2017-02-03 00:00:00'
No, the data is not stored that way. You said:
column on MySqls is TYPE DATETIME.
That means the date-time is not stored as text, and does not have a “format”.
As the documentation says:
The DATETIME type is used for values that contain both date and time parts. MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD HH:MM:SS' format.
Key words there are: retrieves and displays. After extracting the date-time value, some text is constructed to represent that value. Do not conflate the textual representation of the date-time value with the date-time value. Both your database and Java have their own internally-defined way of storing a date-time, but neither use plain text. Both your database and Java can generate text to display a date-time value, as needed.
Unzoned
I am a Postgres user, not MySQL, but it seems that its DATETIME type is akin to the SQL-standard TIMESTAMP WITHOUT TIME ZONE type. This means it does not represent an actual moment, is not a point on the timeline. It represents potential moments along a range of about 26-27 hours. Without the context of a time zone or offset-from-UTC, it has no real meaning.
java.time classes
Avoid the legacy date-time types. Use only java.time classes instead. According to this Question, JPA & Hibernate now support the java.time types.
If you do have input text such as 2018-02-02 23:59:59.700, parse as a LocalDateTime, given the lack of zone/offset information. Like the MySQL type DATETIME and the SQL type TIMESTAMP WITHOUT TIME ZONE, this class lacks any concept of zone/offset. To parse, convert from SQL-style with a SPACE in the middle to ISO 8601 standard format with a T in the middle.
String input = "2018-02-02 23:59:59.700".replace( " " , "T" ) ;
The java.time classes use ISO 8601 formats by default when parsing/generating strings. So no need to define a formatting pattern.
LocalDateDate ldt = LocalDateTime.parse( input ) ;
No need for strings when communicating with your database. As of JDBC 4.2 and later, you can directly exchange java.time objects. (Or let JPA/Hibernate do so under-the-covers.)
myPreparedStatement.setObject( … , ldt ) ;
And retrieval.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
FYI, if you are actually trying to track specific moments in time, you are using the wrong types. You should be using TIMESTAMP in MySQL or TIMESTAMP WITH TIME ZONE in standard SQL, and in Java use Instant and ZonedDateTime.
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.
If you are using MySQL's version 5.6.4, you can see this happen by declaring columns with fractional-second time datatypes.
This documentation shows more in detail about this feature, and as far as a quick check is concerned - you may try SELECT NOW(3) should give you the present time from your MySQL server's operating system with millisecond precision and instead if you are getting an error then you are not using the right version.
Alongside to that, moving from the older Connector/J driver to mysql-connector-java-5.1.26.jar is very much suggested.
Hope this helps answer your question!
The pattern for month of the year should be MM (uppercase) not mm (lowercase) for SimpleDateFormat. It is possible your code is reading the month as a minutes value.
The date format in SQL is YY-MM-dd hh24:mi:ss:mmm while in Java is YY-MM-dd HH:mm:ss.SSS
I used LocalDateTime:
#Column(name = "date", columnDefinition = "DATETIME(3)")
private LocalDateTime date;

Unable to fetch Date Values from Result Set in Java

I am trying to retrieve date values from Oracle database using resultset.The format of date is like dd-mmm-yy(like 17-MAY-18).Th column name is VALID_TO here.The default value is set as TO_DATE 01.01.4000 in DB.I am writing code as below.
String sql_qry = "SELECT a.VALID_TO from table1 a where a.VALID_FROM > '01-JAN-
18' and a.VALID_TO > '31-JAN-18'";
this.preparedStatement = dbconnection.prepareStatement(sql_qry);
ResultSet rs = this.preparedStatement.executeQuery();
while (rs.next()) {
AccountDetails detailsVo = new AccountDetails();
detailsVo.setDateColumn(rs.getDate("VALID_TO"));
accountDetails.add(detailsVo);
}
I am getting the default value 01.01.4000 and not the actual date from database.How to fetch actual values.I imported java.sql.Date above.
tl;dr
Use java.time classes rather than legacy date-time classes. Specifically, LocalDate for date-only value.
Use placeholders in your SQL and prepared statement.
Pass java.time objects directly, via JDBC 4.2.
Example:
myPreparedStatement.setObject( 1 , startLocalDate ) ;
myPreparedStatement.setObject( 2 , stopLocalDate ) ;
…and…
myResultSet.getObject( … , LocalDate.class)
java.time
With JDBC 4.2 and later, you can exchange smart objects with your database rather than dumb strings.
Placeholders
Set up your prepared statement using placeholders rather than literals.
String sql = "SELECT * FROM tbl WHERE fromCol >= ? AND toCol < ? ;" ;
LocalDate
Set up the values to fill-in those placeholders. For a date-only column such as SQL-standard type DATE, use the java.time.LocalDate class. The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 1 ) ; // First of January 2018.
Half-Open
Generally best in date-time work to use the Half-Open approach to defining a span of time, where the beginning is inclusive while the ending is exclusive. So if you want the entire month of January, query for "is equal to or later than the first of the month AND is less than the first day of the following month".
LocalDate stop = start.plusMonths( 1 ) ; // First of February 2018.
Or, your intention might be more clear by using the YearMonth class to represent the entire month as a whole.
YearMonth ym = YearMonth.of( 2018 , 1 ) ; // January 2018.
LocalDate start = ym.atDay( 1 ) ; // First of January 2018.
LocalDate stop = ym.plusMonths( 1 ).atDay( 1 ) ; // First of February 2018.
PreparedStatement & ResultSet
Either way, we now have a pair of LocalDate objects to feed into our prepared statement's placeholders.
myPreparedStatement.setObject( 1 , start ) ;
myPreparedStatement.setObject( 2 , stop ) ;
When retrieving from the result set:
LocalDate start = myResultSet.getObject( … , LocalDate.class ) ;
Avoid the legacy date-time classes
No need for java.util.Date, java.sql.Date, or any of the other poorly-designed hack date-time classes bundled with the earliest versions of Java.
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.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor 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, 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.

Is Oracle db able to compare timestamps with different timezones?

I'd like to know if Oracle is able to compare dates with different Timezones, as in:
12/26/2016 3:58:16.491476 AM -06:00 > 12/26/2016 3:58:16.491476 AM +05:00
Btw, I'm using JPA to do this comparison, the idea would be to look for all the rows created an hour ago.
I found that I might be able to use the After keyword to look for it (i.e. findMeasureDateAfter)
Very easy to check in Oracle. The answer is YES. Please note, in the illustration below the output shows timestamps using my session's NLS settings (I didn't care to change them).
with
inputs ( ts1, ts2 ) as (
select to_timestamp_tz('12/26/2016 3:58:16.491476 AM -06:00',
'mm/dd/yyyy hh:mi:ss.ff AM TZH:TZM'),
to_timestamp_tz('12/26/2016 3:58:16.491476 AM +05:00',
'mm/dd/yyyy hh:mi:ss.ff AM TZH:TZM') from dual
)
select ts1, ts2, case when ts1 > ts2 then 'ts1 > ts2'
when ts1 = ts2 then 'ts1 = ts2'
when ts1 < ts2 then 'ts1 < ts2'
end as comparison,
ts1 - ts2 as difference
from inputs
;
TS1 TS2 COMPARISON DIFFERENCE
----------------------------- ----------------------------- ---------- -------------------
26-DEC-16 03.58.16.491 AM -06 26-DEC-16 03.58.16.491 AM +05 ts1 > ts2 +00 11:00:00.000000
If you are pulling the data from an Oracle table based on a predicate like this, it is much better to do that work in the database - so how this would be done in Java is irrelevant. (You certainly don't want to fetch all the rows, only to ignore most of them after you check the timestamp in Java.) Of course, if you need "the last hour" you would compare against systimestamp - 1/24.
ISO 8601
First, if those inputs are actually strings as presented in the Question, use standard ISO 8601 formats instead if at all possible. The standard formats are intuitive to humans and easier to parse by computers. Indeed, the java.time classes use ISO 8601 formats by default when parsing/generating strings.
java.time
While I do not know about the the query in Oracle (I'm a Postgres man myself), I can show how to form the query more on the Java side.
Ideally we would parse that input string as a OffsetDateTime as it lacks an indication of time zone, only has offset-from-UTC. A zone is an offset plus a set of rules for handling anomalies such as Daylight Saving Time (DST). A time zone is named in format of continent/region such as America/Montreal.
Unfortunately, the java.time implementation in Java 8 has some bugs around parsing offset-from-UTC in the DateTimeFormatter class. So until Java 9, here is a bit of hack code to parse as a ZonedDateTime and convert to the more appropriate OffsetDateTime.
String input = "12/26/2016 3:58:16.491476 AM -06:00";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "MM/dd/uuuu h:m:s.SSSSSS a z" , Locale.ENGLISH );
OffsetDateTime odt = ZonedDateTime.parse ( input , f ).toOffsetDateTime ();
odt.toString(): 2016-12-26T03:58:16.491476-06:00
Repeat for your ending moment.
If your JDBC driver supports JDBC 4.2 or later, you may be able to pass these java.time types directly via PreparedStatement::setObject.
If not, convert to java.sql types. To convert, look to new methods added to the old classes. The from method takes an Instant which is a moment on the timeline in UTC. You can think of an Instant as a OffsetDateTime stripped of its offset. Call OffsetDateTime::toInstant to extract an Instant.
java.sql.Timestamp ts = java.sql.Timestamp.from( odt.toInstant() ) ;
Do this for both your beginning and ending moments. Pass these java.sql.Timestamp objects to your PreparedStatement.
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 and 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 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.

Categories