Format dates, numbers, and currency values for localization with the NumberFormat and DateFormat classes, including number and date format patterns. - Formatar datas, números e valores monetários para localização utilizando as classes NumberFormat e DateFormat, incluindo padrões de formato de número e data.
Ainda dentro do assunto de Localização e Internacionalização, é comum a necessidade de apresentar datas, números e valores monetários em diferentes formatos.
O exame de certificação compreende cinco classes principais de formatação:
-
NumberFormat→ Formatação geral de números, valores monetários, percentuais e números inteiros com arredondamento, possivelmente baseados emLocale. -
DecimalFormat→ Formatação de números quando há necessidade de definições mais específicas ou personalizadas do formato. -
DateFormat→ Formatação de data e hora antes do Java 8 utilizando formatos predefinidos. -
SimpleDateFormat→ Formatação de data e hora antes do Java 8 utilizando formatos mais específicos ou personalizados. -
DateTimeFormatter→ Formatação de data e hora após o Java 8.
-
É possível obter uma instância de
NumberFormata partir de vários métodos estáticos, dependendo da necessidade.src/org/j6toj8/localization/formats/numberformat/NumberFormat_Instance.javalink:../../../src/org/j6toj8/localization/formats/numberformat/NumberFormat_Instance.java[role=include]
Lembre-se que, se não for informado o
Locale, será utilizado o padrão. O ideal é sempre informar oLocale. -
O
NumberFormatpode ser utilizado para transformar números em Strings.src/org/j6toj8/localization/formats/numberformat/NumberFormat_NumberToString.javalink:../../../src/org/j6toj8/localization/formats/numberformat/NumberFormat_NumberToString.java[role=include]
Saída no consolept_BR: 1.000,05 en_US: 1,000.05 fr_FR: 1 000,05
Perceba que a representação do número muda de acordo com o
Locale. -
O
NumberFormatpor ser utilizado para transformar Strings em números.src/org/j6toj8/localization/formats/numberformat/NumberFormat_StringToNumber.javalink:../../../src/org/j6toj8/localization/formats/numberformat/NumberFormat_StringToNumber.java[role=include]
Saída no consolept_BR: 1000.05 en_US: 100005 fr_FR: 1000.05
Perceba que dependendo do
Localeestamos representando um número diferente, e isso muda o resultado do parse. -
O
NumberFormatpode ser utilizado para transformar Strings em valores monetários, e vice-versa.src/org/j6toj8/localization/formats/numberformat/NumberFormat_Currency.javalink:../../../src/org/j6toj8/localization/formats/numberformat/NumberFormat_Currency.java[role=include]
Saída no consolept_BR: R$ 1.000,05 en_US: $1,000.05 fr_FR: 1 000,05 € pt_BR: 1000.05 Unparseable number: "R$ 1000,05" Unparseable number: "R$ 1000,05"
Perceba que novamente o resultado muda de acordo com o
Locale. Além disso, não é possível converter a representação da moeda brasileira com umLocaleen_USoufr_FR. -
O
NumberFormatpode ser utilizado para transformar Strings em percentuais, e vice-versa.src/org/j6toj8/localization/formats/numberformat/NumberFormat_Percent.javalink:../../../src/org/j6toj8/localization/formats/numberformat/NumberFormat_Percent.java[role=include]
Saída no consolept_BR: 90% en_US: 90% fr_FR: 90 % pt_BR: 0.8 en_US: 0.8 Unparseable number: "80%"
Veja que, ao formatar,
100%é1, logo80%é0,8. Além disso, noLocale fr_FRa representação80%não é válida. -
O
NumberFormatpode ficar complicado ao lidar com vírgulas.src/org/j6toj8/localization/formats/numberformat/NumberFormat_Percent2.javalink:../../../src/org/j6toj8/localization/formats/numberformat/NumberFormat_Percent2.java[role=include]
Saída no consolept_BR: 0.802 en_US: 8.02
No
Locale pt_BRtemos o resultado esperado. Porém, noLocale en_USo80,2%se torna802%pois a vírgula não é usada como separador de decimal.
Enquanto NumberFormat permite utilizar formatos predefinidos, DecimalFormat permite uma personalização maior. Um exemplo de formato para o DecimalFormat é ###,###.###.
-
#→ preenche a posição com um número, ou omite se não houver nada. -
0→ preenche a posição com um número, ou 0 se não houver nada. -
.→ indica onde é a posição do separador decimal. -
,→ indica onde é a posição do separador de grupos.
-
É possível obter uma instância de
DecimalFormatutilizando o construtor.src/org/j6toj8/localization/formats/decimalformat/DecimalFormat_Instance.javalink:../../../src/org/j6toj8/localization/formats/decimalformat/DecimalFormat_Instance.java[role=include]
Saída no console###,###.###: 12.345,67 000,000.###: 012.345,67 ###,###.000: 12.345,670 000,000.000: 012.345,670 ###.##: 12345,67 000000.000: 012345,670 ###: 12346
Estou executando o código onde o
Localepadrão épt_BR, por isso a saída no console apresenta vírgulas para separar grupos e pontos para separar os decimais. -
Para utilizar um
Localeespecífico é necessário instanciar umNumberFormate fazer um cast paraDecimalFormat.src/org/j6toj8/localization/formats/decimalformat/DecimalFormat_Locale.javalink:../../../src/org/j6toj8/localization/formats/decimalformat/DecimalFormat_Locale.java[role=include]
Saída no console12,345.67 -
É possível colocar outros símbolos ou palavras no formato do
DecimalFormat.src/org/j6toj8/localization/formats/decimalformat/DecimalFormat_Strings.javalink:../../../src/org/j6toj8/localization/formats/decimalformat/DecimalFormat_Strings.java[role=include]
Saída no consoleNúmero 12.345,67 formatado
Para formatar Data e Hora antes do Java 8, são utilizadas as classes de DateFormat e SimpleDateFormat. Essas classes trabalham em geral com a classe Date e fazem parte do pacote java.text, diferente de DateTimeFormatter que é do novo pacote java.time.format.
-
Obter instâncias de
DateFormaté muito parecido comNumberFormat. -
É possível definir o formato das instâncias como
SHORT,MEDIUM,LONGouFULL. -
É possível definir o
Localedas instâncias.src/org/j6toj8/localization/formats/dateformat/DateFormat_Instance.javalink:../../../src/org/j6toj8/localization/formats/dateformat/DateFormat_Instance.java[role=include]
Saída no console08/09/2001 22:46:40 08/09/2001 22:46:40 8 de Setembro de 2001 22h46min40s BRT September 8, 2001 10:46:40 PM BRT
-
Também é possível transformar
StringemDateutilizando o métodoparse.src/org/j6toj8/localization/formats/dateformat/DateFormat_Parse.javalink:../../../src/org/j6toj8/localization/formats/dateformat/DateFormat_Parse.java[role=include]
Saída no consoleSat Sep 08 00:00:00 BRT 2001 Thu Jan 01 22:46:00 BRT 1970 Sat Sep 08 22:46:00 BRT 2001 Unparseable date: "08/09/2001"
Perceba que ocorreu uma exceção ao tentar converter uma data utilizando um formatar que espera Data e Hora.
A classe SimpleDateFormat permite criar formatos mais personalizados para apresentar Data e Hora, como dd/MM/yyyy HH:mm:ss. A seguir, as letras mais importantes utilizadas na formatação para o exame:
-
y→ Ano (2019, 19) -
M→ Mês (8, 08, Ago, Agosto) -
d→ Dia (06) -
h→ Hora em formato AM/PM -
H→ Hora em formato 24H -
m→ Minutos -
s→ Segundos
Em geral (existem exceções), quanto mais letras forem utilizadas, mais extenso é o formato apresentado. Por exemplo:
-
M→ 8 -
MM→ 08 -
MMM→ Ago -
MMMM→ Agosto
-
É possível criar formatos personalizados para formatar um
Dateutilizando o construtor deSimpleDateFormat.src/org/j6toj8/localization/formats/simpledateformat/SimpleDateFormat_Instance.javalink:../../../src/org/j6toj8/localization/formats/simpledateformat/SimpleDateFormat_Instance.java[role=include]
Saída no console08 09 01 - 22 46 40 08 09 01 22 46 40
-
Também é possível criar
Datea partir deStringutilizando o métodoparse.src/org/j6toj8/localization/formats/simpledateformat/SimpleDateFormat_Parse.javalink:../../../src/org/j6toj8/localization/formats/simpledateformat/SimpleDateFormat_Parse.java[role=include]
Saída no consoleSat Sep 08 22:46:40 BRT 2001 Sat Sep 08 00:00:00 BRT 2001 Thu Jan 01 22:46:40 BRT 1970 Unparseable date: "22 46 40"
Perceba a exceção ao tentar utilizar o formato incorreto.
O Java 8 traz a classe DateTimeFormatter que possui várias formas de formatar e transformar Data/Hora em String, e vice-versa.
-
É possível obter instâncias predefinidas de
DateTimeFormatter, que representam formatosISOouRFC.src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Predefined.javalink:../../../src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Predefined.java[role=include]
Saída no console2019-08-06 11:40:00 2019-08-06T11:40:00 2019-218 2019-W32-2
-
É possível obter instâncias predefinidas de
DateTimeFormatter, que representam formatos localizados, através da classeFormatStyle.src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_FormatStyle.javalink:../../../src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_FormatStyle.java[role=include]
Saída no console06/08/19 11:40 06/08/2019 11:40:00 06/08/19 11:40
O resultado depende de onde o código está sendo executado. Este código foi executado no
Localepadrãopt_BR. -
É possível alterar o
Localeutilizado peloDateTimeFormatter.src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Locale.javalink:../../../src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Locale.java[role=include]
Saída no console8/6/19 11:40 AM Aug 6, 2019 11:40:00 AM
-
É possível obter instâncias personalizadas de
DateTimeFormatter.src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Custom.javalink:../../../src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Custom.java[role=include]
Saída no console06 08 19 - 11 40 00Para criar um
DateTimeFormatterpersonalizado é necessário conhecer o que cada letra do formato representa. Volte na seção deSimpleDateFormatcaso não se lembre. -
Não é possível formatar uma Data/Hora caso o objeto fornecido não tenha os campos necessários. Um exemplo seria tentar apresentar a Data e fornecer um
LocalTime.src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Error.javalink:../../../src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Error.java[role=include]
Saída no console2019-08-06 2019-08-06 Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: Year at java.time.LocalTime.get0(LocalTime.java:679) at java.time.LocalTime.getLong(LocalTime.java:656) at java.time.format.DateTimePrintContext$1.getLong(DateTimePrintContext.java:205) at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298) at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2551) at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2190) at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746) at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720) at java.time.LocalTime.format(LocalTime.java:1413) at org.j6toj8.localization.formats.datetimeformatter.DateTimeFormatter_Error.main(DateTimeFormatter_Error.java:18)
-
O mesmo erro pode ocorrer ao utilizar um formato personalizado.
src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_ErrorCustom.javalink:../../../src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_ErrorCustom.java[role=include]
Saída no console11 40 00 11 40 00 Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay at java.time.LocalDate.get0(LocalDate.java:680) at java.time.LocalDate.getLong(LocalDate.java:659) at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298) at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2551) at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2190) at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746) at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720) at java.time.LocalDate.format(LocalDate.java:1691) at org.j6toj8.localization.formats.datetimeformatter.DateTimeFormatter_ErrorCustom.main(DateTimeFormatter_ErrorCustom.java:20)
Nesse caso é lançada exceção porque
LocalDatenão possui hora, minuto ou segundo. -
Também é possível fazer o oposto: converter uma
Stringem uma classe deData/Hora. Para isso existem os métodosparse.src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Parse.javalink:../../../src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Parse.java[role=include]
Saída no console2019-08-06T11:40 2019-08-06T11:40 2019-08-06T11:40
-
Todos os métodos utilizados para
formateparsetambém podem ser invocados diretamente na instância doDateTimeFormatter.src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Inverted.javalink:../../../src/org/j6toj8/localization/formats/datetimeformatter/DateTimeFormatter_Inverted.java[role=include]
Saída no console2019-08-06T11:40 2019-08-06T11:40:00 {},ISO resolved to 2019-08-06T11:40 2019-08-06T11:40
Porém, veja que ao utilizar o método
parsediretamente noDateTimeFormatter, é necessário converter o resultado para umLocalDateTime.
-
Adding Internationalizationand Localization
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 255). Wiley. Edição do Kindle.
-
Formatting and Parsing
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 603). Wiley. Edição do Kindle.
-
Lesson: Formatting The Java™ Tutorials.
-
Parsing and Formatting. The Java™ Tutorials.
-
Formatting Numeric Print Output The Java™ Tutorials.