Subtract 1 month from a date string in the dd/mm/yyyy format

Asked

Viewed 131 times

0

String data = "09/04/2021";
String charComeco   = data.substring(0, 2);
String charMeio = data.substring(3, 5); 
Integer  meioTratado2 = Integer.parseInt(charMeio);
meioTratado2 -=1;
System.out.println(meioTratado2);

//Após retirar 1 da data, ela perda o 0 do começo, preciso diminuir 1 mês dessa data e mandar novamente com o 0, ficando assim => 09/03/2021

String charFinal = data.substring(6, 10);
data = "'"+ charComeco + "'" + meioTratado2 + "'" + charFinal + "'";
System.out.println(data); //'09'4'2021'

I would also like review for improvement in the code, thank you.

  • 2

    Use the package classes time. Basically, take the String and convert to LocalDate, Remove required amount, then convert to String again.

3 answers

1

Just to complement the other answers, it’s worth explaining why it’s better to use a date API instead of manipulating the string directly.

First because, in addition to giving more work, string manipulation does not guarantee that the date is valid (neither the one you receive, nor the final result).

For example, if the month is January (01) and you simply subtract 1, the result will be zero, so the initial date was 09/01/2020, the result would be something like 09/00/2020. That is, a completely invalid date.

What if the initial date was 31/03/2020? When subtracting 1 of the month, the result would be 31/02/2020 (February 31, completely wrong).

Of course you can even make the proper adjustments manually, but there are already date Apis to deal with these cases for you. The other advantage is that this same API also validates the date, which ensures that you will know if you pass an invalid date:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;

...
String data = "09/04/2021";
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd/MM/uuuu")
    .withResolverStyle(ResolverStyle.STRICT);
// faz o parsing da data e subtrai 1 mês
LocalDate dt = LocalDate.parse(data, fmt).minusMonths(1);
String dataFinal = fmt.format(dt);
System.out.println(dataFinal); // 09/03/2021

I used ResolverStyle.STRICT so that it accepts only valid dates. Without this, the behavior default is accept dates like April 31st (which is automatically adjusted to April 30th, see here an example). Using the mode STRICT, April 31 launches an exception (DateTimeParseException, that you can put in a block try/catch if you want).

I also used uuuu instead of yyyy next year, read here to know the difference.


It is worth remembering that date arithmetic is "bizarre" and often counter-intuitive. For example, if the date is March 31, 2020, the result of subtracting 1 month is February 29, 2020 (as February does not have 31 days, the adjustment is made for the last day of the month). The same is true if we subtract 1 month from 29 or 30 March 2020, the result will also be 29 February 2020 (and if the year was not leap, the adjustment would be made for the 28th).

If you want different results, you will have to adjust manually, because this is the way the API does the calculations.


Java <= 7

The above code holds for Java >= 8, as the API java.time does not exist in previous versions.

For Java 6 and 7, you can use Threeten Backport, which is a backport of java.time. Basically, it has the same classes and methods, the difference is that they are in the package org.threeten.bp, instead of java.time. More details at the end of this answer.

But if you don’t want to use an external library, one option is to use the old API: java.util.Date, java.util.Calendar and java.text.SimpleDateFormat.

String data = "09/04/2021";

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
sdf.setLenient(false); // para não aceitar datas inválidas

Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(data));
cal.add(Calendar.MONTH, -1); // subtrai 1 mês

String dataFinal = sdf.format(cal.getTime());
System.out.println(dataFinal); // 09/03/2021

I used setLenient(false) not to accept invalid dates (otherwise 31 April is set to 1 May). In the non lenient mode, invalid dates throw a java.text.ParseException.

  • Carai '0', I need time to finish reading all this and thank you for the knowledge.

1

Good night David,

if you want to use the java.time libraries, we can resolve it as follows:

public class SubtrairUmMesDaData {

public static void main(String[] args) {
    String date = LocalDate.of(2020,4,9)
            .minusMonths(1).format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));

    System.out.println(date);
}

}

We transform the entry into Localdate, subtract a month and format to the desired pattern.

I hope I’ve helped.

  • Speak man, thanks for your help :)

0


A functional example:

package data;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class ModificarData {

    public static void main(String[] args) {
        String entrada = "04/03/2020";

        // Formatador de data
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
        
        // Converte a string para LocalDate e remove 1 mês
        LocalDate date = LocalDate.parse(entrada, formatter);
        date = date.minus(1, ChronoUnit.MONTHS);

        // Reatribui a string com o LocalDate.
        entrada = formatter.format(date);
        System.out.println(entrada);
    }
}
  • Speak man, thanks for your help :)

Browser other questions tagged

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