18

When I use the "HH" flag in android.text.format.DateFormat, it is interpreted as a literal "HH". But when I use java.text.SimpleDateFormat it is interpreted as the 2 digit Hour. Why are they different?

I'm not looking for a working alternative (I already know I have to use kk instead of HH). I'm just curious why "HH" isn't recognized.

Java example:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Calendar calendar = Calendar.getInstance();

    String dateJava = new java.text.SimpleDateFormat(
        "dd-MM-yyyy HH:mm:ss").format(calendar.getTime());

    String dateAndroid = android.text.format.DateFormat.format(
        "dd-MM-yyyy HH:mm:ss", calendar).toString();

    TextView tvAndroid = (TextView) findViewById(R.id.tvAndroid);
    TextView tvJava = (TextView) findViewById(R.id.tvJava);

    tvAndroid.setText("Android: " + dateAndroid);  //prints 26-05-2013 HH:36:34
    tvJava.setText("Java: " + dateJava);           //prints 26-05-2013 22:36:34
}

Output is:

Android: 26-05-2013 HH:36:34 
Java:    26-05-2013 22:36:34

I expect both to be 26-05-2013 22:36:34

Does Android's DateFormat have a bug?

Java's SimpleDateFormat accepts these:

H   Hour in day (0-23)      Number  0
k   Hour in day (1-24)      Number  24
K   Hour in am/pm (0-11)    Number  0
h   Hour in am/pm (1-12)    Number  12

So it appears the Android developers decided to change the meaning of k and in their DateFormat function it is equivalent to the SimpleDateFormat H as they explicitly say in their documentation page:

This constant was deprecated in API level 18. Use a literal 'H' (for 
compatibility with SimpleDateFormat and Unicode) or 'k' (for compatibility 
with Android releases up to and including Jelly Bean MR-1) instead. Note 
that the two are incompatible. 

What is the reason for this?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Alejandro Colorado
  • 6,034
  • 2
  • 28
  • 39
  • See my answer - I don't know why 'k' was historically used in Android but it makes sense that future versions will support 'H'. The comment in the last bit of code I posted suggests using 'kk' may have been (or still is as of API 17) a problem. – Squonk May 26 '13 at 23:00
  • My first question in SO and that -2 makes me a bit scared. I don't think it's a stupid question to deserve a -2, but it's ok. I accept the critics. – Alejandro Colorado May 26 '13 at 23:02
  • No problem, glad to help. I don't use `DateFormat` and have always used `SimpleDateFormat` so it took a bit of digging in the source to find the answer. BTW, I upvoted your question as it was a good exercise and it's always good to look at Android source code to find out what's going on - I learned something. :) – Squonk May 26 '13 at 23:09
  • Thanks for the +1 and for your answer. The purpose of this question was exactly that: creating an excercise or a challenge with a weird issue I stumbled upon. BTW, I always use `SimpleDateFormat`, but trying to reproduce someone else's error I got to this one. – Alejandro Colorado May 26 '13 at 23:13
  • 4
    This is actually a good question, not sure why people downvote it, I upvoted it. Format "k" is confusing, it is different from both SimpleDateFormat and the grandfather of all date formatting tools - strftime – msh May 26 '13 at 23:30
  • Thanks @msh! Maybe my question was not correctly explained. I too thought it was an interesting question to share because they explicitly say `For the canonical documentation of format strings, see SimpleDateFormat`. @Squonk's effort gave me the answer I was exactly looking for. – Alejandro Colorado May 27 '13 at 08:42

5 Answers5

9

I understand you have accepted an answer already but just to explain this fully to you...

From the source code for DateFormat.java...

The format methods in this class implement a subset of Unicode UTS #35 patterns. The subset currently supported by this class includes the following format characters: acdEHhLKkLMmsyz. Up to API level 17, only adEhkMmszy were supported. Note that this class incorrectly implements k as if it were H for backwards compatibility.

Note the part I have marked in bold.

The source I linked to has been updated to allow the use of H but it isn't on general release yet (API 17 is the current release of Android and doesn't support H).

Later in the source, at the stage of declaring the format character constants, there is this comment...

/**
 * @deprecated Use a literal {@code 'H'} (for compatibility with {@link SimpleDateFormat}
 * and Unicode) or {@code 'k'} (for compatibility with Android releases up to and including
 * Jelly Bean MR-1) instead. Note that the two are incompatible.
 */
@Deprecated
public  static final char    HOUR_OF_DAY            =    'k';

...and later during character replacement...

case 'H': // hour in day (0-23)
case 'k': // hour in day (1-24) [but see note below]
{
    int hour = inDate.get(Calendar.HOUR_OF_DAY);
    // Historically on Android 'k' was interpreted as 'H', which wasn't
    // implemented, so pretty much all callers that want to format 24-hour
    // times are abusing 'k'. http://b/8359981.
    if (false && c == 'k' && hour == 0) {
        hour = 24;
    }
    replacement = zeroPad(hour, count);
}
break;
arekolek
  • 9,128
  • 3
  • 58
  • 79
Squonk
  • 48,735
  • 19
  • 103
  • 135
  • Sorry, @Brian Roach, as I had marked your answer as correct prior to having this one, but this is exactly what I was looking for! Glad to see they will "fix" this confusing issue. Thanks @Squonk! – Alejandro Colorado May 26 '13 at 23:07
5

Because ... it's not the same thing and it's behaving as the documentation states?

From the Documentation for android.text.format.DateFormat

This class only supports a subset of the full Unicode specification. Use SimpleDateFormat if you need more.

But if you read the docs further:

public static final char HOUR_OF_DAY

This designator indicates the hour of the day in 24 hour format. Example for 3pm: k -> 15 Examples for midnight: k -> 0 kk -> 00

So ... using that class, it'd be kk instead of HH

Community
  • 1
  • 1
Brian Roach
  • 76,169
  • 12
  • 136
  • 161
  • I know kk is an alternative (which I'm not looking for), but h is also accepted in Android's DateFormat according to the examples in their [documentation page](http://developer.android.com/reference/android/text/format/DateFormat.html), so why accepting h and not HH? – Alejandro Colorado May 26 '13 at 22:22
  • @AlejandroColorado `h` and `H` are two completely different things. For whatever reason, Android's `DateFormat` decided to use `k` rather than `H` for hour 00-23. Why? No idea ... you'd have to track down whomever wrote it and strangle them ... I mean ask them. ;) – Brian Roach May 26 '13 at 22:23
  • No need to strangle them ;o) Why changing the meaning of the `k` comparing it to SimpleDateFormat? – Alejandro Colorado May 26 '13 at 22:29
  • As I say in my last update, they decided to change the meaning of `k` to make it equivalent to the SimpleDateFormat `H` although they explicitly say in their documentation page: `For the canonical documentation of format strings, see SimpleDateFormat.` – Alejandro Colorado May 26 '13 at 22:54
3

For android.text.format.DateFormat you designate Hour in day as kk like this:

String dateAndroid = android.text.format.DateFormat.format(
    "dd-MM-yyyy kk:mm:ss", calendar).toString();

For java.text.SimpleDateFormat you designate hour in day as HH.

H hour in day (0-23)

Documentation for android.text.format.DateFormat:

public static final char HOUR_OF_DAY

This designator indicates the hour of the day in 24 hour format. Example for 3pm: k -> 15 Examples for midnight: k -> 0 kk -> 00

Community
  • 1
  • 1
msh
  • 2,700
  • 1
  • 17
  • 23
1

I have never programmed for Android. I googled the DateFormat javadoc and saw there the following examples:

Examples for April 6, 1970 at 3:23am:
"MM/dd/yy h:mmaa" -> "04/06/70 3:23am"
"MMM dd, yyyy h:mmaa" -> "Apr 6, 1970 3:23am"
"MMMM dd, yyyy h:mmaa" -> "April 6, 1970 3:23am"
"E, MMMM dd, yyyy h:mmaa" -> "Mon, April 6, 1970 3:23am&
"EEEE, MMMM dd, yyyy h:mmaa" -> "Monday, April 6, 1970 3:23am"
"'Noteworthy day: 'M/d/yy" -> "Noteworthy day: 4/6/70"

The "hour" is marked using small letter h in opposite to SimpleDateFormat where capital letter is used for this purpose.

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • @msh, he has issues with DateFormat of Android that supports `h` – AlexR May 26 '13 at 22:03
  • @AlexR the equivalent to `HH` in `SimpleDateFormat` (hour of day 00-23) is `kk` in `DateFormat`- `h` is 1-12 in both. – Brian Roach May 26 '13 at 22:20
  • As @Brian Roach said, `h` is not used in opposite to SimpleDateFormat's `H` but `k`. Therefore, the equivalent to `HH` is `kk`. BTW, thanks you for your help! – Alejandro Colorado May 26 '13 at 22:58
1

This work for all Android 4.0+ and for two date time format.

Use java.text.SimpleDateFormat.

Work example:

24 hour format use this date pattern = "dd-MM-yyyy HH:mm";

12 hour format use this date pattern = "dd-MM-yyyy hh:mm a";

public static String getDateAsString(Date date, String pattern) {
        Locale locale = new Locale("EN");
        SimpleDateFormat sdf = null;
        try {
            sdf = new SimpleDateFormat(pattern, locale);
            return sdf.format(date);
        } catch (IllegalArgumentException ex) {
            // default format
            sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm", locale);
            return sdf.format(date);
        }
 }
Alex
  • 1,857
  • 4
  • 17
  • 34