Getting JDBC & Saxon DateTime data as a ZonedDateTime object - jdbc

We have a bunch of code that gets a DateTime from JDBC, Saxon (XPath), dom4j, jway json-path (JPath), & OData as a Date object. We're now up on Java 1.8 and my first question is do I want to now try to get any data that I used to get as a Date object to now get it as a ZonedDateTime object? Or should I be using something else?
My second question is how do I read the data from JDBC, Saxon, etc as ZonedDateTime objects?

tl;dr
Never use the legacy classes, use only java.time.
When you must, convert using new methods added to the old classes.
As of JDBC 4.2, exchange java.time objects with your database, never strings or java.sql types.
Do most of your work in UTC. Adjust into a time zone only for presentation.
When communicating date-time values as text, use ISO 8601 formats.
Search Stack Overflow for more info.
Avoid legacy date-time classes
The terribly troublesome old date-time classes such as java.util.Date, java.util.Calendar, java.text.SimpleDateFormat, java.sql.Timestamp, and java.sql.Date are all entirely supplanted by the java.time classes. No need to ever touch those awful old classes again.
The java.time classes have been bundled with Java 8 and later for a few years now. They have proven themselves to be a reliable, industry-leading framework for date-time work. They were inspired by the lessons learned from the excellent Joda-Time project (now in maintenance-mode). So the java.time classes have “an old soul”, and are not some limited “1.0” rough draft.
Conversion
For interoperating with old code not yet updated to the java.time classes, you can easily convert back-and-forth between the legacy classes and modern classes. For conversions, look to new methods added to the old classes. Read Questions such as this to learn more.
Database
As of JDBC 4.2 and later, you can directly exchange java.time objects with your database. No need to ever use the badly-designed java.sql classes again for date-time values.
Generally best to use Instant for values in a column of type akin to the SQL-standard TIMESTAMP WITH TIME ZONE.
myPreparedStatement.setObject( … , instant ) ;
And retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
ISO 8601
When exchanging date-time values outside of a JVM, serialize to text using the standard ISO 8601 formats. These formats are designed to be useful and practical, easy to parse by machines, easy to read by humans across cultures.
The java.time classes use the ISO 8601 formats by default when parsing/generating strings. The ZonedDateTime class extends the standard by wisely appending the name of the zone in square brackets.
Zones
data that I used to get as a Date object to now get it as a ZonedDateTime object?
The java.util.Date class is directly replaced by Instant. Both represent a moment in UTC. The modern class resolves to nanoseconds instead of milliseconds.
Instant instant = myJavaUtilDate.toInstant() ; // Convert from legacy class to modern.
In databases such as Postgres, a column of type TIMESTAMP WITH TIME ZONE actually does not have its time zone saved. Instead, any offset or zone passed with an incoming value is used by the database to adjust into UTC. The resulting UTC moment is saved to the database, and the original zone/offset is discarded. If you need the original zone/offset, you must manually save it to an extra column yourself.
So, generally best to pass and fetch Instant objects with your database for a moment on the timeline.
To learn about the concept of a date-time not on the timeline, search for LocalDateTime class, and read postings like this Question, What's the difference between Instant and LocalDateTime?.
Be aware that the SQL standard barely touches on the tricky topic of date-time handling. It defines a few types but says little about behavior. So databases vary widely in their implementations. Be sure to study and experiment to verify your understanding of your database and driver.
read the data from JDBC, Saxon, etc as ZonedDateTime objects?
Generally the best practice is to work in UTC. That means the Instant class rather than ZonedDateTime class.
If receiving a Date, convert to Instant as shown above.
Usually you want to do your business logic, storage, exchange, logging, and tracing/debugging all in UTC. Apply a time zone only where required by business requirements or for presentation to a user.
With a Instant in hand, you can adjust to the wall-clock time used by the people of a particular region by assigning a time zone. Apply a ZoneId to get a ZonedDateTime.
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( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Search Stack Overflow
Your Question is really a duplicate of many others such as this. I suggest you search Stack Overflow for the various java.time class names. You will learn much as there have been plenty of questions and answers already posted.
Compatible libraries
Many Java libraries have been updated to work with java.time types.
Check for the latest versions of libraries you may be using, and read their documentation to learn about added support.
If not directly supported, libraries that accept converters/formatters/plugins will likely have some java.time ones already written. Search for them, or ask on the sister site: Software Recommendations Stack Exchange.
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

Do JDBC types actually matter? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Can, in today's drivers, JDBCTypes of the most popular DBMSs and set always to JDBCType.OTHER? Can input/output classes be used interchangeably within the character stream/binary stream/number/time point type classes?
I am asking first, specifically about JDBCType/java.sql.Types constants and, second, about the methods used for retrieving (i.e. the Java class to which the column maps). My experience with several databases was that in general, they will happily convert anything to anything else if only it makes sense. Mind you, I did not perform any kinds of exhaustive tests, it is just an experience that I could almost always access a ResultSet column as any type I wanted specifically in that context, not worrying about JDBC<=>DBMS SQL mapping. Obviously, I am not advocating here timestamp<=>string, integer<=>string conversions and similar; I am also aware for example, of the subtle differences between accessing a column as ZonedDateTime with getObject, and converting manually the result of getTimestamp, but that's a difference between the concepts behind these classes.
Explicitly, applications use JDBCType in practice only in PreparedStatement.setNull and CallableStatement.registerOutParameter, and here my experience was also that as long as I stuck to number/string/time/binary distinction I could pick the class according to wishes.
So, overall, they seem to me like a relic of questionable example from 15(?) years ago when we didn't have the experience and knowledge about building modern server side applications and most of Java EE was based on fantasies.
The type constants themselves are also used for metadata introspection. For example, for DatabaseMetaData.getColumns, the result set column DATA_TYPE contains the java.sql.Types code, and ResultSetMetaData.getColumnType returns the java.sql.Types code, and that applies to other metadata methods and objects. Metadata introspection might not be very important in normal programs, but it is used a lot by database tools and data access libraries or frameworks.
Other usage really depends on the driver and database system. Some drivers (and database systems) will always determine the type of columns on prepare time, and when setting values the driver will convert the value to the expected type of the parameter (as long as such a conversion is possible or specified by JDBC). That is, if the parameter is VARCHAR, and you set a long, then the driver will convert the long to string and use the string as the parameter value. For those database systems, the java.sql.Types and java.sql.JDBCType doesn't have a lot of value (beyond metadata introspection), and will usually be ignored.
In other database systems and their drivers, parameters don't necessarily have an expected type at prepare time (or the prepare phase can be skipped if the driver supplies the type information, or the database system allows you to override parameter types), and the type will be determined by explicitly setting the value (so, setting a string will determine the type as VARCHAR, while setting a long will determine the type as BIGINT, etc). In those cases the type constants will have use, for example in setNull, or in setObject, as it will specify the type of the parameter, which could infer specific conversions or behaviour on the driver or on the database. It might also be necessary for situations where a parameter is passed to a polymorphic or overloaded function (that is, the actual type of the parameters determines what the function does and what it returns).
The registerOutParameter in CallableStatement is actually a special case of that. For the first type of drivers, this is usually technically unnecessary (as the types would be determined by the prepare), while for the second type it can be either necessary, to leave conversion of values to a specific type to the database engine, or useful to be able to execute stored procedures without explicit prepare: you tell the driver which OUT types to expect, and it can then execute the procedure without having prepared it first. In that last case, on execute it will - for example - send the statement text, and the parameters and a descriptor of the OUT types expected. If there is a mismatch (incompatible types, too few or too many parameters or OUT types, etc, the database system would then reject execution, or - though I don't know if this exists in practice - the combination of actual parameter types and expected OUT types could select a specific stored procedure implementation (if a database system supports overloaded stored procedures).

How to convert ZonedDateTime to XMLGregorianCalendar in Java 7

My java 7 application consuming a service whcih is in Java 8 , i am receiving a date as string like
"2020-04-13T12:36:13Z"
which is actually a ZonedDateTime.
i need to convert this string to XMLGregorianCalendar and send to another service ?
Since my application is in java 7 i could not parse the string to ZonedDateTime . Is there any way i can do this conversion ?
Easy when you know how.
String receivedDateTimeString = "2020-04-13T12:36:13Z";
XMLGregorianCalendar xmlgc = DatatypeFactory.newInstance()
.newXMLGregorianCalendar(receivedDateTimeString);
System.out.println(xmlgc);
Output:
2020-04-13T12:36:13Z
ZonedDateTime.toString() sometimes produces ISO 8601 format (and sometimes an extended format with a zone ID that is not part of ISO 8601). In your case you have got pure ISO 8601. Dates and times in XML documents use a variant of ISO 8601, it’s close enough that we can consider them the same for our purpose here. So an XMLGregorianCalendar instance is created directly from the ISO 8601 string, and its toString method produces the same ISO 8601 string back.
ThreeTen Backport allows you to use ZonedDateTime in Java 7
You can, and you may prefer to use ZonedDateTime in Java 7 too rather than XMLGregorianCalendar. This use goes through ThreeTen Backport, the backport of java.time to Java 6 and 7, see the links at the bottom.
import org.threeten.bp.ZonedDateTime;
public class DemoZonedDateTimeInJava7 {
public static void main(String[] args) {
String receivedDateTimeString = "2020-04-13T12:36:13Z";
ZonedDateTime zdt = ZonedDateTime.parse(receivedDateTimeString);
System.out.println(zdt);
}
}
2020-04-13T12:36:13Z
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601

How to customize a serialization

I'm newbie with graphql and spqr. I would like to serialize my dates with personal format. How I can do it?
The best answer I'd offer is: don't! SPQR serializes all temporal scalars as ISO 8601 strings in UTC zone for a reason. It is the most portable format, that any client can easily parse and understand, and any conversion and display logic is better left to the client itself.
If this is for some reason impossible (e.g. backwards compatibility with a legacy client), your best bet is providing your own scalar implementations. In the future there might be a feature to avoid this, but currently you have to implement your own scalars and a TypeMapper that will map the desired Java types to those scalars. See the existing ScalarMapper for inspiration. Once you have the mapper, register it via generator.withTypeMappers.

Decoding Protobuf encoded data using non-supported platform

I am new to Protobufs; I haven't had much exposure to them. One of the API endpoints we require data from, uses Protobuf encoded data. This generally wouldn't be an issue if I was using a 'supported' language such as JavaScript, Java, Python or even R to decode the data...
Unfortunately, I am trying to automate the process using Alteryx. Rather than this being an Alteryx specific question, I have a few questions about Protobufs themselves so I understand this situation better. I've read through the implementation of Protobufs in Java and Python, and have a basic understanding of how to use them.
To surmise (please correct me if I am wrong), a Protobuf is a method of serializing structured data where a .proto schema is used to encode / decode data into raw binary. My confusion lies with the compiler. Google documentation and examples for Python / Java show how a Protobuf compiler (library) is required in order to run the encoding and decoding process. Reading the Google website, it advises that the Protobufs are 'language neutral and platform neutral', but I can't see how that is possible if you need the compiler (and .proto file!) to do the decoding. For example, how would anyone using a language outside of the languages where Google have a compiler created possibly decode Protobuf encoded data? Am I missing something?
I figure I'm missing something, since it seems weird that a public API would force this constraint.
"language/platform neutral" here simply means that you can reliably get the same data back from any language/framework/platform. The serialization format is defined independently and does not rely on the nuances of any particular framework.
This might seem a low bar, but you'd be surprised how many serialization formats fail to clear it.
Because the format is specified, anyone can create a tool for some other platform. It is a little fiddly if you're not used to dealing in bits, but: totally doable. The protobuf landscape is not dependent on Google - here's a list of some of the known non-Google tools: https://github.com/protocolbuffers/protobuf/blob/master/docs/third_party.md
Also, note that technically you don't even need a .proto; you just need some mechanism for specifying which fields map to which field numbers (since protobuf doesn't include the names). Quite a few in that list can work either from a .proto, or from the field/number map being specified in some other way. The advantage of .proto is simply that it is easy to convey as the schema - and again: isn't tied to any particular language. You can write plugins for "protoc" to add your own tooling, so you don't need to write your own parser from scratch. Or you can write your own parser from scratch if you prefer.
You can't speak of non-supported platform in this case: it is more about languages for which you can't find a protobuf implementation.
My 2 cents is: if you can't find a protobuf implementation for your language, find another language you're familiar with (and popular in protobuf community) and handle the protobuf serialization/deserialization with it. Then call it via a REST API, a executable ... whatever

An alternative to LinqToRDF, a library to bring Linq to RDF data?

LinqToRDF (http://code.google.com/p/linqtordf/) is a well known library to bring Linq to RDF data. But it is not active for nearly two years.
So I am looking for an alternative. My basic requirement is providing basic Linq function with general RDF data sources. Commercial library is welcome also.
Any suggestions are welcome.
Ying
You could try my library dotNetRDF which is designed so that many things can be accessed in a Linq style i.e. there is significant and pervasive use of IEnumerable<T> as a return type throughout the library.
But it doesn't have a completely Linq style API like LinqToRdf provided by which I mean it doesn't have the kind of methods which LinqToRdf had which allow you to write something like the following and have the library translate it to SPARQL or some other appropriate query language under the hood:
MusicDataContext ctx = new MusicDataContext(#"http://localhost/linqtordf/SparqlQuery.aspx");
var q = (from t in ctx.Tracks
where t.Year == "2006" &&
t.GenreName == "History 5 | Fall 2006 | UC Berkeley"
orderby t.FileLocation
select new {t.Title, t.FileLocation}).Skip(10).Take(5);
My library is much more low level, either you'd have to write the equivalent SPARQL query yourself or write a block of code which extracts the various Triples used to identify something and makes the relevant comparisons you want.
Eventually my intention is to port LinqToRdf to using dotNetRDF as it's underlying library for accessing RDF but this is fairly low on the priority list at the moment as I'm working on a major release of the core library which adds a lot of new functionality related to SPARQL 1.1
In terms of commercial options take a look at Intellidimension's Semantics Framework which is a commercial library though there is a free express version available - I haven't used the library so have no idea how Linq friendly it is. Main downside to the free version is a very strict redistribution policy.

Resources