From Java 8 it is possible to use the API java.time
. One of the differences of this API to Date
and Calendar
is that now there are several different classes to represent dates and times. In case, as you are working only with day, month and year, no matter what the time or timezones, can use a java.time.LocalDate
.
For month names, the solution is similar to another answer: use the format MMMM
and the Locale
corresponding to Portuguese.
For the full days, there is not much to escape from a "manual" solution, which builds the text one by one. In this case, you can use a Map
which maps the numerical value to its respective text, and passes it to a java.time.format.DateTimeFormatterBuilder
. In the end we created a java.time.format.DateTimeFormatter
, that we can use to format the date:
Map<Long, String> dias = new HashMap<>();
dias.put(1L, "Primeiro");
dias.put(2L, "Dois");
dias.put(3L, "Três");
// ... adicionar os textos até o dia 31
dias.put(31L, "Trinta e um");
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// mapeamento dos dias para o texto por extenso
.appendText(ChronoField.DAY_OF_MONTH, dias)
// nome do mês e valor numérico do ano
.appendPattern(" 'de' MMMM 'de' uuuu")
// usar Locale referente ao português (para o nome do mês)
.toFormatter(new Locale("pt", "BR"));
LocalDate data = LocalDate.of(2016, 2, 27);
System.out.println(data.format(formatter));
I use ChronoField.DAY_OF_MONTH
to indicate which field will be mapped to a text (in this case, the day of the month), and use the Map
containing the maps between the numerical value and the respective text.
For the name of the month, I use MMMM
, that bears the full name, and use the locale referring to the Portuguese language of Brazil (pt_BR
), so that the month name is correct. If you do not specify a locale, will be used the default which is configured in the JVM, and is not guaranteed to always be Portuguese (including, this can be changed in Runtime if any application calls Locale.setDefault
, affecting all applications running on the same JVM - that is, it is a configuration over which you have no control). So if you already know that the output should be in a specific language, use the respective locale rather than depending on the default.
The question mentions that the entrance will be the string "27/02/2016". If this is the case, then first you must convert this String
for LocalDate
, using another DateTimeFormatter
:
DateTimeFormatter parser = DateTimeFormatter.ofPattern("dd/MM/uuuu");
LocalDate data = LocalDate.parse("27/02/2016", parser);
... formatar a data, usando o código anterior
Only that the DateTimeFormatter
, by default, accepts some invalid values, such as April 31st (and automatically adjusts to April 30th). If you want to be more restricted and only accept valid dates, use a java.time.format.ResolverStyle
:
DateTimeFormatter parser = DateTimeFormatter.ofPattern("dd/MM/uuuu")
.withResolverStyle(ResolverStyle.STRICT);
For more details about the ResolverStyle
, see this answer.
Note also that in the codes above, I used uuuu
instead of yyyy
for the year. Basically, u
and y
differ in the treatment of dates before Christ, and although this does not matter much for current dates, it is more guaranteed to use u
, which already works for both cases. See more details in this answer.
See also all available formats on documentation, paying attention to the fact that not all work exactly the same way SimpleDateFormat
(some new letters have been added, others mean different fields or don’t exactly have the behavior, etc).
Java 6 and 7
For JDK 6 and 7, you can use Threeten Backport, which is an excellent backport of java.time
. The classes and methods are basically the same as in Java 8, the difference being that they are in the package org.threeten.bp
(that is, with the exception of the package name, the code would be the same as the example above).
How is a backport, is not 100% equal: there are some differences for the java.time
, listed in this answer.
Another option to transform the numbers in their respective texts is to use a library for this, for example that one - Although in this case it seems to me an exaggeration to add a new dependency just for that, since there are only 31 text options. Also, how the classes of this API are immutable and thread-safe, you can create only one DateTimeFormatter
static and reuse it throughout the application, for example (without having to convert texts all the time).
Just an addendum: the reason why there is no Java Spell Number API is because it’s extremely localized. Each language has its own rules and variations, so you end up having to implement your routine.
– utluiz
I made substring to take the date and format it using getDiaPorExtenso, would that be the way or is there another more efficient way to catch the day ? example working on https://ideone.com/OEpecb
– Gabriel Rodrigues
@Gabrielrodrigues I had initially done it this way, but after reading your comment I thought of a slightly better way. I added him to the answer.
– tayllan
this DAY_OF_MONTH will pick up the current day, if someone enter with an old date I believe they will not consider. but it is detail.
– Gabriel Rodrigues
Eh, actually what was giving me just the present day was the fact that I didn’t set a
Date
in the instance ofCalendar
. I fixed it so that you can specify the date you want now (although in the example is any date, fixed).– tayllan