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.
Related
The month names start with an uppercase letter instead of lowercase, as they should.
Some sample code I ran on my local machine:
Locale portugal = new Locale("pt");
Locale brazil = new Locale("pt", "BR");
Locale france = new Locale("fr", "FR");
Object[] params = new Object[] { new Date() };
String pattern = "Today is {0,date,long}!";
MessageFormat ptFormat = new MessageFormat(pattern, portugal);
MessageFormat brFormat = new MessageFormat(pattern, brazil);
MessageFormat frFormat = new MessageFormat(pattern, france);
StringBuffer ptResult = ptFormat.format(params, new StringBuffer(), new FieldPosition(0));
StringBuffer brResult = brFormat.format(params, new StringBuffer(), new FieldPosition(0));
StringBuffer frResult = frFormat.format(params, new StringBuffer(), null);
System.out.println("Portugal result: " + ptResult.toString());
System.out.println("Brazil result: " + brResult.toString());
System.out.println("France result: " + frResult.toString());
And this is what I got:
Portugal result: Today is 10 de Julho de 2018!
Brazil result: Today is 10 de Julho de 2018!
France result: Today is 10 juillet 2018!
So the French is correct, but for some reason the two Portuguese variants are not.
Even weirder, I tried adding the exact same code as an IDEAONE snippet, and it wouldn't localize at all.
What am I misunderstanding here?
tl;dr
Different implementations of Java may vary in their rules for localization.
Different versions of an implementation of Java may vary in their rules for localization.
For the Oracle JDK & OpenJDK projects, version 9 and later switched between its own set of rules and the set of rules defined by the Unicode CLDR (see Wikipedia). See Release Notes and see OpenJDK JEP 252.
Run this code:
Month.JULY.getDisplayName( TextStyle.FULL , new Locale( "pt" ) )
In Java 8, Oracle JDK, by default using its own localization rules, we get initial-cap.
Julho
In Java 10, Oracle JDK, by default using Unicode CLDR rules, we get lowercase.
julho
In Java 10, Oracle JDK after setting the VM option -Djava.locale.providers=COMPAT,SPI to revert to legacy behavior rather than using Unicode CLDR, we get initial-cap.
Julho
Details
The formatting rules defined by cultural norms may vary by JVM implementation and version.
The JVM in IdeOne.com refuses to localize. Only US English. See proof.
You are using the wrong classes. Use java.time for all date-time handling.
Code.
ZonedDateTime // Use modern class for a moment seen from a particular time zone.
.now() // Capture the current moment, using the JVM’s current default time zone. Better to specify a zone explicitly.
.format( // Generate a `String` representing the value of our `ZonedDateTime` object.
DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( new Locale( "pt" , "BR" ) )
) // Returns a `String` object.
11 de julho de 2018 17:57:36 NZST
Cultural norms
Deciding an issue such as capitalization of a month name depends on a culture’s norms. Of course, those norms can vary, and reasonable people can disagree.
But at some point, decisions have to be made. A Java implementation must have a set of rules for making these localization rules.
Unicode CLDR
Perhaps you are using Java 8 or earlier. My code in this Answer was produced with Java 10.
One important difference is that as of Java 9, for the Oracle JDK and OpenJDK projects, the default source of localization rules changed to using the Unicode CLDR (see Wikipedia). In Java 8 and earlier, each JVM provided their own set of rules.
Also, note that the Unicode CLDR is updated from time-to-time, and some rules may change.
So, you may well see different results for localization depending on which version of Java is in use, and on which implementation of Java is in use.
Context of presentation
Perhaps the issue here is one of context. In some cultures, the formatting rules such as capitalization of a month name vary by whether the month is being presented alone or embedded within a date.
Let’s try translate.Google.com:
July yields Julho
Early in the month of July yields no início do mês de julho
12th of July, 2018 yields 12 de julho de 2018
So Google seems to vary by context, but I am not certain what is going on with that first case being initial-cap.
This context can be indicated by the use of the TextStyle enum used in Month::getDisplayName method. That enum offers …STANDALONE variations.
Month.JULY.getDisplayName(
TextStyle.FULL ,
new Locale( "pt" )
)
julho
Month.JULY.getDisplayName(
TextStyle.FULL_STANDALONE ,
new Locale( "pt" )
)
julho
So no, context seems to not be an issue here when using Java 10.
java.time
You are using the troublesome old classes now supplanted by the java.time classes.
Instead of java.util.Date, use java.time.Instant. Both represent a moment in UTC. The modern Instant class uses a finer resolution of nanoseconds instead of milliseconds.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
instant.toString(): 2018-07-11T05:57:36.446917Z
Adjust from UTC to the time zone where the people of that region use a particular wall-clock time you desire. Apply a ZoneId to get a ZonedDateTime object. Time zone is completely orthogonal to locale. One relates to the content of the moment, the other affects only the localization used in generating a String to represent that content. You could, for example, use a Japan time zone with a Portuguese locale.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Now, we want to generate strings representing that moment. First, generate a String in standard ISO 8601 format extended by appending the name of the time zone in square brackets.
String output = zdt.toString() ; // Generate ISO 8601 format string.
2018-07-11T17:57:36.446917+12:00[Pacific/Auckland]
You want to localize the generated String objects. Use DateTimeFormatter to control the formatting of the String to be generated. Specify a FormatStyle to control how long or abbreviated.
Locale l_pt = new Locale( "pt" ) ;
Locale l_ptBR = new Locale( "pt" , "BR" ) ;
Locale l_FR = Locale.FRANCE ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ) ;
String output_pt = zdt.format( f.withLocale( l_pt ) ) ;
String output_ptBR = zdt.format( f.withLocale( l_ptBR ) ) ;
String output_FR = zdt.format( f.withLocale( l_FR ) ) ;
quarta-feira, 11 de julho de 2018 17:57:36 Horário Padrão da Nova Zelândia
quarta-feira, 11 de julho de 2018 17:57:36 Horário Padrão da Nova Zelândia
mercredi 11 juillet 2018 à 17:57:36 heure normale de la Nouvelle-Zélande
For fun, let’s try FormatStyle.LONG instead of FULL.
11 de julho de 2018 17:57:36 NZST
11 de julho de 2018 17:57:36 NZST
11 juillet 2018 à 17:57:36 NZSTe
IdeOne refuses to localize
I enjoy using IdeOne.com to demo Java code. Unfortunately, its JVM refuses to use any Locale except US English. So, no go for the code above.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, 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.
A brief history of time
Responding to comments on this Answer…
Timeline:
Sun Microsystems launches Java 1.0 with some date-time classes (java.util.Date etc.) donated by IBM/Taligent. Unfortunately, they are poorly-designed and flawed, confusing and troublesome.
Sun adds more classes in Java 1.1 (java.util.Calendar etc.) in an attempt to improve the date-time handling. But these too turn out to be poorly-designed and confusing, not a real improvement.
Years later, a man Stephen Colebourne founds the Joda-Time project, to make a comprehensive sophisticated date-time handling library, a first in the IT industry afaik. Huge success. One of the most popular Java libraries, added routinely to many developers’ projects.
Sun, then Oracle, and the JCP community finally recognize that the old date-time classes shipped with the earliest versions of Java are not adequate. This recognition opens the door for that same Stephen Colebourne to launch JSR 310, a specification for an all-new date-time API for inclusion as part of the Java platform. This project is based on concepts from Joda-Time, but is an entirely new rewrite. The new rewrite builds on the experience of having created Joda-Time, asking “If we knew then what we know now, how would we have designed Joda-Time?”.
The implementation of JSR 310 is built as the java.time package to be included with the then-upcoming Java 8.
To ensure wider acceptance of the java.time API, Stephen Colebourne launches the open-source ThreeTen-Backport project, mimicking nearly the same API as in java.time but capable of running on Java 6 and Java 7. Not quite all of the java.time functionality, but most of it. The goal is to enable a developer on earlier Java to start using the API. Then when moving to later versions of Java they need do little more than change their import statements from org.threeten.bp.* to java.time.*.
With Java 8 successfully shipping, Stephen Colebourne et al. shift the Joda-Time project into maintenance-mode, still actively updated with tzdata changes and bug fixes, but no further feature work to be done. They advise migration away from Joda-Time and on to the java.time classes.
Stephen Colebourne also launches the open-source ThreeTen-Extra project to work on additional features that may or may not eventually be submitted to later versions of JSR 310 (to become additional java.time classes). Meanwhile, these extra features, extensions to the java.time functionality, are provided as a library to the public for those developers who find them useful.
I'm a little bit frustrated of java 8 date format/parse functionality. I was trying to find Jackson configuration and DateTimeFormatter to parse "2018-02-13T10:20:12.120+0000" string to any Java 8 date, and didn't find it.
This is java.util.Date example which works fine:
Date date = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZZZ")
.parse("2018-02-13T10:20:12.120+0000");
The same format doesn't work with new date time api
ZonedDateTime dateTime = ZonedDateTime.parse("2018-02-13T10:20:12.120+0000",
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SSSZZZ"));
We should be able to format/parse date in any format suitable for FE UI application. Maybe I misunderstand or mistake something, but I think java.util.Date gives more format flexibility and easier to use.
tl;dr
Until bug is fixed:
OffsetDateTime.parse(
"2018-02-13T10:20:12.120+0000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" )
)
When bug is fixed:
OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" )
Details
You are using the wrong classes.
Avoid the troublesome old legacy classes such as Date, Calendar, and SimpleDateFormat. Now supplanted by the java.time classes.
The ZonedDateTime class you used is good, it is part of java.time. But it is intended for a full time zone. Your input string has merely an offset-from-UTC. A full time zone, in contrast, is a collection of offsets in effect for a region at different points in time, past, present, and future. For example, with Daylight Saving Time (DST) in most of North America, the offsets change twice a year growing smaller in the Spring as we shift clocks forward an hour, and restoring to a longer value in the Autumn when we shift clocks back an hour.
OffsetDateTime
For only an offset rather than a time zone, use the OffsetDateTime class.
Your input string complies with the ISO 8601 standard. The java.time classes use the standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
OffsetDateTime odt = OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" );
Well, that should have worked. Unfortunately, there is a bug in Java 8 (at least up through Java 8 Update 121) where that class fails to parse an offset omitting the colon between hours and minutes. So the bug bites on +0000 but not +00:00. So until a fix arrives, you have a choice of two workarounds: (a) a hack, manipulating the input string, or (b) define an explicit formatting pattern.
The hack: Manipulate the input string to insert the colon.
String input = "2018-02-13T10:20:12.120+0000".replace( "+0000" , "+00:00" );
OffsetDateTime odt = OffsetDateTime.parse( input );
DateTimeFormatter
The more robust workaround is to define and pass a formatting pattern in a DateTimeFormatter object.
String input = "2018-02-13T10:20:12.120+0000" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" );
OffsetDateTime odt = OffsetDateTime.parse( input , f );
odt.toString(): 2018-02-13T10:20:12.120Z
By the way, here is a tip: I have found that with many protocols and libraries, your life is easier if your offsets always have the colon, always have both hours and minutes (even if minutes are zero), and always use a padding zero (-05:00 rather than -5).
DateTimeFormatterBuilder
For a more flexible formatter, created via DateTimeFormatterBuilder, see this excellent Answer on a duplicate Question.
Instant
If you want to work with values that are always in UTC (and you should), extract an Instant object.
Instant instant = odt.toInstant();
ZonedDateTime
If you want to view that moment through the lens of some region’s wall-clock time, apply a time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );
See this code run live at IdeOne.com.
All of this has been covered many times in many Answers for many Questions. Please search Stack Overflow thoroughly before posting. You would have discovered many dozens, if not hundreds, of examples.
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.
Short: Not a bug, just your pattern is wrong.
Please use the type OffsetDateTime which is especially designed for time zone offsets and use a pattern this way:
OffsetDateTime odt =
OffsetDateTime.parse(
"2018-02-13T10:20:12.120+0000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSZZZ" )
)
Problems in detail:
a) 12-hour-clock versus 24-hour-clock
"h" indicates the hour of AM/PM on a 12-hour-clock but you obviously need "H" for the 24-hour-clock as required by ISO-8601.
b) The form of zero offset
If you want to parse zero offset like "+0000" instead of "Z" (as described in ISO-paper) you should not use the pattern symbol "X" but "ZZZ". Citing the pattern syntax:
Offset Z: This formats the offset based on the number of pattern
letters. One, two or three letters outputs the hour and minute,
without a colon, such as '+0130'. The output will be '+0000' when the
offset is zero.
c) Your input is NOT ISO-8601-compatible therefore no bug in Java
Your assumption that "2018-02-13T10:20:12.120+0000" shall be valid ISO is wrong because you are mixing basic format (in the offset part) and extended format which is explicitly prohibited in ISO-paper (see sections 4.3.2 (example part) and 4.3.3d). Citing ISO-8601:
[...]the expression shall either be completely in basic format, in which
case the minimum number of separators necessary for the required
expression is used, or completely in extended format[...]
The statement of B. Bourque that java.time has a bug is based on the same wrong expectation about ISO-compatibility. And the documentation of let's say ISO_OFFSET_DATE_TIME describes the support of the extended ISO-format only. See also the related JDK issue. Not all ISO-8601-variants are directly supported hence a pattern-based construction of the parser in the right way is okay.
if offset +0000 try this
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" )
LocalDate from =LocalDate.parse("2018-02-13T10:20:12.120+0000",f);
I have to use a custom date format in Java. It contains microseconds although Java doesn't provide support for microseconds. Because of that I filled the time pattern with zeroes, which work fine when formatting, but I cannot parse date-strings with that pattern.
Is there a simple workaround or must I handle microseconds on my own (with String functions)?
#Test
public void testDateFormat() throws ParseException {
DateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss.SSS000");
String theDate = format.format(new Date());
// this will fail:
format.parse(theDate);
}
java.text.ParseException: Unparseable date: "2010-01-25-12.40.35.769000"
Your problem is that the pattern used in SimpleDateFormat unfortunately have different meanings depending on whether it is used as a parser or as a formatter. As a formatter, your pattern does what is expected, the output will end with the millisecond value formatted as three digits followed by three 0 characters, e.g:
2010-01-25-14.17.47.307000
Used as a parser, the "SSS" pattern will however match an arbitrary number of digits and parse the above example as 307000 ms. After having parsed the ms field, the parser will still look for a "000" substring and fail with an exception, since you've reached the end of the input string, without fulfilling the requirements of the pattern.
Since there is no pattern for a µs value in SimpleDateFormat, you will have to write your own wrapper to strip the input string for the last three 0 characters, before feeding it to SimpleDateFormat.
In addition to jarnbjo's answer, if you need the microseconds, you might be able to use java.sql.Timestamp:
Date dateToMillis = format.parse(theDate.substring(0, 23));
DateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Timestamp timestamp = Timestamp.valueOf(timestampFormat.format(dateToMillis) + theDate.substring(23,26));
tl;dr
LocalDateTime.parse(
"2010-01-25-12.40.35.769000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" )
)
Using java.time
You are using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.
These old classes were limited to tracking milliseconds, three digits of decimal fraction. The modern java.time classes resolve to nanoseconds, for nine digits of decimal fraction.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" ) ;
LocalDateTime ldt = LocalDateTime.parse( "2010-01-25-12.40.35.769000" );
ldt.toString(): 2010-01-25T12:40:35.769
ISO 8601
Tip: Rather than invent your own format to textually represent a date-time value, stick to the standard ISO 8601 formats.
The java.time classes use the standard formats by default. You can see that format in the output above. The T separates the date portion from the time-of-day portion.
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.
Add a '' around the zeros, like so: "yyyy-MM-dd-HH.mm.ss.SSS'000'"
Date and time formats are specified by
date and time pattern strings. Within
date and time pattern strings,
unquoted letters from 'A' to 'Z' and
from 'a' to 'z' are interpreted as
pattern letters representing the
components of a date or time string.
Text can be quoted using single quotes
(') to avoid interpretation. "''"
represents a single quote. All other
characters are not interpreted;
they're simply copied into the output
string during formatting or matched
against the input string during
parsing.
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.
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.