Search code examples
javaandroidcalendargregorian-calendar

Calendar: how to get string “10:00 AM”


I’m trying to get a string like e.g. “10:00 AM”

int numberOfHourFrom_0_to_23=10;
Calendar m_auxCalendar = new GregorianCalendar();
m_auxCalendar.set(Calendar.HOUR, numberOfHourFrom_0_to_23 +12);//+12 makes it work correctly during PM hours, but not sure why.
m_auxCalendar.set(Calendar.MINUTE,0);

Date mdate=m_auxCalendar.getTime();
String mstring  = DateFormat.getTimeInstance(DateFormat.SHORT).format(mdate);

If I use my Android phone during PM hours, this code works correctly (I get “10:00 AM”); however, if I use my phone during AM hours, I get “10:00 PM” instead of “10:00 AM”


Solution

  • java.time through desugaring

    Consider using java.time, the modern Java date and time API, for your time work.

        DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
        
        int numberOfHourFrom0To23 = 10;
        LocalTime time = LocalTime.of(numberOfHourFrom0To23, 0);
        String mstring = time.format(timeFormatter);
        
        System.out.println(mstring);
    

    Output in US locale is (no surprises):

    10:00 AM

    A LocalTime is a time of day with no date, so seems to be all that you need here.

    What went wrong in your code?

    Unexpectedly Calendar.HOUR refers to hour within AM or PM, from 0 through 11. I never understood for what this is useful. When you create a GregorianCalendar in the morning and set its HOUR to 10, you get 10 AM. When you do the same in the afternoon, you get 10 PM. You tried to compensate by adding 12 hours. Now you set the hour to 22 even though the range was o through 11. Any decent class would throw an IllegalArgumentException (or similar). Not a Calendar object with default settings. Instead it adjusts the time to 10 AM on the next day. And now when you run your code in the morning, you get 10 PM, as you observed.

    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. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.

    Links