How to format a date by any locale obtained from language tag with java time?

谁都会走 提交于 2020-12-15 06:27:07

问题


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?


回答1:


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.




回答2:


Proposed solution

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

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


来源:https://stackoverflow.com/questions/47442317/how-to-format-a-date-by-any-locale-obtained-from-language-tag-with-java-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!