0

I want to get a date as string and a language tag and based on that to parse the string by the locale format.

This is what I've done so far:

public static String formatDateByLocale(String date, String languageTag) {
    Locale locale = Locale.forLanguageTag(languageTag);
    String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.LONG, FormatStyle.LONG, Chronology.ofLocale(locale), locale);

    DateTimeFormatter targetFormat = DateTimeFormatter.ofPattern(datePattern).withLocale(locale);
    DateTimeFormatter currentFormat = DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm a");

    LocalDateTime localDateTime = LocalDateTime.parse(date, currentFormat);

    String result = targetFormat.format(localDateTime);


    return result;
}

This throws Unable to extract value: class java.time.LocalDateTime

How should I approach this to have this date: 17/04/2017 10:50AM with FR tag transform into 2017/04/17 10:50AM?

Gustavo
  • 3,461
  • 7
  • 26
  • 41

2 Answers2

4

Your example is incomplete and incorrect. You should provide a MCVE. Your example output of 17/04/2017 10:50AM is not at all close to the actual output of French with format style LONG. So we cannot answer precisely. But here is something to point you in the right direction.

You cannot count on being able to parse any date-time input string. Some ambiguities are impossible to resolve. And some crucial information such as offset-from-UTC or time zone may be omitted. Instead:

  • Within your app, pass around java.time objects, rather than mere strings.
  • Between apps/systems, pass strings is standard ISO 8601 format. Do so in UTC for date-time values, generally speaking.

Here is some example code showing your desired French output.

Capture the current moment in UTC as an Instant.

Instant instant = Instant.now( );

Adjust into a particular time zone. Remember that time zone has nothing to do with localization issues.

ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );

Determine a Locale. Here we use French language with cultural norms of France.

Locale locale = Locale.forLanguageTag( "fr-FR" );

Your Question shows swapping of Chronology where appropriate for a locale. Has no effect here as both Instant and France use IsoChronology.

Chronology c = Chronology.ofLocale( locale );

Define a formatter. No need for the builder pattern seen in the Question.

DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT ).withLocale( locale ).withChronology( c ) ;

Generate output.

String s = zdt.format( f );

Dump to console.

System.out.println( "instant.toString(): " + instant + " at zone: " + z + " in chrono: " + c + " = " + s );

instant.toString(): 2017-11-23T04:30:45.091424Z at zone: Asia/Kolkata in chrono: ISO = 23/11/2017 10:00

Note how this output cannot be parsed back into a date-time value as it lacks crucial information.

You could, in this case, parse the string to a LocalDateTime as shown in your Question. But you have data loss here. A LocalDateTime purposely has no concept of offset or zone, and so it does not represent a point on the timeline. A LocalDateTime is not an actual moment, only a vague hint of a range of possible moments that may be occurring over a period of about 26-27 hours. You are not even close to ending up where you started.

LocalDateTime ldt = LocalDateTime.parse( s , f );
System.out.println( "ldt: " + ldt );

ldt.toString(): 2017-11-23T10:00

By the way, I suggest your method take a Locale rather than a mere string of the language tag. The calling programmer should be responsible for determining the full Locale for a valid language tag. Language tags and their variants are complicated business. The calling programmer should verify they have properly defined a valid language construct by successfully instantiating a Locale (and, ideally, testing it). The method at hand here should focus on date-time issues and not have to also deal with language tag complications.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Your statement about `Chronology.of(Locale)` having no effect in case of `Instant` or French locale is not true. For example: "fr-FR-u-ca-buddhist" would produce the ThaiBuddhist calendar in French language. – Meno Hochschild Nov 23 '17 at 11:00
  • @MenoHochschild No, I did not say that about Chronology. I said that about time zone. – Basil Bourque Nov 23 '17 at 16:27
  • Okay, my English is of course not on your level. Anyway, I get the feeling that you care too much about timezones regarding the fact that the OP handles zoneless inputs which can be perfectly parsed to `LocalDateTime`. And I guess the real problem of OP is somewhere else - maybe related to mismatch of format pattern and/or AM/PM-support in the realm of i18n. – Meno Hochschild Nov 23 '17 at 16:47
  • @MenoHochschild Actually, I do not believe we know exactly what the OP wants or what the OP is doing. The Question is unclear, mixing parsing of strings with generating strings. I get the feeling the root question here is "How do I parse any date-time string in any format?", which of course is impossible. – Basil Bourque Nov 23 '17 at 19:20
0

Proposed solution

Replace your datePattern with "yyyy/MM/dd hh:mm a":

DateTimeFormatter targetFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm a").withLocale(locale);
Sync
  • 3,571
  • 23
  • 30