Hello, everybody!!!

This post is the second subject of the series about the changes that you can find between version 6 to 8. Here we will talk about the Localization.

Summary


Advantages of localizing and how to define, read, and set the locale

Some attributes as Language, Dates, Times, Numbers, Currencies or Messages will vary from one region to another. The application needs to be prepared for this. And it is the  Internationalization proposition and Localization.  More detail can be seen here.

Internationalization is the process of designing your program to support more than one language or country. Internationalization just means that you can.
Localization means actually supporting multiple locales. You can think of a locale as being like a language and country pairing.
zh_CN                                            // lowercase_UPPERCASE
Locale.setDefault(new Locale("zh", "CN");
Locale locale = Locale.getDefault();            // Returns the default locale of the JVM.
Locale chinese = new Locale("zh");
Locale CHINA = new Locale("zh", "CN");
Locale china = new Locale.Builder().setRegion("CN").setLanguage("zh").build();

String countryCode = locale.getCountry();        // CN
String countryName = locale.getDisplayCountry(); // China
languageCode = locale.getLanguage();             // zh
languageName = locale.getDisplayLanguage();      // chinese

Locale [] locales = Locale.getAvailableLocales(); // All the locales supported by JVM

Resource Bundle

The first step in internationalization is to do a map to translate text into ResourceBundle objects. The map is a collection of key/value pairs.

It can be possible using property files or a java class (used when you need not only String). Who handles this is the Resource Bundles with abstract class java.util.ResourceBundle. If the application use property files to represent locale, then it's necessary to use the subclass java.util.PropertyResourceBundle. If the application uses Java Class to represent locale,  java.util.ListResourceBundle. Java class has to have the same name that you would use for a property file.

The convention name is:
package.Bundle_language_country_variant
Example: com.example.MyBundle_fr_FR

Steps used by java to find the bundle:

  1. Java first searches for a bundle whose name matches the complete locale: package.bundle_language_country_variant
  2. If it cannot find one, it drops the last component of the name and repeats the search: package.bundle_language_country
  3. If it cannot find one, again, it drops the last component of the name and repeats the search: package.bundle_language
  4. If still cannot find one, the last component is dropped again, leaving just the name of the bundle: package.bundle
  5. If nothing is found, a MissingBundleException is thrown.
  6. If a class and a property file share the same name, Java gives priority to the class.

Create and manage date- and time -based events 

The Java 8 version try to improve the use of date and time. Some limitations as months start at '0' (java.util.Date) or java.util.Date and java.util.Calendar be immutable class could come out problems in some applications.

Then, this version introduced a new API to support those aspects. That API brought new classes that are immutable and thread-safe:

  •  Classes that implement the interface java.time.temporal.Temporal:
    • LocalDate: represents a year, month, and day. Obs: Months start at '1'. It's possible to create, to get, compare or manipulate values (adding or subtracting).  Examples here.
    • LocalTime: hour, minutes, seconds, and nanoseconds. It's possible to create, to get, compare or manipulate values (adding or subtracting). Examples here.
    • LocalDateTime: A combination of the above. It's possible to create, to get, compare or manipulate values (adding or subtracting). Examples here.
    • Instant: It is a point in time represented by a single point in time in seconds and nanoseconds. It's possible to get, compare or manipulate values (adding or subtracting). OBS: You cannot convert a LocalDateTime to an Instant. Obs: Instant displays a year and month but you cannot do math with those fields.

Resource: java-8-tips


  •  Classes that implement the interface java.time.temporal.TemporalAmount:
    • Period: Represents an amount of time in terms of years, months and days. It's possible to create, to get and to identify a period between two LocalDates.  The results can be negative values. OBS: You cannot chain methods when creating a Period. You will get a compiler warning about this. Examples here.
    • Duration: It is as a Period represented by an amount of time in terms of seconds and nanoseconds. It's possible to create, to get, to identify a difference between two Temporal types (LocalTime, LocalDateTime and Instant) or manipulate values. Examples here.

Reference: Oracle Certified Professional Java SE 8 Programmer Exam 1Z0-809


The objects created by these classes are immutable. For this reason, Java added a with method to create another object from an existing one. For example, you can create a new LocalDate using .withMonth(12).withDayOfMonth(25).

For adding or subtracting methods you can use the specific methods or the generic method. An example of a specific method is from LocalDate, object.minusYears(2). If you choose the generic way, you will do object.minus(2, ChronoUnit.YEARS).

In the same way, to get a specific information related with the created object you can use a specific get method or you can use a generic get method. Then, to get a year in a LocalData, for example, you can use object.getYear() or object.get(ChronoField.YEAR).

The possible values to ChronoField and ChronoUnit are different to each class. Observe that Period and Duration don’t use these enums.

ChronoField

LocalDate LocalTime LocalDateTime Instant

ChronoUnit

Examples of different ways to use the date in the versions.

Old Version J8
import java.util.*; import java.time.*;
Calendar c = new GregorianCalendar(2018, Calendar.JANUARY, 1);  
Date jan = c.getTime(); LocalDate jan = LocalDate.of(2018, Month.JANUARY,1);
public Date addDay(Date date) { Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.DATE, 1); return cal.getTime(); } public LocalDate addDay(LocalDate date) { return date.plusDays(1); }
public Date subtractDay(Date date) { Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.DATE, -1); return cal.getTime(); } public LocalDate subtractDay(LocalDate date) { return date.minusDays(1); }

Format Numbers and currency

To format numbers you will use NumberFormat class and use format() method to turn a number into a String and parse() method to turn a String into a number.

# Example 1
DecimalFormat df = new DecimalFormat("#,000.0#");
String result = df.format(3.141592653);
# Result: 003,14
# PS> DecimalFormat extends NumberFormat
> '#' : to omit the position if no digit exists for it.
> '0' : to put a 0 in the position if no digit exists for it.

#Example 2
NumberFormat nf = NumberFormat.getInstance();
String one = "456abc";
String three = "x85.3";
# Result1: 456
#PS> Parse until finish the number.
# Result 2:ParseException
# PS>It has to beginning with number.

# Example 3
NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
try {
    System.out.println(nf.parse("444,33"));
    // Result: 444.33
} catch (ParseException e) {
    System.out.println("ERROR!!!");
}

# Example 4
NumberFormat br = NumberFormat.getCurrencyInstance();
System.out.format(price);
# Result: </span>R$ 48,00

Format Date and Time

You can use java.time.format.DateTimeFormatter to read or print in different formats. When use method toString() to print the value, the formats will be:

  • LocalDate: uuuu-MM-dd
  • LocalTime: HH:mm:ss.SSSSSSSSS
  • LocalDateTime: uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS
  • Instant: uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS
  • Period: PNYNMND
  • Duration: PTnHnMnS

If you want to customize the format you should use the ofPattern() method in the DateTimeFormatter class. Pay attention in UPPERCASE and lowercase letters. In dd-MM-yy, MM refers to month. In dd-mm-yy, mm refers to minutes.

To format the time you can follow the same idea.

To parse date you can use SHORT date format.

DateFormat shortFormat = DateFormat.getDateInstance( DateFormat.SHORT, Locale.US);
String  = "01/31/1984";
try {
   Date date = shortFormat.parse(s);
   System.out.println(date);
   // Result: Tue Jan 31 00:00:00 BRT 1984
} catch (ParseException e) {
   System.out.println("Exception!!!");
}

Time zones 

To work with the zone, the new version changes the use from TimeZone class to ZonedDateTime, where (as you can guess) you have the date, time and zone. For example, "10:50 a.m. EST". Time zone is expressed as a number of hours

# Example 1
ZonedDateTime.now()
# Result: 2018-11-28T20:30:43.274-03:00[America/Fortaleza]

# Example 2
ZoneId.systemDefault()
ZoneId zone = ZoneId.of("US/Eastern");
ZonedDateTime zoned1 = ZonedDateTime.of(2018, 1, 20, 6, 15, 30, 200, zone);
# zoned1: 2018-01-20T06:15:30.000000200-05:00[US/Eastern]

# Combine other class
LocalDate date = LocalDate.of(2018, 1, 1);
ZonedDateTime zonedDate = date.atStartOfDay(zone);

LocalDateTime dateTime = LocalDateTime.of(2018, 1, 1, 7, 15);
ZonedDateTime zonedDateTime = dateTime.atZone(zone);

Instant instant = Instant.now();
ZonedDateTime zonedInstant = instant.atZone(zone);

# PS
To ZoneOffset: ChronoField.OFFSET_SECONDS
To ZenedDateTime: The same of LocalDateTime

# PS
The Daylight Saving Time (DST) is to advance one hour in the clock.

The new class have new options:

  • ZoneID: America/Fortaleza
  • ZoneOffset: -03:00 (or UTC+11:00) (It has to be started with a sign)
  • ZonedDateTime: 2018-11-28T20:30:43.274-03:00[America/Fortaleza]
  • OffsetDateTime: 2018-11-28T20:30:43.274-03:00.
  • OffsetTime: 20:30:43.274-03:00

Posts Related

Reference