Joda-Time ignores locale on en-US server

I am using Joda-Time to convert string dates to timestamp. Everything works fine in my pt-BR machine. However, on an en-US server, Joda ignores the custom locale.

On my laptop (Windows 8 pt-BR):

Locale.setDefault(new Locale("pt", "BR"));
DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("dd-MMM-yy");
dateFormatter.parseLocalDate("13-Out-14").toDateTimeAtStartOfDay().getMillis();

      

This code works flawlessly. The word for October in Portuguese is Outubro.

Locale.setDefault(new Locale("en", "US"));
DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("dd-MMM-yy");
dateFormatter.parseLocalDate("13-Oct-14").toDateTimeAtStartOfDay().getMillis();

      

The above code works great. The JVM recognizes the new locale and converts the date. However, when I try to run the first piece of code on Windows Server 2012 en-US, I get an exception.

java.lang.IllegalArgumentException: Invalid format: "13-Out-14" is malformed at "Out-14"
  at org.joda.time.format.DateTimeFormatter.parseLocalDateTime(DateTimeFormatter.java:854)
  at org.joda.time.format.DateTimeFormatter.parseLocalDate(DateTimeFormatter.java:798)
  at br.com.luminiti.pro.service.DataUtil.dataStringToLong(DataUtil.java:155)

      

And if I change Out to Oct it converts without issue. So it looks like the JVM is using the language of the machine itself.

How to solve this problem?

Thank!

+3


source to share


1 answer


Uppercase O

Problem

The expected abbreviated name for October is in Portuguese out

instead out

.

To demonstrate this code in Joda-Time 2.5:

System.out.println( "October in Portuguese: " + DateTimeFormat.forPattern( "dd-MMM-yy" ).withLocale( locale_ptBR ).print( new DateTime( 2014 , 10 , 13 , 0 , 0 , 0 ) ) );

      

... outputs lowercase O

:

October in Portuguese: 13-out-14

      

➥ So, change the input line from 13-Out-14

to 13-Out-14

and your code works.

Monthly names Abbreviated

See what the expected names are truncated in Joda-Time:

Locale locale_ptBR = new Locale( "pt" , "BR" );  // Portuguese in Brazil.
System.out.println( "Short months for locale : " + locale_ptBR + Arrays.toString( org.joda.time.DateTimeUtils.getDateFormatSymbols( locale_ptBR ).getShortMonths() ) );

Locale locale_frCA = Locale.CANADA_FRENCH;  // Québec.
System.out.println( "Short months for locale : " + locale_frCA + Arrays.toString( org.joda.time.DateTimeUtils.getDateFormatSymbols( locale_frCA ).getShortMonths() ) );

Locale locale_enUS = Locale.US;  // United States.
System.out.println( "Short months for locale : " + locale_enUS + Arrays.toString( org.joda.time.DateTimeUtils.getDateFormatSymbols( locale_enUS ).getShortMonths() ) );

      

When launched with Joda-Time 2.5 in Java 8 Update 25 on Mac (Mountain Lion), configured for US (US).

Short months for locale : pt_BR [jan, fev, mar, abr, mai, jun, jul, ago, set, out, nov, dez, ]
Short months for locale : fr_CA [janv., févr., mars, avr., mai, juin, juil., août, sept., oct., nov., déc., ]
Short months for locale : en_US [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, ]

      

You can see how they change in upper and lower case, number of characters and punctuation ( .

).

The rest of this answer deals with other question code issues.

Avoid setting the default locale

Calling Locale::setDefault

is a risky bad practice, as it affects all Java code running in all threads of all applications running in that complete Java Virtual Machine (JVM). Not only are you undermining the possible intent of other code to use the original source language, you do it at runtime, on the fly. You change it while other code is running. Not good.



Specify the locale

Instead of overriding the default Locale, specify the language you want. Call DateTimeFormatter::withLocale

to inform the language-specific formatter when parsing or generating strings.

Specify time zone

The code in the Question does not address the time zone question. The time zone is critical to parsing and determining the date. In the example below, try changing the timezone applied to the formatting to see very different results.

If this parameter is omitted, you get the current JVMs default time zone. This implicit use of the current default means that the behavior of your code can change at runtime on different machines.

To specify the time zone, call withZone

.

Use correct time zone names . Never use 3 or 4 letter codes that are not standardized and unique.

No local date needed

There is no need for LocalDate

this particular case. This should work, but storing it into DateTime

objects might be easier.

Sample code

Sample code in Joda-Time 2.5.

DateTimeZone zoneSaoPaulo = DateTimeZone.forID( "America/Sao_Paulo" );
DateTimeZone zoneNewYork = DateTimeZone.forID( "America/New_York" );
DateTimeZone zoneLosAngeles = DateTimeZone.forID( "America/Los_Angeles" );

Locale locale_ptBR = new Locale( "pt" , "BR" );
Locale locale_enUS = new Locale( "en" , "US" );

DateTimeFormatter formatter_ptBR = DateTimeFormat.forPattern( "dd-MMM-yy" ).withLocale( locale_ptBR ).withZone( zoneSaoPaulo );
DateTimeFormatter formatter_enUS = DateTimeFormat.forPattern( "dd-MMM-yy" ).withLocale( locale_enUS ).withZone( zoneSaoPaulo );  // Try swapping out this time zone to see very different results.

DateTime dateTime_ptBR = formatter_ptBR.parseDateTime( "13-out-14" ).withTimeAtStartOfDay();  // Month must be lowercase for Portuguese, "out" not "Out".
DateTime dateTime_enUS = formatter_enUS.parseDateTime( "13-Oct-14" ).withTimeAtStartOfDay();  // The call to "withTimeAtStartOfDay" is not necessary as it is the default when parsing date-only. I would include it to be self-documenting of our intention.

long millis_ptBR = dateTime_ptBR.getMillis();
long millis_enUS = dateTime_enUS.getMillis();

      

Dump for console.

System.out.println( "dateTime_ptBR : " + dateTime_ptBR );
System.out.println( "dateTime_ptBR : " + formatter_ptBR.print( dateTime_ptBR ) );
System.out.println( "dateTime_ptBR : " + DateTimeFormat.forStyle( "FF" ).withLocale( locale_ptBR ).print( dateTime_ptBR ) );
System.out.println( "millis_ptBR : " + millis_ptBR );

System.out.println( "dateTime_enUS : " + dateTime_enUS );
System.out.println( "dateTime_enUS : " + formatter_enUS.print( dateTime_enUS ) );
System.out.println( "dateTime_enUS : " + DateTimeFormat.forStyle( "FF" ).withLocale( locale_enUS ).print( dateTime_enUS ) );
System.out.println( "millis_enUS : " + millis_enUS );

System.out.println( "UTC : " + dateTime_ptBR.withZone( DateTimeZone.UTC ) );

      

At startup.

dateTime_ptBR : 2014-10-13T00:00:00.000-03:00
dateTime_ptBR : 13-out-14
dateTime_ptBR : Segunda-feira, 13 de Outubro de 2014 00h00min00s BRT
millis_ptBR : 1413169200000

dateTime_enUS : 2014-10-13T00:00:00.000-03:00
dateTime_enUS : 13-Oct-14
dateTime_enUS : Monday, October 13, 2014 12:00:00 AM BRT
millis_enUS : 1413169200000

UTC : 2014-10-13T03:00:00.000Z

      

+3


source







All Articles