How to format date in full?

Asked

Viewed 10,205 times

11

Is there a Java class that works with date formatting in full?

For example:

Input: [dd/mm/yyyy] 27/02/2016

Check-out: Twenty-seventh February 2016

I tried to:

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Scanner;

public class Exemplo {

  public static void main(String[] args) {
    Scanner ler = new Scanner(System.in);

    String s;

    System.out.printf("Informe o nome da Cidade:\n");
    s = ler.nextLine();

    System.out.printf("\nResultado:\n");
    System.out.printf("%s\n", DataPorExtenso(s, new java.util.Date()));
  }

  public static String NomeDoMes(int i, int tipo) {
    String mes[] = {"janeiro", "fevereiro", "março", "abril",
      "maio", "junho", "julho", "agosto", "setembro", "outubro",
      "novembro", "dezembro"};
    if (tipo == 0)
       return(mes[i-1]); 
    else return(mes[i-1].substring(0, 3)); 
  }


  public static String DiaDaSemana(int i, int tipo) {
    String diasem[] = {"domingo", "segunda-feira", "terça-feira",
      "quarta-feira", "quinta-feira", "sexta-feira", "sábado"};
    if (tipo == 0)
       return(diasem[i-1]); 
    else return(diasem[i-1].substring(0, 3));
  }

  public static String DataPorExtenso(String cidade, java.util.Date dt) {
    int d = dt.getDate();
    int m = dt.getMonth()+1;
    int a = dt.getYear()+1900;

    Calendar data = new GregorianCalendar(a, m-1, d);
    int ds = data.get(Calendar.DAY_OF_WEEK);

    return(cidade + ", " + d + " de " + NomeDoMes(m, 0) + " de " +
      a + " (" + DiaDaSemana(ds, 1) + ").");
  }

}

The exit was:

27 of February of 2016

3 answers

15


To leave in the format you want and with the month in full:

Date data =  new Date();
Locale local = new Locale("pt","BR");
DateFormat formato = new SimpleDateFormat("dd 'de' MMMM 'de' yyyy",local);
System.out.println(formato.format(data));

This will print, for example, 27 de Fevereiro de 2016, I mean, the day is not yet full. I haven’t found anything native of Java that will give you the numbers in full the way you want. But implementing a method that does this is also not very difficult. Follow my version:

public static String getDiaPorExtenso(int dia) throws Exception {
    String dias[] = {"zero", "um", "dois", "três","quatro", "cinco", "seis", "sete", "oito", "nove"};
    String retorno = "";

    if (dia < 1 || dia > 31) {
        throw new Exception("Não existe esse dia em nenhum mês do ano");
    }
    else if (dia < 10) {
        retorno = dias[dia];
    }
    else if (dia < 20) {
        retorno = new String[]{
            "dez", "onze", "doze", "treze", "quatorze", "quinze", "dezesseis", "dezessete", "dezoito", "dezenove"
        }[dia - 10];
    }
    else if (dia < 30) {
        if (dia == 20) {
            retorno = "vinte";
        }
        else {
            retorno = "vinte e " + dias[dia - 20];
        }
    }
    else {
        if (dia == 30) {
            retorno = "trinta";
        }
        else {
            retorno = "trinta e " + dias[dia - 30];
        }
    }

    // Capitaliza apenas a primeira letra do dia.
    return retorno.substring(0, 1).toUpperCase() + retorno.substring(1);
}

By joining the two, you can display the final result as follows:

Date data = new GregorianCalendar(2014, Calendar.FEBRUARY, 11).getTime();
Locale local = new Locale("pt","BR");
DateFormat formato = new SimpleDateFormat(" 'de' MMMM 'de' yyyy", local);
String dataFormatada = formato.format(data);

Calendar calendario = Calendar.getInstance();
calendario.setTime(data);
int dia = calendario.get(Calendar.DAY_OF_MONTH);

System.out.println(getDiaPorExtenso(dia) + dataFormatada);

Exit: Onze de Fevereiro de 2014.

Observing:

Calendar calendario = Calendar.getInstance();
calendario.setTime(data);
int dia = calendario.get(Calendar.DAY_OF_MONTH);

is used instead of the most obvious data.getDate() because this last method is deprecated.

See the full code and running on Ideone.

  • 2

    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.

  • 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

  • @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.

  • 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.

  • Eh, actually what was giving me just the present day was the fact that I didn’t set a Date in the instance of Calendar. I fixed it so that you can specify the date you want now (although in the example is any date, fixed).

0

It could be like this: d 'de' MMMM 'de' yyyy

  • The d returns the numeric value of the day (and not the full text, as the question asks). Also, MMMM may not return the name of the month in Portuguese, if the locale default configured in JVM not for English. Read the other answers to understand better :-)

0

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).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.