I'm passing around some objects through web service and some of them contain java.sql.Date. Because Date doesn't have empty constructor it doesn't want to get serialized.
First part of a question is easy: what is the best way to pass a date between client and service?
Second part is bit trickier: Once I decide how to pass dates around, I can obviously declare date transient and make some wrapper class to pass dates as String or whatever, but how to apply same solution as transparently as possible to several classes that include Date?
(I have a hunch that DynamicProxy thingy might be a solution, but reading documentation on Sun's site wasn't very helpful, so if it really is something in that direction, some clarification would be appreciated)
Edit: I asked wrong question, sorry (some misunderstanding between me and coworker what is actually a problem). Problem occurs because of deserializing. So once I have date in xml format it tries to deserialize itself as GregorianCalendar. Other part of a question still remains: What is the best way to receive something (long timestamp or GregorianCalendar) and convert it to sql date, without making 10 different wrappers for 10 different classes. I'm using a NetBeans for code and wsdl generation.
Joda-Time
The Date class has a clunky API. A better implementation is Joda-Time.
ISO 8601
Joda-Time also allows you to convert your date in a ISO 8601 standard format (yyyy-mm-ddTHH:MM:SS.SSS). Using this standard when moving dates from server to its client has the advantage to include the full date in a readable format. When you use for example JAXB, the XML representation of a date is also this ISO standard. (see the XMLGregorianCalendar class)
Serializing the long returned by Date.getTime() as previously suggested will work. You should however note that if your server is in another time zone than the client, the date you'll reconstruct on the other side will be different. If you want want to reconstruct exact same date object you also need to send your time zone (TimeZone.getID()) and use it to reconstruct the date on the other side.
To answer the first part of your question, I would suggest a string in iso 8601 format (this is a standard for encoding dates).
For the second part, I'm not sure why you would need a proxy class? Or why you would have to extend the date class to support this. eg. would not your web service know that a certain field is a date and do the conversion from date to string and back itself? I'd need a little more information.
java.sql.Date extends java.util.Date
Just use getTime() to get the long value from it. This can be serialized and a new java.sql.Date(long) or new java.util.Date(long) constructed from it at the other end.
I've looked into the implementation of java.sql.Date and as I see it java.sql.Date is Serializable as an extension of java.util.Date.
one caveat with java.sql.Date that bit me recently is that it doesn't store the time portions (hours, minutes, seconds, etc) just the date portion. if you want the full timestamp you have to use java.util.Date or java.sql.Timestamp
I will expand on the correct answer by JeroenWyseur.
ISO 8601
The ISO 8601 standard format is absolutely the best way to serialize a date-time value for data exchange. The format is unambiguous, intuitive to peoples across cultures, and increasingly common around the world. Easy to read for both humans and machines.
2015-01-16T20:15:43+02:00
2015-01-16T18:15:43Z
The first example has an offset of two hours ahead of UTC. The second example shows the common use of Z ("Zulu") to indicate UTC, short for +00:00.
java.time
The java.util.Date & .Calendar classes bundled with Java are notoriously troublesome, confusing, and flawed. Avoid them. Instead use:
java.time package, built into Java 8, inspired by Joda-Time, defined by JSR 310.
The java.time package supplants its predecessor, the Joda-Time library.
By default, both libraries use ISO 8601 for both parsing and generating String representations of date-time values.
Note that java.time extends the ISO 8601 format by appending the proper name of the time zone, such as 2007-12-03T10:15:30+01:00[Europe/Paris].
Search StackOverflow.com for many hundreds of Questions and Answers with much discussion and example code.
Avoid Count-From-Epoch
Some of the other answers recommend using a number, a count from epoch. This approach is not practical. It is not self-evident. It is not human-readable, making debugging troublesome and frustrating.
Which number is it, whole seconds as commonly used in Unix, milliseconds used in java.util.Date & Joda-Time, microseconds commonly used in databases such as Postgres, or nanoseconds used in java.time package?
Which of the couple dozen epochs, first moment of 1970 used in Unix, year 1 used in .Net & Go, "January 0, 1900" used in millions (billions?) of Excel & Lotus spreadsheets, or January 1, 2001 used by Cocoa?
See my answer on a similar question for more discussion.
LocalDate
I'm passing around some objects through web service and some of them contain java.sql.Date
The replacement for the terrible java.sql.Date class is java.time.LocalDate.
Best to avoid the legacy class entirely, but you can convert back and forth by calling new methods added to the old class: myJavaSqlDate.toLocalDate()
Serializing LocalDate
The LocalDate class implements Serializable. So you should have no problem with it automatically serializing, both marshaling and unmarshalling.
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.
You don't need default constructor (empty) in order to serialize/deserialize date (either java.sql.Date or java.util.Date). During deserialization constructor is not called but attributes of object set directly to values from serialized data and you can use the object as it is since it deserialized.
You could use an encoder and decode to serialise and deserialise your objects.
Here is an example which serialises the SWT Rectangle class:
XMLEncoder encoder = new XMLEncoder(new FileOutputStream(file));
encoder.setPersistenceDelegate(
Rectangle.class,
new DefaultPersistenceDelegate(new String[]{"x", "y", "width", "height"}));
encoder.writeObject(groups);
encoder.close();
First, if you are using web services, it means you are serializing to XML and not your regular Java serialization (but some other library for marshaling and unmarshaling). So the question is lacking some information.
Second, if you have control over your InputStream & OutputStream try extending ObjectOutputStream and ObjectInputStream and override replaceObject() and resolveObject() and then you can implement serialization for java.sql.Date.
java.sql.Date already implements Serializable so no need to implement it :-)
As far as your main question is concerned, I'm deeply in love with JAXB as I can turn almost any XML into an object, so it might be worth your while to look into it.
Hmmm... Can't think of any reason why any serialized object-instance (serialized via the default java mechanism) should deserialize itself as an instance of another class as the class information should be an inherent part of the serialized data.
So it's either a problem of your (de-)serialization framework or the framework accepts any "date-like" object on the "sending end" (Calendar, java.util.Date etc. - an thus java.sql.Date too as it extends java.util.Date), "serializes" it to a String in some common date-format (so the type information is lost) and "deserializes" it back to a Calendar object on the receiving end.
So I think the simplest way to get to java.sql.Date is to do a
java.sql.Date date = new java.sql.Date(calendar.getTimeInMillis);
where you need an java.sql.Date but get the GregorianCalendar back from the "deserialization".
Related
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 would like to format dates, while formatting the numbers in the date in dozenal.
With the older Java date formatting API, I am able to do this:
format = new SimpleDateFormat(pattern, new DateFormatSymbolsAdapter(locale)) {{
numberFormat = new DozenalNumberFormat();
}};
Unfortunately, SimpleDateFormat internally has some dumb code which is allocating objects too rapidly for my purposes, as I'm formatting values rather frequently. Joda Time might not have this problem (their other classes seem to be fine so far), so I'm attempting to switch.
However, with Joda Time's date formatting classes, it isn't entirely clear how I can do it. A lot of the API is locked down in a way which makes it hard to get in and do what I want:
DateTimeFormatterBuilder methods don't give me a way to specify it
DateTimeFormatterBuilder has no arbitrary append that I can see
DateTimeFormatter doesn't seem to have any obvious intercept points
all the useful stuff seems to be locked inside InternalPrinter and its implementations, which are package private
Methods to append DateTimeFormatter, DateTimePrinter and the like appear to require a lot of framework just to make a custom implementation, and I haven't yet made my implementation work. After some investigation, it seems like this is a bug in Joda Time.
Surely there has to be some way to do it though. Does anyone have any idea? I think that perhaps someone has had to do it to get Arabic date formatting to work correctly in the past as well, as I vaguely recall Joda Time having problems with that, but maybe that is in the past. I might be the first one trying to do it because I want a different number base for the numbers...
Joda-Time is obviously not capable of printing other digits than ASCII-digits 0-9. I have investigated all relevant parts of Joda-documentation, even the classes DateTimeUtils and FormatUtils. And setting the locale to a locale which mandates the usage of an alternative numbering system does not help, too.
String s = DateTimeFormat.forPattern("yyyy-MM-dd").withLocale(new Locale("ar"))
.print(System.currentTimeMillis()));
// output: 2017-01-02 (still ASCII)
The newest CLDR-data (version v30.02) tell us that Arabic uses the alternative numbering system with code name "arab" (xml-tag defaultNumberingSystem). However, the JDK might not be always up-to-date. Often the JDK relies on an old CLDR-version. But even then, as far as I remember, also old CLDR-versions didn't use ASCII-digits for Arabic.
Conclusion: You should not use Joda-Time for serious i18n-work (one among many other details like fixed start of week etc. where this library is notoriously bad). If you still insist on using Joda-Time then you can go the hard way to write your own customized DateTimePrinter. But this is not fun as you have also noticed in your Joda-issue (and will still be no fun after possible fix because it is sooo awkward).
So let's look at better alternatives.
Java-8
Locale loc = new Locale("ar");
System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd")
.withDecimalStyle(DecimalStyle.of(loc))
.format(LocalDate.now()));
// output: 2017-01-02 (obviously my JDK uses wrong or outdated data)
System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd")
.withDecimalStyle(DecimalStyle.STANDARD.withZeroDigit('\u0660'))
.format(LocalDate.now()));
// correct output with hardwired numbering system
So we see that using the standard on Java-8 is better than Joda-Time but still not without quirks. The correct and only half-way-flexible solution makes usage of class DecimalStyle.
My library Time4J (also runnable on Java-6 with version line v3.x):
I have written an alternative format and parse engine which can also process Java-8-types like LocalDate, Instant etc. Time4J has its own repository for localized resources independent from JDK and actually uses CLDR-version v30.0.2. Showing two ways, either a generic way by locale or using hardwired assumption about numbering system:
System.out.println(
ChronoFormatter.ofPattern(
"yyyy-MM-dd",
PatternType.CLDR,
new Locale("ar"),
PlainDate.axis(TemporalType.LOCAL_DATE)
).format(LocalDate.now()));
System.out.println(
ChronoFormatter.ofPattern(
"yyyy-MM-dd",
PatternType.CLDR,
Locale.ROOT,
PlainDate.axis(TemporalType.LOCAL_DATE)
)
.with(Attributes.NUMBER_SYSTEM, NumberSystem.ARABIC_INDIC)
.format(LocalDate.now()));
Both ways produces digit representations based on zero digit ٠ (unicode point 0660). The year 2017 is displayed as: ٢٠١٧
Update:
Your last comments made clear that you are mainly concerned about how to realize the dozenal numbering system (positional number system for base 12). Well, with Java-8, there is not enough flexibility (no DateTimePrinter-interface like in Joda-Time, also no more flexible hook than DecimalStyle which only allows to set the zero decimal digit while dozenals are not decimal). In order to fill the gap (and it was not so much work), I have decided to implement the dozenal system within the newest version v3.27 (or v4.23 on Java-8-platforms). For Android, I have just now released Time4A-v3.27-2016j. Example of usage and final solution:
#Test
public void printDate() {
ChronoFormatter<PlainDate> f =
ChronoFormatter.setUp(PlainDate.axis(), Locale.ROOT)
.addFixedInteger(PlainDate.YEAR, 4)
.addLiteral('-')
.padNext(2)
.addInteger(PlainDate.MONTH_AS_NUMBER, 1, 2)
.addLiteral('-')
.padNext(2)
.addInteger(PlainDate.DAY_OF_MONTH, 1, 2)
.build()
.with(Attributes.NUMBER_SYSTEM, NumberSystem.DOZENAL)
.with(Attributes.PAD_CHAR, '0');
assertThat(
f.format(PlainDate.of(2017, 10, 11)),
is("1201-0\u218A-0\u218B"));
}
If you are working on Android then you might also consider to choose a slightly changed code using the old type java.util.Date for interoperability with legacy code, for example with the expression
ChronoFormatter.setUp(
Moment.axis(TemporalType.JAVA_UTIL_DATE), Locale.getDefault())...
Remark: This solution also makes best efforts to avoid extra array allocation when printing numbers (for example even avoiding Integer.toString() in many cases), especially if you use a StringBuilder as second parameter to the method ´ChronoFormatter.formatToBuffer()`. The overall performance effort so far done is unusally high compared with other libraries.
Your Question is not at all clear as you do not actually specify what you are trying to do nor exactly what is stopping you. But I will provide a bit of info.
FYI, the Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes.
Using java.time
Both java.time and Joda-Time use immutable objects. That means you get thread-safety built-in. So, you can cache your formatter object(s) and re-use them. No need to instantiate repeatedly.
In java.time, the java.time.format.DateTimeFormatter class can automatically localize for you. Both the human language and formatting can be automatically assigned from a Locale. See this list of supported locales in Java 8. I suggest using these auto-localized formats when they suffice.
Capture the current moment in UTC. Adjust into a time zone. Note that time zone has nothing to do with locale. You may want to see the wall-clock time in Québec while formatting for presentation to a Moroccan user reading Arabic.
Instant instant = Instant.now ();
ZonedDateTime zdt = instant.atZone ( ZoneId.of ( "America/Montreal" ) );
Generate a String for presentation to the user.
Locale l = new Locale ( "ar" , "MA" ); // Arabic language, cultural norms of Morocco.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.FULL ).withLocale ( l );
Keep a reference to f to cache that object. No need to instantiate again.
Dump to console.
String output = zdt.format ( f );
System.out.println ( "zdt.toString(): " + zdt );
System.out.println ( "output: " + output );
zdt.toString(): 2017-01-01T15:06:34.255-05:00[America/Montreal]
output: 01 يناير, 2017 EST 03:06:34 م
I am not sure if Arabic will copy-paste correctly here. See live code in IdeOne.com.
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.
I have read all of the other Q/A about Date Manipulation, but none of them seems to deliver a satisfactory answer to my concern.
I have a project with geographically diverse users which uses Date in some of its classes and data. The thing is that I am looking for an efficient way to manipulate the Dates for the different users in their respective timezone, most of the answers suggest using Joda library for Date manipulation, which quite don't understand yet because I still have not found any operation you cannot do with traditional Java, so if someone can explain what can I do with Joda that can't be done with traditional Java, then I may consider using it.
I finally came to the approach of using System.currentTimeMillis() to save my dates into the database (any database). This would avoid me to worry about what timezone is using the database to store the dates. If I want to query the database for an specific date or range of dates, I would perform the queries using the long value of the Date I want to query:
SELECT * FROM table1 WHERE date1>=1476653369000
And when retrieving a ResultSet I would then format the long value retrieved from database to a readable Date using the timezone of the user requesting the data.
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(resultSet.getLong(1));
cal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
Date myDate = cal.getTime();
According to some opinions I have read, some people say emphatically that storing System.currentTimeMillis() is definitely not the best practice, nevertheless, for some reason they all miss to say WHY it is not recommendable. Am I missing something? Does this cause a performance issue for the conversions Long->Date/Date->Long? Is there any use case that cannot be accomplished when using Long instead Date in database? Can someone post a rationale explanation about this?
In the other hand, assuming that I keep using Date values to store dates in database, is there a way to avoid worrying about time-zones while handling database Date?
Thanks in advance.
I have read all of the other Q/A about Date Manipulation
No, you certainly did not read them all.
You would have learned that both the legacy date-time classes (such as java.util.Date & java.util.Calendar) and the Joda-Time project are supplanted by the java.time classes (1,890 results for search on 'java.time').
You would have learned not to track date-time values as a count-from-epoch. Debugging and logging becomes very difficult with bugs going undiscovered as humans cannot decipher the meaning of a long integer as a date-time. And because many granularities of counting (whole seconds, milliseconds, microseconds, nanoseconds, whole days, and more) and at least a couple dozen of epochs are employed in various software projects create ambiguity about your data with assumptions leading to errors, misinterpretation, and confusion.
You would have learned to use date-time types in your database to track date-time values.
You would have learned to work and store date-time values in UTC. Adjust into a time zone only where required by logic or as expected by the user for presentation. “Think global, present local.”
You would have learned that while a valiant industry-first effort, the legacy date-time classes are poorly designed, confusing, and troublesome. See What's wrong with Java Date & Time API? for some discussion. Joda-Time was the first good date-time library in the industry, and inspired its replacement, the java.time classes built into Java 8 and later.
I'll be somewhat brief as all of this has been covered many times already on Stack Overflow.
Work in UTC. In Java that means the Instant class is commonly used. 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 = Instant.now();
Any serious database such as Postgres tracks date-time values in UTC. Your JDBC driver handles the detail of converting from database internally-stored data to a Java type. JDBC drivers that comply with JDBC 4.2 and later can directly handle java.time types via PreparedStatement::setObject & ResultSet::getObject methods.
myPreparedStatement.setObject( … , instant );
For non-compliant drivers, fall back to using java.sql types such as java.sql.Timestamp to communicate with database, and convert to/from java.time types via new methods added to the old classes. The internal details of how the database handles date-time values may be quite different than how java.time does. For the most part the JDBC driver hides all the nitty-gritty details from you. But one critical issue is resolution, which you should study in your database. The java.time classes handle date-times with a resolution up to nanoseconds but your database may not. For example, Postgres uses a resolution of microseconds. So going back-and-forth means data-loss. You want to use the truncation methods on the java.time classes to match your database.
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) );
So, no time zone involved. So no “worrying about time-zones while handling database Date”.
When you want to see the same moment through the lens of a region’s wall-clock time, apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );
When taking a zoned date-time back to the database, extract an Instant.
Instant instant = zdt.toInstant();
Be aware that for any given moment, the date as well as the time-of-day varies around the globe by time zone. So if an exact moment matters, such as when a contract expires, beware of using a date-only value. Either use a date-time value for the exact moment, or store the intended time zone alongside the date-only so the exact moment can be calculated later.
LocalDate ld = LocalDate.of( 2016, 1 , 1 );
// Determine the first moment of 2016-01-01 as it happens in Kolkata.
ZonedDateTime zdt = ld.atStartOfDay( ZoneId.of( "Asia/Kolkata" ) );
Instant instant = zdt.toInstant(); // Adjust to UTC and store.
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, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. 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….
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.
what can I do with Joda that can't be done with traditional Java
It's not really about what you can or cannot do with traditional Java in the general case. It's more about how the library API works to make you write better (more robust and correct) code easier than traditional Java does.
So much so that as of Java 8 the Joda API was more or less copied/adopted verbatim with just package names changed and incorporated into the Java 8 SE standard library.
Therefore if you are using Java 8 you should pick the new API, and if not you should consider that using Joda will at least buy you a smooth path towards upgrading/porting to Java 8 when you are able to.
A few examples:
Consistent API for date and time types.
Date/time objects are immutable, manipulations return new instances of the type representing the altered value. (Like Java Strings). This makes it easier to reason about reuse of date/time objects.
By design avoids mixing DST & timezone dependent values/operations with DST & timezone agnostic ones. This makes it a lot easier to write code that works consistently and correctly and doesn't have corner cases dependent on timezone/locale/date/time-of-day.
Sane defaults for things like toString() so serialising/deserialising can be expected to work correctly with minimal effort.
Culture/locale dependent corner cases and things you weren't aware of yet (for example, did you know about the traditional Korean calendar?) which saves you a whole lot of hassle when converting your date times between locales/calendaring systems. Also: a wealth of formatting options.
The concept of Instants to represent 'absolute' time stamps which is useful when working with geographically distributed systems (when the system default clocks/timezones & DST rules may differ) or for interop because it uses UTC.
EDIT to add:
According to some opinions I have read, some people say emphatically that storing System.currentTimeMillis() is definitely not the best practice, nevertheless, for some reason they all miss to say WHY it is not recommendable. Am I missing something?
System.currentTimeMillis() has a few downsides. The big drawback is that the type of clock is ill defined. It could be a monotonic clock, it could be clock subject to DST and timezone or it could be a UTC time. It is also not necessarily an accurate clock, it is not actually guaranteed to be accurate down to the millisecond. Just whatever happens to be to hand for something that will work as a semblance of the current time at the current time, basically.
This means that if you want to use multiple servers to handle incoming requests, for instance, it gets tricky when you have to consider working with the output of System.currentTimeMillis() from server A in the context of your program running on a different server B the next day, say.
To make a JDBC query I need to pass date to it. The date is kept in Date field type of PostgreSql database, which represents specific day without any time.
As I need only date, I decided to use specific object which represent only date without time, which is LocalDate from Joda-Time package. I thought it is important because if I used DateTime object, it would carry redundant time data as well as it might lead to bugs at end of daylight saving time when the clock are put backward one hour (though the situation is unprecedentedly rare, it's not impossible).
But when I started trying to square LocalDate object with accepted arguments of preparedStatement.setDate method, I didn't find a proper way to do it.
setDate accepts java.sql.Date as parameter. And the only option to construct java.sql.Date object is to pass it time in milliseconds.
But this defeats all the purpose of using LocalDate from Joda-Time package, as on this conversion we get back to milliseconds and, while these conversions happen, clock may be put back one hour and change the date to the previous date.
So, now I have this line in my code:
preparedStatement.setDate(1, new java.sql.Date(localDate.toDate().getTime()));
But is this the best way to convert LocalDate to accepted by setDate format?
Are my concerns related to daylight saving time and corresponding clock-shifts justified?
Is there a better way to pass date (and only date without time) to JDBC preparedStatement?
It should be safe to use your technique because all the timezone issues will be taken into account by LocalDate#toDate. The resulting millisecond instant you have is context-independent: it uniquely relates to a timezone valid at that point in time within the locale you are using for conversion. In other words, if you repeat the conversion of the exact same millisecond value throughout a year, you will consistently get the exact same answer, even if timezone regulations change for your place in the meantime, since JDK refers to a database documenting the complete history of all timezone changes around the world.
When reasoning about these issues it is important to remember that your current timezone has no effect on the conversion, which is parameterized by your locale and resolves the timezone only within the context of the instant being converted.
I wholeheartedly sympathize with the queasiness you fell about all this: it is turning a simple and straigtforward operation into a complex maze of calculations which does nothing but invite trouble. Hopefully things will take a positive turn with Java 8 and its new (yes, again!) Date/Time API, based firmly on JodaTime.
I got the same problem today. I'm using JDK 8. After spending some hours searching finally I found the answer at Java SE 8 Documentation. This is the solution :
statement.setDate(5, java.sql.Date.valueOf(personToUpdate.getBirthday()));
statement is PreparedStatement instance. "personToUpdate.getBirthday()" is type of LocalDate.
Since org.joda.time.toDateMidnight() and org.joda.time.toDateMidnight(DateTimeZone zone) have been deprecated, this is the solution that works perfectly for me.
My typical Class, to be persisted:
...
import org.joda.time.LocalDate;
...
public class MyObject implements Serializable {
...
private LocalDate startDate;
...
private EndDate startDate;
// Getters and Setters
...
...
}
Im my other Class where I persist startDate, I have:
myObject.setStartDate(new LocalDate(myObject.getStartDate().toDateTimeAtStartOfDay(DateTimeZone.getDefault())));
tl;dr
myPreparedStatement.setObject( // Pass java.time objects directly to database with JDBC 4.2 or later.
… ,
LocalDate.now() // Get current date today. Better to pass optional `ZoneId` time zone object explicitly than rely implicitly on JVM’s current default.
)
java.time
In Java 8 and later, the new java.time framework is now built-in. This successor to Joda-Time is defined by JSR 310 and extended by the ThreeTen-Extra project.
Hopefully we well eventually see the JDBC drivers updated to directly handle the new java.time types. But until then we continue to need the java.sql.* types. Fortunately, new methods have been added to conveniently convert between the types.
For a date-only, with no time-of-day and no time zone, the Java type is LocalDate (quite similar to Joda-Time).
As for your concern about time zone related to a LocalDate, it matters when your are translating a date-only to a date-time, to a moment on the timeline. A date-only is just a vague idea, with no real meaning, until you translate it to a time-span of moment on the timeline (midnight to midnight in some time zone). For example, determining "today" requires a time zone. In java.time we use the ZoneId class.
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
If omitted, your JVM’s current default time zone is used in determining the date. In other words, the following two lines are equivalent.
LocalDate today = LocalDate.now();
LocalDate today = LocalDate.now( ZoneId.systemDefault() );
I consider the first version, now(), to be a poor API design choice. This implicit application of the JVM’s current default time zone causes no end of confusion, bugs, and misery among naïve developers. For one thing, the JVM's current default varies by machine, by host OS settings, and by sysadmins. Worse, the JVM’s current default can change at any moment, during runtime, by any code in any thread of any app within that JVM. So best practice is to always specify your desired/expected time zone.
Now that we have a java.time object for "today", how to get it into the database?
With JDBC 4.2 or later, directly exchange java.time objects with your database.
myPreparedStatement.setObject( … , today ) ;
To retrieve:
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
If you cannot upgrade yet to JDBC 4.2 or later: Use a java.sql.Date object. In Java 8, that old class gained new methods, toLocalDate and valueOf. The latter is our bridge from the java.time type to the java.sql type.
java.sql.Date sqlToday = java.sql.Date.valueOf( today );
From there do the usual PreparedStatement handling.
myPreparedStatement.setDate( 1 , sqlToday );
Date-only vs Date-time
Perhaps you have concerns about such a date-only fitting your business needs.
If you need to know, for example, if a contract was signed by the end of the day for legal reasons, then date-only is the wrong data-type if mean a specific moment such as the stroke of midnight in Montréal. A new day dawns earlier in Paris than in Montréal, so "today" in Paris is "yesterday" in Montréal. If your contract deadline is defined legally as the end of the day in Montréal, then you must apply a time zone. To apply a time zone, you must have a date-time rather than a date-only. You can make a jump from the LocalDate into a ZonedDateTime, but I consider that overly complex. Your database should have used a date-time type from the beginning.
In Postgres, a date-time type means the TIMESTAMP WITH TIME ZONE type. That name is a misnomer as the time zone is not actually stored. Think of it as “timestamp with respect for time zone”. Postgres uses any offset-from-UTC or time zone information accompanying incoming data to adjust to UTC, and that offset/zone info is then discarded. The other type, TIMESTAMP WITHOUT TIME ZONE, ignores the offset/zone info entirely, and this is the wrong behavior for most any business app.
I suspect many developers or DBAs may make the naïve mistake of thinking by intuition that the date-only has obvious meaning. But in fact if you have specific or strict moment-oriented needs, such as legalities regarding events such as “contract signed”, “invoice received”, or “company executive hired”, then a date-time value should be used rather than date-only.
In other words, regarding the Question’s author’s comment:
And I expected there should be a way to work with dates without resorting to time instances.
No, I would argue that is asking for trouble. If moments matter, use a date-time rather than a date-only.
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.
Try to Use LocalDate#toDateMidnight() which sets time to 0 and then DateMidnight#toDate().
Date date = localDate.toDateMidnight().toDate();
Or if you're using JodaTime 1.5 or newer, use LocalDate#toDateTimeAtStartOfDay() and then DateTime#toDate()
Hope that help
Every time I need to work with date and/or timstamps in Java I always feel like I'm doing something wrong and spend endless hours trying to find a better way of working with the APIs without having to code my own Date and Time utility classes. Here's a couple of annoying things I just ran into:
0-based months. I realize that best practice is to use Calendar.SEPTEMBER instead of 8, but it's annoying that 8 represents September and not August.
Getting a date without a timestamp. I always need the utility that Zeros out the timestamp portion of the date.
I know there's other issues I've had in the past, but can't recall. Feel free to add more in your responses.
So, my question is ... What third party APIs do you use to simplify Java's usage of Date and Time manipulation, if any? Any thoughts on using Joda? Anyone looked closer at JSR-310 Date and Time API?
java.time
Java 8 and later now includes the java.time framework. Inspired by Joda-Time, defined by JSR 310, extended by the ThreeTen-Extra project. See the Tutorial.
This framework supplants the old java.util.Date/.Calendar classes. Conversion methods let you convert back and forth to work with old code not yet updated for the java.time types.
The core classes are:
InstantA moment on the timeline, always in UTC.
ZoneIdA time zone. The subclass ZoneOffset includes a constant for UTC.
ZonedDateTime = Instant + ZoneIdRepresents a moment on the timeline adjusted into a specific time zone.
This framework solves the couple of problems you listed.
0-based months
Month numbers are 1-12 in java.time.
Even better, an Enum (Month) provides an object instance for each month of the year. So you need not depend on "magic" numbers in your code like 9 or 10.
if ( theMonth.equals ( Month.OCTOBER ) ) { …
Furthermore, that enum includes some handy utility methods such as getting a month’s localized name.
If not yet familiar with Java enums, read the Tutorial and study up. They are surprisingly handy and powerful.
A date without a time
The LocalDate class represents a date-only value, without time-of-day, without time zone.
LocalDate localDate = LocalDate.parse( "2015-01-02" );
Note that determining a date requires a time zone. A new day dawns earlier in Paris than in Montréal where it is still ‘yesterday’. The ZoneId class represents a time zone.
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
Similarly, there is a LocalTime class for a time-of-day not yet tied to a date or 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
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.
This post has a good discussion on comparing the Java Date/Time API vs JODA.
I personally just use Gregorian Calendar and SimpleDateFormat any time I need to manipulate dates/times in Java. I've never really had any problems in using the Java API and find it quite easy to use, so have not really looked into any alternatives.
The Apache Commons Lang project has a DateUtils class that performs helpful Date operations.
I use DateUtils.truncate() a lot, which will "zero out" parts of the Date for you (helpful if you want your Date object to, say, represent a date and not include any time information). Each method works for both Date and Calendar objects too.
http://commons.apache.org/lang/
I've been using Joda exclusively for three years now and would definitely recommend it - it has the whole area covered with an interface that 'does what it says'.
Joda can look complex when you start, as eg it has concepts of periods, duration and intervals which look sort of similar, but you can start off simply by substituting org.joda.time.DateTime (or org.joda.time.DateMidnight) for java.util.Date in your code, and sticking with the many useful methods that those classes contain, before understanding the other areas.
Im using GregorianCalendar - always and everywhere. Simple java.util.Date is too complex, yeah.
So, my advice is - use GC, its simple
It's the same in javascript. Someone must have been smoking something when they think it's a good idea to let 2008 mean the year 2008, 31 to mean the 31st day in the month, and - this is the best part - 11 to mean the 12th month.
On the other hand, they got it right on two out of three.
The thing that always gets me with Java is the date time library. I've never used Joda, just briefly look at it, looks like its a pretty good implementation, and if I understand JSR-130 correctly its taking knowledge from Joda and eventually having it included in JavaSE.
Quite often for past projects I've wrapped the Java date time objects, which in itself was quite a task. Then used the wrappers for date manipulation.
Date APIs are very difficult to design, especially if they have to deal with localization. Try to roll your own and see, it's worth doing at least once. The fact that Joda was able to do such a good job is a real credit to its developers. To answer your question, I've heard nothing but good things about that library, though I have never played around with it myself.
A lot of programmers begin by using Date, which has numerous deprecated overloaded constructors (making it difficult to use), but once you figure out GregorianCalendar it becomes a little bit easier to manage. The example here is pretty helpful:
http://java.sun.com/j2se/1.4.2/docs/api/java/util/GregorianCalendar.html
It's really simple to write your own date API which sits on top of the raw Java classes, Date and Calendar. Basically both date and Calendar suffer from the fact that they are trying to cram two concepts into one class:
Date (i.e. Year-Month-Day)
Instant (i.e. currentTimeMillis)
When you understand this, it will just revolutionize how you handle date-like concepts in your code. Things will be simpler, clearer, better. In every sense!
For me, Joda is over-complicated, at least for the overwhelming majority of purposes and I particularly don't like the fact that they have gone against standard Java forms, one example being how they parse and format dates. Stephen Colebourne, the guy behind JODA, is the spec lead of JSR-310 and this suffers from the same problems imho (I've followed and contributed to the discussions for the last few years).
Do it yourself; it's easy. Just fill in the following classes: MyDate (wrapping year-month-day), Month (an enum), TimeOfDay (hour-min-sec-millis), DayOfWeek (enum), Instant (wrapping a long). Always consider time-zones when converting between Instants and Dates.
If this seems daunting, you can use Calendar and SimpleDateFormat under the hood. You'll do this in a day and never regret it.