Is there a good date parser for Java? - java

Does anyone know a good date parser for different languages/locales. The built-in parser of Java (SimpleDateFormat) is very strict. It should complete missing parts with the current date.
For example
if I do not enter the year (only day and month) then the current year should be used.
if the year is 08 then it should not parse 0008 because the current year pattern has 4 digits.
Edit: I want to parse the input from a user. For example if the locale date format of the user is "dd.mm.yyyy" and the user type only "12.11." then the parser should accept this as a valid date with the value "12.11.2008". The target is a good usability.

Check Joda Time, and its Freaky Formatters.
Java 8 includes JSR-310 so that could be a solution as well.

From 43642, although not necessarily a duplicate:
See Apache Commons' DateUtils. There's a parseDate method that takes your String and multiple patterns to try and spits out a Date instance.

(Edited for clarity.)
Personally, I think strict is good. So many different situations call for different rules around relaxed parsing, it's impossible to really put that into a common library comprehensively.
However, I would thoroughly recommend Joda Time instead of the built-in date/time classes in general. Their formatters and parsers are thread-safe and immutable, which helps too. Joda Time has some support for relaxed parsing, as shown in the other answer, but you should expect to have to provide some of the rules yourself.

I would say JChronic if you're looking for something that will parse dates from natural "fuzzy" human input.
I've used both JChronic and Chronic (the original Ruby version) with great success.

tl;dr
java.time.format.DateTimeFormatterBuilder::parseDefaulting
java.time
The DateTimeFormatter class parses strings into date-time objects.
You can create customized instances of DateTimeFormatter by using the DateTimeFormatterBuilder class. That builder class enables you to specify default values for missing components of the input string.
DateTimeFormatter f =
new DateTimeFormatterBuilder()
.appendPattern( "MM-dd" )
.parseDefaulting(
ChronoField.YEAR ,
ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ).getYear()
)
.toFormatter() ;
String input = "01-23" ;
LocalDate ld = LocalDate.parse( input , f ) ;
System.out.println( ld ) ;
ld.toString(): 2018-01-23
See also DateTimeFormatterBuilder with specified parseDefaulting conflicts for YEAR field.
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.

The POJava project on SourceForge has a DateTime object that parses dates from multiple languages (when month is specified as a name) and is configurable between MM-DD-YYYY and DD-MM-YYYY. It parses dates heuristically, picking out the most likely year, month, date, hour, minute, second, and time zone rather than supporting predefined formats. The jar file is about 60K in size.
There is ambiguity in interpretation of a date like "10-08" in that it could be intended as shorthand for either "2008-10-08" or "Oct 2008". You could append the year yourself if you are accepting the sort of shorthand you give in your example.
Proj: POJava
Docs: HOWTO use DateTime

Your first requirement has been answered by Basil Bourque.
if I do not enter the year (only day and month) then the current year should be used.
if the year is 08 then it should not parse 0008 because the current year pattern has 4 digits.
DateTimeFormatter allows us to specify the optional patterns inside square brackets. For the second requirement, you can specify the optional pattern, [.[uuuu][uu]] while building the DateTimeFormatter.
Demo:
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Replace JVM's ZoneId, ZoneId.systemDefault() with the applicable one e.g.
// ZoneId.of("Europe/Berlin")
int defaultYear = LocalDate.now(ZoneId.systemDefault()).getYear();
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendPattern("dd.MM[.[uuuu][uu]]")
.parseDefaulting(ChronoField.YEAR, defaultYear)
.toFormatter(Locale.ENGLISH);
// Test
Stream.of(
"12.11",
"12.11.21",
"12.11.2021"
).forEach(s -> System.out.println(LocalDate.parse(s, dtf)));
}
}
Output:
2021-11-12
2021-11-12
2021-11-12
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Use DateFormat ... Current standard until the welcome respite of Joda.

I tried to implement an extensible PHP's strtotime in Java in this answer

Calendar is usually the way to go, but understand that most Java Date management will be handled on your part if you want it done properly. Timezone is a good thing to look into if you have to manage international/cross-zone info. Joda Time is also a neat thing and is the inspiration behind the new suggested Date/Time concepts to be added to Java in JSR 310.
Hope this is helpful.

I would have to say +1 for JodaTime. In addition to parsing, Joda makes just about every date-related operation better.

Related

Unexpected exception while parsing date

I am trying to parse the date according to the following code but getting exception. Below is the code -
public class DateTest {
public static void main(String args []) {
String start = "23-Jan-2017";
DateFormat dateFormatTripStartDate = new SimpleDateFormat("dd-MMM-yyyy hh:mm a");
try {
Date parsedDate = dateFormatTripStartDate.parse(start);
System.out.println(parsedDate);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Exception :
java.text.ParseException: Unparseable date: "23-Jan-2017"
at java.text.DateFormat.parse(DateFormat.java:357)
at DateTest.main(DateTest.java:18)
Kindly help me identify the problem. Thanks.
Remove the time part in your pattern:
DateFormat dateFormatTripStartDate = new SimpleDateFormat("dd-MMM-yyyy");
tl;dr
LocalDate.parse(
"23-Jan-2017" ,
DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US )
)
Using java.time
Other Answers are correct about formatting pattern mismatching input data. But both the Question and other Answers are outdated.
The modern way is with java.time classes that supplant the troublesome old date-time classes.
The LocalDate class represents a date-only value without time-of-day and without time zone.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US );
LocalDate ld = LocalDate.parse( "23-Jan-2017" , f );
ld.toString(): 2017-01-23
Specify the Locale as that determines the human language used to translate the name of the month. If omitted the JVM’s current default Locale is used implicitly. That default can be changed at any moment by any code in any thread of any app within the JVM, so do not rely upon it.
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, andfz more.
First of all, the answer from kamehl23 is correct. Your parsed string may not be missing any parst that are specified in format and thus you will need to modify your format to DateFormat dateFormatTripStartDate = new SimpleDateFormat("dd-MMM-yyyy"); However just to add few more interesting options: Remember that SimpleDateFormat is not thread safe and in general not recommended. Sensible pre Java 8 options are Apache FastDateFormat and joda-time package. Both have some problems but certainly by far better then SimpleDateFormat (Joda-time package is very popular). In Java 8 a new date and time hanling was introduced with package java.time.format It takes time to adjust to it but it works wonderful and resolves many problems that existed in that area. See class DateTimeFormatter.And finally, I once had to write a utility that can take a String in any format and attempt to parse it to Date if possible. I wrote an article that describes how I implemented that Utility. I wrote it in Java 8, but the idea could be implemented in any version. See Java 8 java.time package: parsing any string to date
You are using pattern "dd-MMM-yyyy hh:mm a". But in actual "hh:mm a" part is not present in the "23-Jan-2017" value. Because of this parse function is not able to parse the String date.
So change your pattern to "dd-MMM-yyyy" which matches your date string. This will remove the exception you are getting.

Why is my Java Calendar.setTime() sporadically setting wrong times?

Using this code below, I noticed that sometimes the date gets formatted incorrecty. And to make it even more weird, sometimes timeStamp will have the right date, and timeStampCopy will have the wrong date, and visa versa.
public static Timestamp method(String date, DateFormat dateFormat) throws Exception {
// date is always "2017-02-17"
// original
GregorianCalendar gCal = new GregorianCalendar();
gCal.setTime(dateFormat.parse(date));
Timestamp timeStamp = new Timestamp(gCal.getTimeInMillis());
// copy
GregorianCalendar gCalCopy= new GregorianCalendar();
gCalCopy.setTime(dateFormat.parse(date));
Timestamp timeStampCopy = new Timestamp(gCalCopy.getTimeInMillis());
if (!timeStamp.toString().contains("2017-02-17"))
System.out.println(timeStamp.toString());
if (!timeStampCopy.toString().contains("2017-02-17"))
System.out.println(timeStampCopy.toString());
return timeStamp;
}
I'm not sure what could be causing it but I tried this using a Date object and am having the same issues. I thought it could be a parsing issue but since it's doing the same thing twice I'm not sure.
Below are some of the values that I'm getting:
timeStamp is: 2017-02-17 00:00:00.0
timeStampCopy is: 1700-02-17 00:00:00.0
You say that you are sharing the DateFormat instance between threads.
According to the Javadoc:
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
Note that this refers to external synchronization of access to the DateFormat instance, not the method. Making the method synchronized would only fix this problem if there are no other uses of the DateFormat instance.
You can either:
Explicitly synchronize around all code using the DateFormat instance (it is worth adding an #GuardedBy annotation to the variable, in order to document that you expect a lock to be held before using it);
Change the variable type to ThreadLocal<DateFormat> (and initialize the shared variable appropriately), which ensures that each thread has its own copy of the DateFormat.
The latter approach has lower contention, because each thread can proceed independent of the others. It also means that you can't accidentally omit the synchronization.
But, there are better libraries for handling dates and times, which were designed with the hindsight of problems like DateFormat's lack of thread safety. In Java 8, there is the java.time API; for earlier versions of Java, there is Jodatime.
The Answer by Turner is correct and should be accepted.
java.time is thread-safe
The java.time classes solve this problem by using immutable objects and making them inherently thread-safe.
LocalDate ld = LocalDate.of( "2017-02-17" );
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ld.atStartOfDay( z );
Generate a string in standard ISO 8601 format by calling toString. For other formats, use DateTimeFormatter class. Search Stack Overflow for many examples and discussions. No worries about threads, all thread-safe.
For a value in UTC, extract an Instant.
Instant instant = zdt.toInstant() ;
No need to use java.sql.Timestamp. Modern JDBC drivers can handle the java.time types via toObject and setObject methods. For older drivers convert using new methods added to the old classes.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
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.

Java Dates - What's the correct class to use?

So the whole Java Date/Calendar/GregorianCalendar thing is obviously a joke. What's the right Date class to use?
Edit: Building an SDK for third parties on Android where the application needs to provide a date
More Edit: Things that make this so obviously a joke:
99% of Date is deprecated
Date's Year is offset from 1900
Date's Month is zero-indexed while day is one-indexed
Dates are mutable
You're supposed to use a Calendar to create a date...
... except you really have to use a GregorianCalendar
Do a significant percent of developers want to use a different calendar?
Calendar.getTime() returns a Date
There's no Date math (like how far apart are two dates in years)
Messing with milliseconds since epoch doesn't count
You can't chain parts together to get an expression (like the date one year ago today)
Probably more stuff
Joda-Time. Even on Android.
If you want to stick to Java SE classes, it depends on what you're trying to do.
Edit: You keep changing your question. Date and Calendar.
Avoid the legacy date-time classes
So the whole Java Date/Calendar/GregorianCalendar thing is obviously a joke.
Yes, the old date-time classes bundled with the earliest versions of Java are an awful mess. Badly designed, clumsy attempts at improvements, many hacks.
But to be fair, those classes were a valiant effort in addressing a surprisingly tricky topic that the entire information industry has ignored for decades. Based on prior work at Taligent and IBM, the authors of those classes at least made an attempt where virtually all other programming languages, platforms, and tools take a pass with only the barest minimum of support for date-time handling.
Fortunately we now have the industry-leading java.time classes (JSR 310) built into Java 8 and later. These were inspired by the success of the Joda-Time project. Indeed both efforts were led by the same man, Stephen Colebourne.
java.time
Every single one of your bullet items of complaint is rectified by using java.time instead.
99% of Date is deprecatedInstant replaces java.util.Date. AFAIK, nothing is deprecated in java.time in Java 8 & Java 9.
Date's Year is offset from 1900Years have sane numbering in java.time, 2018 is the year 2018.
Date's Month is zero-indexed while day is one-indexedMonths have sane numbering in java.time, 1-12 for January-December. Even better, the Month enum provides objects to represent each month of the year rather than a mere integer number. So you get valid values, type-safety, and self-documenting code.
Dates are mutableVirtually all of java.time is immutable. Any calls to alter some aspect of a java.time object returns a new and distinct object. Even constructors are hidden, with static factory methods used instead.
You're supposed to use a Calendar to create a date...ZonedDateTime replaces java.util.Calendar.
... except you really have to use a GregorianCalendarZonedDateTime replaces java.util.GregorianCalendar too. The java.time framework uses interfaces mostly for internal-use only, encouraging apps to use only the concrete classes. This was a design decision specific to the needs of java.time as a framework and does not mean you should the same in your apps.
Do a significant percent of developers want to use a different calendar?Yes. Other calendaring systems are used by many people around the globe. The java.time framework provides for this via the Chronology interface and AbstractChronology class. The default chronology is IsoChronology following the ISO 8601 standard used generally in the West. In Java 8 & 9, other bundled chronologies include Thai Buddhist, Hijrah (Islamic), Minguo (Taiwan), and Japanese Imperial. Third-parties may implement others. In the ThreeTen-Extra project, you’ll find additional chronologies for Accounting (proleptic 52/53-week per US IRS Publication 538 and the International Financial Reporting Standards), the British Julian-Gregorian cutover, Coptic (Christian Egypt), Discordian (Erisian), Ethiopic, International Fixed (Cotsworth plan, the Eastman plan), proleptic Julian, Pax, and Symmetry010 & Symmetry454. If only someone would implement the French Republican Calendar.
Calendar.getTime() returns a DateJust use Instant as your basic building-block class in java.time, always representing a moment in UTC with a resolution of nanoseconds. The other types such as OffsetDateTime & ZonedDateTime can convert back-and-forth with Instant.
There's no Date math (like how far apart are two dates in years)The java.time classes have many convenient plus…/minus… methods. Furthermore, java.time provides powerful TemporalAduster implementations as well as enabling you to write your own. Also look to the ChronoUnit::between method, such as ChronoUnit.YEARS.between( thisLocalDate , that LocalDate ).
Messing with milliseconds since epoch doesn't countLook to Instant::toEpochMilli and Instant.ofEpochMilli if you must use count-from-epoch, but certainly not advisable. Better to use java.time objects and ISO 8601 strings to represent date-time values.
You can't chain parts together to get an expression (like the date one year ago today)The java.time classes are definitely designed for call-chaining. Example: LocalDate.now( ZoneId.of( "Europe/Paris" ) ).minusYears( 1 ).getDayOfWeek().getDisplayName( TextStyle.FULL , Locale.FRANCE ) > dimanche. Sometimes appropriate, but don’t go nuts with it — that’s my advice.
Probably more stuffYes many more problems with the old legacy classes. You will find java.time to be a radical departure from the old stuff, thoroughly modern and well-designed, a gigantic improvement.
One of the other problem areas is exchanging date-time values with a database. Note that with a JDBC driver compliant with JDBC 4.2 or later (JSR 221), you can avoid the date-time related java.sql classes such as java.sql.Timestamp classes. Those old classes are related to the troublesome old legacy classes, and are no longer needed.
myPreparedStatement.setObject( … , instant ) ;
…and…
Instant instant = myResultSet.getObject( … , Instant.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.
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 "right" date type totally depends on your application; however, java.util.Calendar is generally accepted as the replacement for java.util.Date as it provides more functionality (especially regarding extraction of individual date elements like year, month, etc). In reality, Date can be much easier to use for certain situations (and is the one used by Java's own DateFormat classes), so it's a judgement call.
It's not difficult to convert between the two so I would pick one and stick with it consistently for your API. If I were to pick one I'd use Date because it's the simplest, IMHO.

How to get Date pattern from Timezone of Locale in Java

I have a timezone, and Locale of the user. Now I want to get the date pattern.
For example: User's timezone PST and Locale US and the pattern I expect is "MM/dd/yyyy" and if the user's timezone is IST and Locale India, then pattern I expect is "dd/MM/yyyy"
How to get this?
Note: I want to get the pattern not the actual date so that I can use this in some other place.
The logic translating Locale to date/time formats is burried in java.text.SimpleDateFormat#SimpleDateFormat constructor, precisely in sun.util.resources.LocaleData#getDateFormatData. This method provides ResourceBundle which is then queried for particular pattern depending on which style was chosen.
In other words - unfortunately JDK doesn't seems to provide an API/SPI to access raw formats. My advice is to use the Locale all along and pass it to formatting/parsing methods.
Really do you need the TZ for date pattern? The usual way is having the data pattern in the localized properties file for a locale (or locale_country). I think it is enough.
java.time
The modern solution use the java.time classes that years ago supplanted the terrible legacy classes such as SimpleDateFormat. Specifically replaced by DateTimeFormatter.
Skip the formatting pattern, let java.time localize automatically
You asked:
I have a timezone, and Locale of the user. Now I want to get the date pattern.
There is no need to actually obtain the formatting pattern used by a particular locale.
The .ofLocalized… methods on DateTimeFormatter return a formatter object that can automatically localize the text representing the the date-time object’s value. So you don't need to see the pattern, just ask for generated textual result.
The FormatStyle object controls how long or abbreviated the text. The Locale determines the human language and cultural norms to use in localizing.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f =
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( locale )
;
String output = zdt.format( f ) ;
Dump to console.
System.out.println( zdt.toInstant().toString() ) ; // Adjust to UTC.
System.out.println( zdt.toString() ) ; // Generate text in standard ISO 8601 format extended wisely to append the name of the time zone in square brackets.
System.out.println( output ) ; // Automatically formatted content.
See this code run live at IdeOne.com.
2020-07-13T23:26:40.554180Z
2020-07-14T08:26:40.554180+09:00[Asia/Tokyo]
mardi 14 juillet 2020 à 08 h 26 min 40 s heure normale du Japon
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. Hibernate 5 & JPA 2.2 support java.time.
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 brought 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 (26+) bundle implementations of the java.time classes.
For earlier Android (<26), a process known as API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
It sounds like you want the static getInstance methods on DateFormat. They take an integer constant for style (short, long, etc.), and optionally a different Locale (instead of the JVM's default).
you can use Interface Map
the k will be Locale
the v will be a string with the date pattern
If you're using Joda Time (and why wouldn't you if you have any choice? It nearly got bundled into JDK 1.7) you could do something like this:
String patternForStyleAndLocale = org.joda.time.format.DateTimeFormat.patternForStyle("S-", locale);
Which unfortunately only gives a two digit year. One work around for that would be:
if (!org.apache.commons.lang.StringUtils.contains(patternForStyleAndLocale, "yyyy"))
{
// The default Joda pattern only has a two digit year for US and Europe, China etc - but we want four digit years
patternForStyleAndLocale = StringUtils.replace(patternForStyleAndLocale, "yy", "yyyy");
}
And you could consider caching them in a ConcurrentHashMap<Locale, String>.
The nice thing about getting a numeric date as a pre-localised pattern like this is that it doesn't require any further localisation later, as it would do if you were using a pattern such as:
"dd MMM yyyy" // UK: "25 Dec 2010" FRANCE: "25 déc. 2010" etc..
However... I just noticed from your later comment that you want to pass the pattern to JavaScript - that might get very difficult since JS uses different pattern formatting to Java (ISO date for instance is "yyyy-MM-dd" in Java and "yy-mm-dd" in JS). I've not tried solving that one but I'd probably use a some string mapping in the JS or Java to simply map from Java patterns to JS. You'd have to know each of the patterns you might encounter for each of the languages in advance of course.

A non-deprecated exact equivalent of Date(String s) in Java?

I have old code that uses new Date(dateString) to parse a date string. Compiling the code produces the deprecation warning Date(java.lang.String) in java.util.Date has been deprecated.
The javadoc unhelpfully advises me to use DateFormat.parse(), even though the DateFormat class does not have a static parse method.
Now, I know how to use SimpleDateFormat, but I want to make sure I'm getting the exact same behaviour of the deperecated Date constructor.
Here's my guess (I posted as community wiki so you can vote up if I'm right):
Date parsed;
try {
SimpleDateFormat format =
new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
parsed = format.parse(dateString);
}
catch(ParseException pe) {
throw new IllegalArgumentException(pe);
}
SimpleDateFormat is the way to go. Can I point out, however, that you may feel compelled to define one SimpleDateFormat instance and build Date objects using this. If you do, beware that SimpleDateFormat is not thread-safe and you may be exposing yourself to some potentially hard-to-debug issues!
I'd recommend taking this opportunity to look at Joda which is a much better thought-out (and thread-safe) API. It forms the basis of JSR-310, which is the new proposed Java Date API.
I understand this is a bit more work. However it's probably worthwhile given that you're having to refactor code at the moment.
If you take a look at source of the Date.parse(String s) method that Nicolas mentions, you'll see that it will be difficult or impossible to construct a date format that exactly reproduces the behavior.
If you just want to eliminate the warning, you could put #SuppressWarnings({“deprecation”}) outside the method calling the Date(String) constructor.
If you really want to ensure future access to this behavior with future JREs, you might be able to just extract the method from the JDK sources and put it into your own sources. This would require a careful read of the source code licenses and consideration of their application to your specific project, and might not be permissible at all.
DateFormat has static methods that return DateFormat instances. I don't know which one (if any) has the same behavior as Date(String s) but here you go:
DateFormat.getInstance()
DateFormat.getDateInstance()
DateFormat.getTimeInstance()
DateFormat.getDateTimeInstance()
Short answer (before further investigation) is: no, it is not equivalent. the Date(String toParse) constructor is equivalent to the parse method of the class Date (which is also deprecated)... And the javadoc of this method claims:
Note that this is slightly different from the interpretation of years less than 100 that is used in SimpleDateFormat.
If it is the only change, I guess you can go on this way.
To parse a date time string in ISO format you should use the DateFormat like this:
java.text.DateFormat.getDateInstance().parse(dt);
With SimpleDateFormat you need to know the format.
tl;dr
ZonedDateTime.format(
input ,
DateTimeFormatter.ofPattern(
"EEE MMM dd HH:mm:ss zzz uuuu" ,
Locale.ENGLISH
)
)
java.time
The terrible Date and DateFormat classes were supplanted years ago by the modern java.time classes with the adoption of JSR 310.
The constructor you reference is actually calls on the static method Date.parse. As that documentation explains, that method takes a variety of formats. There is single point for the same behavior in java.time. However, I would doubt your app is encountering all those various format syntaxes simultaneously.
I suggest you look at the specific formats used by your actual data. Then craft a collection of DateTimeFormatter objects to match. Note that unlike the legacy classes, the java.time classes are entirely thread-safe. So you can keep one set of formatters around for use repeatedly throughout your app and across threads.
For the formatting pattern shown in the accepted Answer, here is the equivalent in java.time using the DateTimeFormatter class. Note that you should explicitly state your desired/expected locale rather than rely implicitly on the JVM’s current default locale.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE MMM dd HH:mm:ss zzz uuuu" , Locale.ENGLISH ) ;
ZonedDateTime zdt = ZonedDateTime.format( input , f ) ;
You should avoid using the legacy date-time classes such as java.util.Date wherever possible. But if you must have a Date to interoperate with old code not yet updated to java.time, you can convert. Look to new conversions methods added to the old classes.
The misnamed java.util.Date represents a moment in UTC. Its modern equivalent
is the java.time.Instant class. We can extract an Instant from our ZonedDateTime. Then convert to a Date.
Instant instant = zdt.toInstant() ; // Adjust from time zone to UTC.
java.util.Date d = Date.from( instant ) ; // Convert from modern class `Instant` to legacy class `Date`.
Going the other direction.
Instant instant = d.toInstant() ; // Convert from legacy class `Date` to modern class `Instant`.
ZonedDateTime zdt = instant.atZone( ZoneId.of( "Pacific/Auckland" ) ) ; // Adjust from UTC to the wall-clock time used by the people of a particular region (a 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.
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.

Categories

Resources