0

This part of code make a sort of conversion from an input like "January 1, 2020" to "01/01". The whole code works perfectly on devices with Android up to Pie and in AVD with devices with Q and R too. When I try to run it on phisycal Android devices with Android Q it doesn't run (I tried with 2 different devices a Mi Note 10 and a OnePlus 6T). I did a check on the debugger and I found this error as soon as it go in the IF loop (I think in the instruction: @SuppressLint("SimpleDateFormat") SimpleDateFormat dt = new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy");"

W/System.err: java.text.ParseException: Unparseable date: "Thu Nov 05 00:00:00 GMT+01:00 2020"

       String[] mese = new String[] {"January","February","March","April","May","June","July","August","September","October","November","December"};
       int a= 0 ;

       while (a < 12){ 
                    if(dato.contains(mese[a])){ 
                             System.out.println("Test 3");
                             DateFormat format = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
                             Date date = format.parse(dato);
                             @SuppressLint("SimpleDateFormat") SimpleDateFormat dt = new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy");
                             Date date2 = dt.parse(String.valueOf(date));
                             @SuppressLint("SimpleDateFormat") SimpleDateFormat dt1 = new SimpleDateFormat("dd/MM");
                             assert date2 != null;
                             dato = dato.replaceAll(dato,dt1.format(date2));
                    }
                    a++;
                }

my pattern is wrong? I tried EEE MMM dd HH:mm:ss zzz yyyy and EEE MMM dd HH:mm:ss zzzz yyyy but same results

Andry
  • 323
  • 1
  • 2
  • 10
  • As an aside consider throwing away the long outmoded and notoriously troublesome `SimpleDateFormat` and friends. See if you either can use [desugaring](https://developer.android.com/studio/write/java8-support-table) or add [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP) to your Android project, in order to use java.time, the modern Java date and time API. It is so much nicer to work with. – Ole V.V. Nov 05 '20 at 17:14
  • I'll try to do that. BTW, still no idea about my issue :/ – Andry Nov 06 '20 at 08:02
  • 1
    As feedback. I totally converted the code using the new Java.time and this solved my compatibility issue with Android Q (and R) on phisycal devices. It seems they don't like SimpleDataFormat – Andry Nov 06 '20 at 10:27
  • Great to hear! I’d love if you would post that as an answer to your own question for other readers to learn from. – Ole V.V. Nov 06 '20 at 10:44

2 Answers2

1

java.time and desugaring or ThreeTenABP

I recommend that you use java.time, the modern Java date and time API, for your date work.

java.time formatters are thread-safe, so we often prefer to declare them static:

private static final DateTimeFormatter sourceFormatter
        = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
private static final DateTimeFormatter targetFormatter
        = DateTimeFormatter.ofPattern("dd/MM");

Now your conversion goes like this:

    String dato = "November 5, 2020";
    LocalDate date = LocalDate.parse(dato, sourceFormatter);
    dato = date.format(targetFormatter);
    System.out.println(dato);

Output:

05/11

What went wrong in your code?

It seems to me that you were doing your format conversion in a way that was more complicated than needed. Rather than checking if there’s a month name in the string, why not just try to parse it? If there wasn’t, my code would throw a DateTimeParseException which you may then catch and handle the way that is appropriate to your situation. Your code was converting your String to Date to String to Date again and to String again. I didn’t understand the reason. Also you were using the SimpleDateFOrmat class. It is notoriously troublesome and long outdated. The second time you parsed from String to Date failed, and I bet I know why: For your first SimpleDateFormat you had remembered to specify Locale.ENGLISH, but you forgot on your second SimpleDateFormat. The string contained Thu and Nov in English, so if your Android Q and R devices had a different language setting, this explains. Finally for your purpose this line:

    dato = dato.replaceAll(dato,dt1.format(date2));

is the same as the simpler:

    dato = dt1.format(date2);

Question: Doesn’t java.time require Android API level 26?

java.time works nicely on both older and newer Android devices. It just requires at least Java 6.

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
  • On older Android either use desugaring or the Android edition of ThreeTen Backport. The latter is called ThreeTenABP. When using ThreeTenABP make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
1

I solved in this way not using anymore SimpleDateFormat:

         while (a < 12){
                    if(dato.contains(mese[a])){

                        String dateInString = dato;
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
                        LocalDate dateTime = LocalDate.parse(dateInString, formatter);
                        DateTimeFormatter f2 = DateTimeFormatter.ofPattern("dd/MM");
                        String newDate = dateTime.format(f2);
                        dato = dato.replaceAll(dato,newDate);

                    }
                    a++;
                }
Andry
  • 323
  • 1
  • 2
  • 10