3

Based on an input string with the following format: "yyyyMMdd", for example "20170412", how can I display the day and date?

For example:

input -> "20170412"

output -> "Wednesday, April 12th 2017" or "Wed Apr 12 2017" or something similar

Whichever pattern I try using SimpleDateFormat (https://stackoverflow.com/a/4216767/658323), I always get the time and the timezone which I do not need.

Is that possible?

Edit: My question is not a duplicate. I explicitly mention in my post, that all patterns of SimpleDateFormat that are listed in the possible duplicate question, display the time and the time zone of the user. I need a pattern for the date on the user's locale, without the time or time zone.

Community
  • 1
  • 1
steliosf
  • 3,669
  • 2
  • 31
  • 45
  • 1
    Possible duplicate of [Java string to date conversion](http://stackoverflow.com/questions/4216745/java-string-to-date-conversion) – Cas Dekkers Apr 12 '17 at 18:28

3 Answers3

6

tl;dr

LocalDate.parse(
    "20170412" ,
    DateTimeFormatter.BASIC_ISO_DATE
).format(
    DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL )
                     .withLocale( Locale.US )
)

Wednesday, April 12, 2017

Using java.time

The modern way is with the java.time classes, LocalDate specifically. The LocalDate class represents a date-only value without time-of-day and without time zone.

Define a formatting pattern to match your input. Your input happens to comply with the “basic” version of ISO 8601 where the use of separators is minimized. For that, java.time has already pre-defined a formatting pattern.

DateTimeFormatter f = DateTimeFormatter.BASIC_ISO_DATE ;
LocalDate ld = LocalDate.parse( "20170412" , f );

To generate a string in standard ISO 8601 format, call toString. The java.time classes use the standard formats when parsing/generating strings.

String output = ld.toString() ;

2017-04-12

Generally I suggest you stick with the expanded versions of the ISO 8601 formats, as seen in this example above that includes the hyphens in a date, rather than the basic versions. The expanded versions are easier to read by humans and more recognizable as date-time values.

Localize

You can generate strings in other formats. You can specify exact formats if desired. But generally best to let java.time localize for you.

To localize, specify:

  • FormatStyle to determine how long or abbreviated should the string be.
  • Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such.

Example code.

Locale l = Locale.CANADA_FRENCH ;  // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL )
                                       .withLocale( l ) ;
String output = ld.format( f ) ;

For Locale.US that output would be:

Wednesday, April 12, 2017


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • And for the human readable date mentioned in the title, there are `ld.format(DateTimeFormatter.ofPattern("EEEE, MMM dd'th' uuuu", Locale.ENGLISH))` and `ld.format(DateTimeFormatter.ofPattern("EEE MMM d uuuu", Locale.ENGLISH))` and countless variants (those examples yield exactly the strings mentioned in the question). Please fill in the correct locale for your users. – Ole V.V. Apr 12 '17 at 19:11
  • Thank you, Basil. So as far as I understand, what I'm trying to do is not possible in Java 7 without any external library, right? – steliosf Apr 13 '17 at 21:22
  • @MScott You can kinda-sorta do what you want with the old legacy classes bundled with Java and with Android. But those classes do not have a way to truly represent a date-only value with no time-of-day and no zone. See the “Android” bullet in my Answer for a backport library to give you java.time functionality including a `LocalDate` class. Built by same people that made java.time. Well worth the bother of adding a library as the legacy date-time classes are a horrible awkward confusing mess. – Basil Bourque Apr 13 '17 at 21:54
5

If I correctly understood Your question: Seems that You need different format for reading from string to date and different for display. Try this

    String string = "20170412";
    DateFormat readFormat = new SimpleDateFormat("yyyyMMdd");
    Date date = readFormat.parse(string);

    DateFormat displayFormat = new SimpleDateFormat("E MMMM d, yyyy", Locale.ENGLISH);
    System.out.println(displayFormat.format(date));

But generaly You should respect date format seleced by user glably for system. So every app wil have same display date format: Like in this post How to get user-selected date format in Android?

Community
  • 1
  • 1
Emiter
  • 268
  • 2
  • 13
  • 1
    FYI, the troublesome old date-time classes such as `java.util.Date`, `java.util.Calendar`, and `SimpleTextFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) classes. Much of the java.time functionality is back-ported to a Java 6 and Java 7 in the [ThreeTen-Backport](http://www.threeten.org/threetenbp/) project. Further adapted for Android in the [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP) project. – Basil Bourque Apr 12 '17 at 18:56
  • A `java.util.Date` is a date *and* a time-of-day in UTC. The Question seeks a date-only without time-of-day and without time zone. – Basil Bourque Apr 12 '17 at 19:04
  • That's right, Basil, I don't want to display the time or time zone. @Emiter Not sure what you mean by respecting the date format selected by the user. I want to display the date formatted in the user's locale, i.e. using `Locale.getDefault()` – steliosf Apr 13 '17 at 20:39
  • @Emiter - I've tried your solution and it works without displaying the time, however, the problem is that it's using the same format, regardless of the language of the user's device. What I mean is that some languages display the month after the date, while others display the date after the month. Any way to achieve that? (I tried using `Locale.getDefault()` instead of `Locale.ENGLISH`, and that works to translate the day and the month, but the format remains the same) – steliosf Apr 13 '17 at 21:31
  • So IMHO you should use date format from android prefeneces. Sth like this: final String format = Settings.System.getString(getContentResolver(), Settings.System.DATE_FORMAT); if (TextUtils.isEmpty(format)) { dateFormat = android.text.format.DateFormat.getMediumDateFormat(getApplicationContext()); } else { dateFormat = new SimpleDateFormat(format); } – Emiter Apr 18 '17 at 07:45
1

So, the answer was pretty simple actually. There's a built-in method in Android getBestDateTimePattern (available since API 18) that will automatically format the date based on the language of the user:

String pattern = android.text.format.DateFormat.getBestDateTimePattern(Locale.getDefault(), "EEEEMMMMdyyyy"); //order on the String doesn't matter
SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.getDefault());
String dateToDisplay = format.format(date);

Here's the official documentation of getBestDateTimePattern:

Returns the best possible localized form of the given skeleton for the given locale. A skeleton is similar to, and uses the same format characters as, a Unicode UTS #35 pattern.

One difference is that order is irrelevant. For example, "MMMMd" will return "MMMM d" in the en_US locale, but "d. MMMM" in the de_CH locale. Note also in that second example that the necessary punctuation for German was added. For the same input in es_ES, we'd have even more extra text: "d 'de' MMMM".

This method will automatically correct for grammatical necessity. Given the same "MMMMd" input, this method will return "d LLLL" in the fa_IR locale, where stand-alone months are necessary. Lengths are preserved where meaningful, so "Md" would give a different result to "MMMd", say, except in a locale such as ja_JP where there is only one length of month.

This method will only return patterns that are in CLDR, and is useful whenever you know what elements you want in your format string but don't want to make your code specific to any one locale.

For API's lower than 18, you can use the workaround described by Emiter on his comment:

final String format = Settings.System.getString(getContentResolver(), Settings.System.DATE_FORMAT);
if (TextUtils.isEmpty(format)) dateFormat = android.text.format.DateFormat.getMediumDateFormat(getApplic‌​ationContext());
else dateFormat = new SimpleDateFormat(format);
steliosf
  • 3,669
  • 2
  • 31
  • 45