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.
Related
I am trying to get the timestamp value for 2018-09-04 13:43:32.922000 by doing
Timestamp.valueOf("2018-09-04 13:43:32.922000")
my expected output is 2018-09-04 13:43:32.922
but I am getting 2018-09-04 01:13:32.922
It might be due to different timezone because my team in India got the exact result but I am here in California gets the different result.
Suggest the changes that can solve this problem.
tl;dr
myPreparedStatement.setObject(
Instant
.parse(
"2018-09-04 13:43:32.922000"
.replace( " " , "T" )
.concat( "Z" )
)
.atZone(
ZoneOffset.UTC
)
)
java.time
Suggest the changes that can solve this problem.
Never use java.sql.Timestamp.
Among the many flaws of that class is that the method you call is not documented to explain its behavior while parsing. It appears your JVM’s current default time zone is being silently applied with some adjustment. But the issue is moot.
That terribly-designed class was supplanted years ago by the modern java.time classes with the adoption of JSR 310, specifically Instant and OffsetDateTime.
Change your input string to standard ISO 8601 format by replacing the SPACE in the middle with a T.
String input = "2018-09-04 13:43:32.922000".replace( " " , "T" ) ;
Was your input intended to represent a moment in UTC, an offset of zero? If so, append a Z (pronounced Zulu).
String input = "2018-09-04 13:43:32.922000".replace( " " , "T" ).concat( "Z" ) ;
The Instant class represents a moment in UTC, always in UTC by definition.
Instant instant = Instant.parse( input ) ;
Your JDBC driver may optionally accept a Instant object.
myPreparedStatement.setObject( instant ) ;
If your JDBC driver does not support Instant, use OffsetDateTime. Support is required in JDBC 4.2 and later.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( odt ) ;
Notice how your JVM’s current default time zone at runtime is irrelevant, with no impact on the code above.
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 do not think the issue is due to different time zones. Its just that the output that you are getting is in 24 hour format and that needs to be converted to 12 hour format. Please refer How to convert 24 hr format time in to 12 hr Format? to convert the time to 12 hour format.
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.
I need to format the Java Date object into a String like yyyyMMdd (round to day). For e.g, 20180129. I have the following implementation:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.format(roundedDate);
The code works most the time, but sometimes it'll generate results like 2018129, which is not what I want. So I'll have both 20180129 and 2018129 in my database.
The app consumes messages from a MQ and ummarshalls the timestamp in the message into a Java Date object. And it formats the date into a the above String.
The issue is that I cannot reproduce the issue in debug mode. It always produces the expected results in the debugger. But after I ran it on a server (in Docker) for some time, I see such corrupted data.
I wonder why the SimpleDateFormat could have such undetermined behavior given a valid Date object? Any idea will be appreciated.
SimpleDateFormat is not thread-safe, see this excellent article.
java.time.format.DateTimeFormatter is the modern thread-safe implementation of this functionality in the core Java.
tl;dr
Use the thread-safe java.time classes instead.
Specifically, use LocalDate and DateTimeFormatter.BASIC_ISO_DATE.
LocalDate.parse(
"2018129" ,
DateTimeFormatter.BASIC_ISO_DATE
)
2018-01-29
LocalDate.now()
.format( DateTimeFormatter.BASIC_ISO_DATE )
20180129
Thread-safety
You do not provide enough information to diagnose your problem. I would guess either:
You are using those legacy date-time objects across threads, and they were not designed to be thread-safe. Instead use the java.time classes which are designed to be thread-safe by design via immutable objects pattern.
Something is going wrong during whatever you are doing in this mysterious “date rounding” which you mention but neglect to explain.
Wrong data type
timestamp in the message into a Java Date object.
You are putting a date-only value into a date-with-time-of-day type. Square peg, round hole.
Instead, use a date-only type for a date-only value: LocalDate.
ISO 8601
Your desired format YYYYMMDD happens to be defined in the ISO 8601 standard, as the “basic” variant where the use of delimiters is minimized.
Java provides a DateTimeFormatter object for this purpose: DateTimeFormatter.BASIC_ISO_DATE. So no need to define a formatting pattern.
String input = "2018129" ;
LocalDate ld = LocalDate.parse( input , DateTimeFormatter.BASIC_ISO_DATE ) ;
To generate such a string, use the same formatter.
LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
String output = today.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
By the way, I recommend using the full-length versions of ISO 8601 formats rather than the compact “basic” variants. The few bytes saved are not worth giving up the readability and reduced ambiguity, in my experience. Plus, the java.time classes use the full-length ISO 8601 formats by default when parsing/generating String objects, so you can dispense with DateTimeFormatter objects entirely.
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.
I have following web application:
Users can enter java simple date format patterns and a date (of course matching to the java simple date format pattern) and I want to store these date in an oracle database.
Therefore I need to translate the java simple date format pattern into the oracle pattern.
E.g:
"dd-MM-yyyy HH:mm:ss" into "DD-MM-YYYY HH24:MI:SS"
"dd-MM-yy HH:mm:ss" into "DD-MM-YY HH24:MI:SS"
"dd-MM-yy HH:mm" into "DD-MM-YY HH24:MI"
and so on.
Instead of the following code just having one SimpleDateFormat I would like to have all or at least a big bunch of SimpleDateFormatPatterns translated into Oracle pattern:
SimpleDateFormat sFormat = new SimpleDateFormat( "dd-MM-yyyy HH:mm:ss");
String sqlSnippet = "TO_DATE('" + sFormat.format(date) + "','DD-MM-YYYY HH24:MI:SS')";
Is there a library or maybe just a mapping list to do this?
Thanks.
Edit:
I need to build the SQL by hand as the user defines the criteria, compare operators and joins in the user interface.
In the end I have something like this
AND col2 > TO_DATE('26-09-2012','DD-MM-YYYY')
Therefore I need to translate the java simple date format pattern into the oracle pattern
No, you don't. You should instead use a PreparedStatement, and call setDate or setTimestamp on it to specify the value you're interested in.
Avoid string conversions unless they're fundamentally part of what you're trying to do (e.g. displaying a date/time in a UI). For simply transferring information from your app to your database or vice versa, you should reduce the number of conversions required as far as possible.
The Answer by Jon Skeet is correct but is now outdated in referring to some legacy classes. The java.sql.Date and java.sql.Timestamp and related classes are now supplanted by the java.time classes, LocalDate and Instant respectively. But your Question demands the LocalDateTime class.
Smart objects, not dumb strings
You objects to represent your date-time values. As of JDBC 4.2 and later, you can directly exchange java.time objects with your database.
Your inputs lack any indicator of time zone or offset-from-UTC. So parse in Java as a LocalDateTime for storage in a column of a type similar to SQL-standard TIMESTAMP WITHOUT TIME ZONE.
DateTimeFormatter f1 = DateTimeFormatter.ofPattern( "dd-MM-uuuu HH:mm:ss" ) ;
DateTimeFormatter f2 = DateTimeFormatter.ofPattern( "dd-MM-uu HH:mm:ss" ) ;
DateTimeFormatter f3 = DateTimeFormatter.ofPattern( "dd-MM-uu HH:mm" ) ;
Choose a formatter by length of the input string.
LocalDateTime ldt = LocalDateTime.parse( myInputString , f2 ) ;
I need to build the SQL by hand as the user defines the criteria, compare operators and joins in the user interface. In the end I have something like this
String sqlSnippet = "TO_DATE('" + sFormat.format(date) + "','DD-MM-YYYY HH24:MI:SS')";
No, do not embed your date-time value as text in a String of SQL. Instead, use a PreparedStatement with ? placeholders replaced with your LocalDateTime object.
String sql = "SELECT when FROM tbl WHERE when > ? ;" ;
Pass the object to be slipped into that placeholder at runtime.
myPreparedStatement.setObject( … , ldt ) ;
Retrieval:
LocalDateTime ldt = myResultSet.getObject( … ; LocalDateTime.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.
I have a Joda DateTime object representing a UTC time, and wish to store it in a Timestamp field in a MySql table.
I have the following code:
String ztime = "2013-10-07T08:00:00Z";
DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser();
DateTime dt = parser.parseDateTime(ztime).withZone(DateTimeZone.UTC);
PreparedStatement stmt = con.prepareStatement("insert into time_test (time) values (?)");
stmt.setTimestamp(1, Timestamp(dt.getMillis()));
stmt.execute();
However, when I look in the database, the time that gets store is out by the difference of my database's timezone from UTC.
e.g. when my database is running in UTC+1, and run the above code to save "08:00Z", in the database the Timestamp shows as 09:00.
DateTime's getMillis method says " Gets the milliseconds of the datetime instant from the Java epoch of 1970-01-01T00:00:00Z."
and MySql's Timestamp says: "MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval.",
so I presume it's the MySql conversion that's causing the issue, because the millis it's being initialized with is relative to a fixed UTC time, so it has no need to convert from current time zone to UTC.
My code to read the data back out into a DateTime works fine, and I get the value out that I put in, but I also need this to work with some 3rd-party code over which
I have no control, which expects the Timestamp to be in the correct UTC time.
How do I get the Timestamp field in the database to match my original UTC date/time ?
tl;dr
Use java.time classes that supplant Joda-Time.
myPreparedStatement.setObject(
… ,
Instant.parse( "2013-10-07T08:00:00Z" )
)
Retrieve.
myResultSet.getObject(
… ,
Instant.class
)
java.time
The Joda-Time project is now in maintenance-mode, recommending migration to its successor, the java.time classes built into Java 8 and later. Both are led by the same man, Stephen Colebourne. You'll find many of the same concepts in play, so fairly easy to migrate.
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).
Your input string happens to be in standard ISO 8601 format. The java.time classes use these standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
String input = "2013-10-07T08:00:00Z" ; // Standard ISO 8601 format.
Instant instant = Instant.parse( input ) ; // Parses standard ISO 8601 format by default.
The Instant class replaces both java.util.Date and java.sql.Timestamp. As of JDBC 4.2 and later, you can directly exchange java.time objects with the database.
myPreparedStatement.setObject( … , instant ) ;
And retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
The TIMESTAMP type in MySQL seems to be akin to the SQL-standard TIMESTAMP WITH TIME ZONE type. So the code above should work appropriately.
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.