Dates and Times

Calendars and date formatting are central to a properly internationalized application.  Java provides several classes that are very useful to the localization developer for handling dates and times. 
 
Java's Calendar class and its sub-classes handle the complex date calculations that go with Chinese, Islamic, Hebrew, and Gregorian calendars, as well as a number of others.
 
Java's DateFormat class handles formatting dates and times in a locale appropriate manner.
 
The DateFormatSymbols class contains localized information for date parts like weekdays, eras, months, etc...

Calendars

Most Java developers are familiar with the Gregorian calendar and perhaps even Julian Day, but to have a well localized application it is often neccessary to go beyond that.
 
To do business across Asia you need to be able to handle the Chinese, Japanese, and Buddhist calendars.  Muslim nations require an Islamic Calendar, and Israel needs a Hebrew calendar.  Each of these poses problems for the internationalization developer, but thankfully core Java and, to a greater extent, ICU provide some excellent capabilities for handling diverse calendars.

Gregorian Calendar

Problem:

You want to create a standard calendar as used in the west.

Solution:

The Gregorian Calendar is the predominant calendar of western countries today. To create a new Gregorian Calendar call the Singleton getInstance method on the Calendar class. if you specify a Locale as an argument the Calendar returned will reflect the first day of the week etc. of the Locale.

Locale locale = new Locale("en","US");
Calendar calendar = Calendar.getInstance(locale);

 

Hebrew Calendar

 Problem:

You want to use a Hebrew Calendar in your application.

Solution:

The Hebrew calendar is a very interesting lunar-solar calendar that poses some interesting challenges for the pogrammer.  It uses a leap month to synch the lunar and solar components.  The first day of the year can vary depending upon how it will affect jewish holidays, and the day ends at sundown.

 

Thankfully icu4j provides an excellent Hebrew calendar.  It is a simple manner to create a calendar, and the usage is similar to a standard Gregorian calendar.

 

To get an instance of a Hebrew calendar simply call the getInstance method passing in a ULocale that has a calendar type specified.

//Specify the calendar type on the ULocale

ULocale he = new ULocale("he_IL@calendar=hebrew");

//Call getInstance passing the ULocale

Calendar cal = Calendar.getInstance(he);

 

 

To get the months of the Jewish Calendar get an instance of DateFormatSymbols with a ULocale specifying the Hebrew Calendar.

//Get a Hebrew calendar for a Hebrew locale

ULocale he = new ULocale("he_IL@calendar=hebrew");

//Get a Hebrew calendar on an English locale

ULocale en = new ULocale("en@calendar=hebrew");

//Get DateFormatSymols for the locales

DateFormatSymbols dfsHe = DateFormatSymbols.getInstance(he);

DateFormatSymbols dfsEn = DateFormatSymbols.getInstance(en);

//Get arrays of months

String[] hebrewMonths = dfsHe.getMonths();

String[] englishMonths = dfsEn.getMonths();

//loop through the arrays and print out the English and Hebrew months

for(int x = 0; x < hebrewMonths.length; x++){

   System.out.println(englishMonths[x] + " = " + hebrewMonths[x]);

}

 

The output is:

 

Tishri = תשרי

Heshvan = חשון

Kislev = כסלו

Tevet = טבת

Shevat = שבט

Adar I = אדר ראשון

Adar = אדר שני

Nisan = ניסן

Iyar = אייר

Sivan = סיון

Tamuz = תמוז

Av = אב

Elul = 

 

 

 

 

 

Japanese Calendar

 Problem:

You want a calendar that is most familiar to your Japanese users.

Solution:

The Japanese calendar is identical to the Gregorian calendar, except the year is represented by the year of the emperor's reign.  It is currently the 20th year of the Heisei emperor's reign, so the year is Heisei 20.

You can create a Japanese calendar by using icu4j .

To create a calendar object:

ULocale ul = new ULocale("ja_JP@calendar=japanese");

 

To format a simple date example:

ULocale ul = new ULocale("en@calendar=japanese");

DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, ul);

System.out.println(df.format(new Date()));

 

 The result is "Friday, November 28, 20 Heisei".  If we change the ULocale to japanese the output is "平成20年11月28日金曜日"

To get the era of the current date:

//Get Japanese locale with attribute specifying japanese calendar

ULocale ul = new ULocale("ja_JP@calendar=japanese"); 

//calling getInstance using the locale bearing a calendar type will give us the appropriate locale

Calendar cal = Calendar.getInstance(ul);

//Output the era number.  This is a largely arbitrary number, but it can be used to compare

//against the static constants on Japanese Calendar

System.out.println(cal.get(JapaneseCalendar.ERA) + " Heisei era = " + JapaneseCalendar.HEISEI);

 

Chinese Calendar

Problem:

You want to create a Chinese calendar.

Solution:

Use icu4j to create a calendar instance.

//Get a ULocale for Chinese written in simplified Chinese for China using a Chinese calendar
ULocale chinese = new ULocale("zh_Hans_CN@calendar=chinese");
//Get a Calendar instance specifying our ULocale.  This will give us a Chinese calendar
Calendar c = Calendar.getInstance(chinese);
//Get a DateTimeFormat appropriate for the calendar.
DateFormat df = c.getDateTimeFormat(DateFormat.FULL, DateFormat.FULL, chinese);
//Output a formatted date.
System.out.println(df.format(new Date()));
//Output the pattern.
System.out.println(((SimpleDateFormat)df).toPattern());

 

Discussion:

The Chinese calendar is one of the most interesting and accurate calendars in use.  It is a lunisolar calendar that introduces a leap month to handle the justification of the lunar and solar systems.  The months are lunar months, but the leap month is added to avoid the calendar diverging from the solar cycle.  The calendar is still in wide use across Asia.

 

The Chinese calendar uses a system of measuring years in 60 year cycles.  The cycles are broken into earthly and heavenly stems of the elements and branches with animal names. 

 

Icu4j offers and excellent implementation of the Chinese calendar. It is very easy to implement.  By default it will output the year as "year x cycle".  I will demonstrate in another recipe how to create a more interesting format.

Find the Chinese zodiac for a Gregorian year

Problem:

You want to know the Chinese zodiac sign for a Gregorian year.

Solution:

Use the icu4j Chinese calendar to get the appropriate branch.  The following code illustrates and example:

//An array of heavenly and earthly elements.  The elements start with wood and end with
//water, but since we are using a modulus to determine the element we have moved earthly water
//to position 0
String[] enElements = {"Water","Wood","Wood","Fire","Fire","Earth",
        "Earth","Metal","Metal","Water"};
String[] zhElements = {"癸","甲","乙","丙","丁","戊","己","庚","辛","壬"};

//The 12 animals of the Chinese calendar.  Rat is first and Boar is last but we have
//moved boar to position zero so our modulus returns a correct result.
String[] enAnimals = {"Boar","Rat","Ox","Tiger","Rabbit","Dragon","Snake",
        "Horse","Sheep","Monkey","Rooster","Dog"};
String[] zhAnimals = {"亥","子","丑","寅","卯","辰","巳",
        "午","未","申","酉","戌"};
//Get an instance of a Chinese calendar by specifying a calendar type of Chinese on our ULocale
ULocale chinese = new ULocale("zh_Hans_CN@calendar=chinese");
Calendar c = Calendar.getInstance(chinese);
//Get a Gregorian calendar instance for setting our dates
Calendar g = Calendar.getInstance();
//We will set the year, month, and day since the stem and branch change on
//Chinese New Year, not January 1st.
//Set the year
g.set(Calendar.YEAR, 2008);
//Set the month.  Remember the month is 0 based so January is 0 and December is 11.
g.set(Calendar.MONTH, 0);
//Set the day of the month
g.set(Calendar.DATE, 7);
//Output the date to confirm
System.out.println(DateFormat.getDateInstance().format(g.getTime()));
//Set the Chinese calendar for your specified date
c.setTimeInMillis(g.getTimeInMillis());
//Get the element stem.  The current year mod 10 will give us a value between 0 and 9.
//We use that value to retrieve the element from the elements array.
String enElement = enElements[c.get(Calendar.YEAR)%10];
String zhElement = zhElements[c.get(Calendar.YEAR)%10];
//Get the animal branch. The current year mod 12 will give us a value between 0 and 11.
//We use that value to retrieve the animal from the animals array.
String enAnimal = enAnimals[c.get(Calendar.YEAR)%12];
String zhAnimal = zhAnimals[c.get(Calendar.YEAR)%12];
System.out.println(enElement + " " + enAnimal);
System.out.println(zhElement + zhAnimal);

Discussion:

The Chinese Calendar uses a 60 year cycle.  The year is represented by a branch representing heavenly and earthly examples for the 5 elements and the 12 animals of the zodiac.  The zodiac changes based upon the Chinese New Year, so the calculations are little more complex and require the month and day to be trully accurate.

 

 

Get the name of the current month

Problem:

You want to retrieve a localized display name of the current month.

Solution:

To get the name of a month you first retrieve an instance of Calendar for the desired locale. You use calendar.get(int) passing in the constant Calendar.MONTH to get the current month of the calendar. You then use that to pull the correct value out of the array of month names returned by getMonths() on an instance of DateFormatSymbols.

To get the display name for the current month:

//Get an instance of Calendar for a Japanese locale

Calendar calendar = Calendar.getInstance(Locale.JAPANESE);

//Get a new DateFormatSymbols object for the Japanese locale

DateFormatSymbols dfs = new DateFormatSymbols(Locale.JAPANESE);

//Get an Array of months

String[] months = dfs.getMonths();

System.out.println(months[calendar.get(Calendar.MONTH)]);


 

To loop through all of the months for a locale:

//Get a new DateFormatSymbols object for the Japanese locale

DateFormatSymbols dfs = new DateFormatSymbols(Locale.FRENCH);

//Get the months String[] months = dfs.getMonths();

//Months are zero based, so loop from 0 to 11

for(int x = 0; x < 12; x++){

  System.out.println(months[x]);

}

Get the first day of the week

Problem:

You want to find the first day of the week for a locale and display it.

Solution:

To get the first day of the week for a calendar in a particular locale you need to first get the Calendar instance by passing in the Locale, then retrieve a DateFormatSymbols object using the same Locale. You can then use the DateFormatSymbols to retrieve an array of weekdays and use the numeric first day of week value returned from the Calendar to get the a human readable first day of week.

 

To get a human readable first day of week for Great Britain.

Locale locale = new Locale("en","GB");

Calendar calendar = Calendar.getInstance(locale);

DateFormatSymbols dfs = new DateFormatSymbols(locale); System.out.println(dfs.getWeekdays()[calendar.getFirstDayOfWeek()]);

 

To do the same for Japan using the static Locale shortcut:

Calendar calendar = Calendar.getInstance(Locale.JAPANESE);

DateFormatSymbols dfs = new DateFormatSymbols(Locale.JAPANESE);

System.out.println(dfs.getWeekdays()[calendar.getFirstDayOfWeek()]);

Add time to Calendar

Problem:

You need to add or subtract time from a calendar.

Solution:

There are two ways to perform date math with a Calendar, use add(int,int) or roll(int,int). Roll will increment or decrement the specified field until the maximum or minimum value is reached, and then it will begin again. Adding 13 months to the calendar with roll will not increment the year.

Add will bubble up such that adding 13 months to a Calendar will also increment the year. To get the current date and add 3 months:

Calendar c = Calendar.getInstance(Locale.GERMAN); System.out.println(c.getTime()); c.add(Calendar.MONTH, 3); System.out.println(c.getTime());

To get the current date and subtract 7 weeks:

Calendar c = Calendar.getInstance(Locale.GERMAN); System.out.println(c.getTime()); c.add(Calendar.WEEK_OF_MONTH, -7); System.out.println(c.getTime());

Get an array of Holidays

 Problem:

You want to know what holidays are common for a locale.

Solution:

Icu4j contains a system to help the Java developer handle international holidays.  The Holiday class is simple to use, and has failry complete data.

 

To get an Array of all Holidays for Mexico:

//Get a ULocale

ULocale locale = new ULocale("es_MX");

//Get an array of Holidays

Holiday[] holidays = Holiday.getHolidays(locale);

//Loop through all of the Holidays and output the localized display name

for(int x = 0; x < holidays.length; x++){

    System.out.println(holidays[x].getDisplayName(locale));

}

 

The output:

 

New Year's Day

Constitution Day

Benito Juárez Day

May Day

Cinco de Mayo

Navy Day

Independence Day

Día de la Raza

All Saints' Day

Day of the Dead

Revolution Day

Flag Day

Christmas

 

 

Find the date for the Chinese New Year

Problem:

You want to find the date of the Chinese new year for a given year.

Solution:

Use icu4j's Chinese calendar to perform the calculations.  You will specify a year in a Gregorian calendar and use that to set the time of the Chinese calendar.  Then set the calendar tot he first month and first day.

//Get a ULocale for Chinese written in simplified Chinese for China using a Chinese calendar
ULocale chinese = new ULocale("zh_Hans_CN@calendar=chinese");
//Get a Calendar instance specifying our ULocale.  This will give us a Chinese calendar
Calendar c = Calendar.getInstance(chinese);
//Get a Gregorian calendar instance
Calendar c2 = Calendar.getInstance();
//Set the year you want to find new Years for.  We will also set the month
//to half way through the year since the Chinese New Year won't occur until perhaps late February
c2.set(Calendar.YEAR, 2008);
c2.set(Calendar.MONTH, 5);
//Set the year of the Chinese Calendar
c.setTimeInMillis(c2.getTimeInMillis());
//Set the month to the first month.  Remember months are zero based
c.set(Calendar.MONTH, 0);
//Set the day to the first.  Remember dates are one based.
c.set(Calendar.DATE, 1);
//Output the date.  getTime() returns a Gregorian date.
System.out.println(c.getTime());

The output:

Thu Feb 07 22:35:16 EST 2008 Shows us the New Years occured on Feb 7th in 2008.  The time output is irrelevant.

 Discussion:

The length of the Chinese calendar's year varies from year to year.  Since the Calendar uses a leap month, the New Year can occur anywhere from late January to late February. 

 

Get all the Era names for the Japanese Calendar

Problem:

You want to retrieve all of the era names for the Japanese calendar.

Solution:

Use the icu4j Japanese calendar and DateFormatSymbols to retrieve the era names.

//Get a ULocale that specifies a Japanese Calendar in Japanese
ULocale jp = new ULocale("ja_JP@calendar=japanese");
//Get a Japanese calendar instance
Calendar jc = Calendar.getInstance(jp);
//The era field contains the numeric identifier for the reigning emperor at the current time
System.out.println(jc.get(Calendar.ERA));
//Get an instance of the DateFormatSymbols for Japanese using the Japanese calendar
DateFormatSymbols dfs = DateFormatSymbols.getInstance(jp);
//getEras() returns a String array of era names
String[] eras = dfs.getEras();
//Loop through the eras and output
for(int x = 0; x < eras.length; x++){
    System.out.println(eras[x]);
}
//Now let's get the English Era names
//Get a ULocale that specifies a Japanese Calendar in English
ULocale en = new ULocale("en@calendar=japanese");
//Get the DateFormatSymbols for English using a Japanese Calendar
dfs = DateFormatSymbols.getInstance(en);
eras = dfs.getEras();
for(int x = 0; x < eras.length; x++){
    System.out.println(eras[x]);
}

Discussion:

The Japanese calendar counts years based upon the reign of the emperor.  Since the reign of an emperor varies in length it is impossible to calculate the year programmatically.  icu4j's DateFormatSymbols can provide us with a list of all Emperors.  To find the Japanese year for a Gregorian date use this recipe.

Get the Japanese era for a Gregorian date

Problem:

You want to know the Japanese era for a Gregorian date.

Solution:

Use a Japanese Calendar and DateFormatSymbols from icu4j to retrieve the Japanese year and era.

//Get a ULocale specifying a locale of Japanese using the Japanese calendar
ULocale jp = new ULocale("en@calendar=japanese");
//Get a calendar instance
Calendar jc = Calendar.getInstance(jp);
//Get a default Gregorian calendar instance
Calendar gc = Calendar.getInstance();
//Set calendar for desired date
gc.set(Calendar.YEAR, 1971);
//The month is zero based
gc.set(Calendar.MONTH, 9);
gc.set(Calendar.DATE, 22);
//Set the Japanese calendar using your Gregorian calendar
jc.setTimeInMillis(gc.getTimeInMillis());
//Get a DateFormat appropriate for the ULocale
DateFormat df = jc.getDateTimeFormat(DateFormat.FULL, DateFormat.FULL, jp);
//Output a formatted date
System.out.println(df.format(jc.getTime()));
//Output the era.
System.out.println(jc.get(Calendar.ERA));
//The era is a numeric value.  To get a meaningful value we need to
//get an instance of DateFormatSymbols and retrieve an array of era names.
//We can then use the era to retrieve the appropriate display name
DateFormatSymbols dfs = DateFormatSymbols.getInstance(jp);
//Concatenate the era and year.
String jYear = dfs.getEras()[jc.get(Calendar.ERA)]+jc.get(Calendar.YEAR);
System.out.println(jYear);

Output:

昭和46年10月22日金曜日 12時53分44秒アメリカ合衆国 (ニューヨーク)
234
昭和46

Discussion:

The Japanese year is represented by the year of the Emperors reign.  This makes it impossible to programmatically calculate the year since the length of an Emperor's reign fluctuates.  We will rely on the data stored in the CLDR and access it via icu4j.

 

Formating dates and times

Problem:

You want to format a date correctly for a locale.

Solution:

Formatting dates and times correctly for a locale can prove challenging, especially considering the variety of possibilities.  Thankfully, Java provides a number of date formatting methods and classes.  icu4j adds even more tools to the programmers toolbox.

 

To format a date you need to get an instance of the DateFormat class passing the locale in:

//Get a locale object.  In this case we could also use the static constant Locale.FRENCH

Locale french = new Locale("fr");

//Get a DateFormat instance using the locale.  We also specify a length.

//Possible length values are DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL

//To demonstrate we will get an example of each

int[] lengths = {DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL};

//Loop through the lengths.  Get a DateFormat instance for each length and format a date

for(int x = 0; x < lengths.length; x++){

    DateFormat df = DateFormat.getDateInstance(lengths[x], french);

    System.out.println(df.format(new Date()));

}

 

 

The output:

 

29/11/08

29 nov. 2008

29 novembre 2008

samedi 29 novembre 2008

 

Format a time amount

Problem:

You want to format a time amount like "5 days" for a locale.

Solution:

TimeUnitFormat from icu4j provides some excellent formatting options for time units.  To use you specify a TimeUnitAmount which contains an amount and a unit.  Then specify a locale on the TimeUnitFormat.

To format 1 day in French:

//Get a TimeUnit
TimeUnit unit = TimeUnit.DAY;
//Specify the unit amount
TimeUnitAmount amount = new TimeUnitAmount(1,unit);
TimeUnitAmount amount2= new TimeUnitAmount(3,unit);
//Get a unit format
TimeUnitFormat format = new TimeUnitFormat();
//Get and set a ULocale
ULocale uloc = new ULocale("fr");
format.setLocale(uloc);
//Format and output
System.out.println(format.format(amount));
System.out.println(format.format(amount2));


The output:

1 jour
3 jours
 

Format a time interval

Problem:

You want to format a span of time.

Solution:

As of version 4, icu4j contains a DateIntervalFormat class.  This class makes it relatively easy to format an interval value.  The format will automatically format as compactly as possible. For example: if the difference between the two dates is only a few hours and both dates occur on the same day, the year, month, and day parts of the date will be omitted.

 

In order to try this example out you will need to download a copy of icu4j from http://icu-project.org/download/4.0.html#ICU4J .

 

Import the correct classes

import java.text.FieldPosition;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.DateIntervalFormat;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.ULocale;

Then simply get an instance of the DateIntervalFormat class and format:

//Get two calendar instances
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = (Calendar)cal1.clone();
//increment one calendar by one week.
cal2.add(Calendar.HOUR, 4);
cal2.add(Calendar.MINUTE, 34);
//Get an instance of DateIntervalFormat.  Specify the date format skeleton to use.
//The skeleton is an example format that will be used as a base for the interval format.
//You can specify your own skeleton format, or use one of the defaults in the DateFormat class
DateIntervalFormat dtIntervalFmt = DateIntervalFormat.getInstance(DateFormat.HOUR_MINUTE, new ULocale("ja"));
//Create a StringBuffer to hold the formatted value.
StringBuffer str = new StringBuffer("");
//Create a FieldPosition to specify the position for the StringBuffer
FieldPosition pos = new FieldPosition(0);
//format the interval.  The formatted value is placed in the StringBuffer.
dtIntervalFmt.format(cal1, cal2, str, pos);
System.out.println(str);

 

 Running this we get an output of "19時20分~23時54分".

Format and cast a date to a timezone

Problem:

You want to format a date and cast it to a timezone.

Solution:

The Java DateFormat class can cast a date to a new time zone at the same time as formatting it.  This can be accomplished simply by specifying a TimeZone on the DateFormat object.

 

To format and cast a date to PST:

//Get a Locale.  In this case we are going to use Afrikans in South Africa
Locale afrikans = new Locale("af","ZA");
//Get a DateFormat instance.
//We specify length for date and time and a locale to format for.
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, afrikans);
//Get a TimeZone instance for a specified id.
//The ids are Olsen TimeZone ids
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
//Specify the time zone
df.setTimeZone(tz);
//output the format
System.out.println(df.format(new Date()));

 

Output Example:

viernes 5 de diciembre de 2007 06:49:46 PM PST

Get all time zone ids

Problem:

You want to know what time zones are available on your system.

Solution:

Java uses the TimeZone class to handle date/time casting to and from UTC.  A TimeZone is retrieved by specifying a string id.  Most of these ids are Olsen time zone ids.  You can retrieve an array of time zone ids by calling the static getAvailableIDs() method.

 

To get all available IDs:

//Get all Timezone ids
String[] ids = TimeZone.getAvailableIDs();
//Loop through ids and output
for(int x = 0; x < ids.length; x++){
    System.out.println(ids[x]);
}

 

The output is very long, so I will omit it here.

Get an array of day names

 Problem:

You want to retrieve all of the day of the week names for a locale.

Solution:

The DateFormatSymbols class contains a wealth of information useful to the localization programmer.  You can easily retrieve day names, month names, era names, etc...

 

To get the days of the week in Korean and English:

//Get a DateFormatSymbols object using a locale as an argument

DateFormatSymbols dfsKorean = new DateFormatSymbols(Locale.KOREAN);

DateFormatSymbols dfsEnglish = new DateFormatSymbols(Locale.ENGLISH);

//Get an array of weekday names

String[] kWeekdays = dfsKorean.getWeekdays();

String[] eWeekdays = dfsEnglish.getWeekdays();

//Loop through the array and output the names

for(int x = 1; x < 8; x++){

    System.out.println(eWeekdays[x] + " = " + kWeekdays[x]);

}

 

 


The output:

Sunday = 일요일

Monday = 월요일

Tuesday = 화요일

Wednesday = 수요일

Thursday = 목요일

Friday = 금요일

Saturday = 토요일

 

Get an array of timezone ids for offset

Problem:

You know what your offset from UTC is and you want to know what timezones are available for that offset

Solution:

The Java TimeZone class uses string ids to retrieve an instance.  You can get a list of all TimeZone ids, but the list is quite large.  Luckily you can narrow the results by specifying an offset from UTC and retrieve only the results with that raw offset.

 

The offset is specified as milliseconds from UTC.  Go figure.

 

To get all TimeZone ids for an offset of -7:00 from UTC:

//Get all Timezone ids for an offset.
//For some reason the offset is in milliseconds. 
//To my knowledge there is no offset increment less than half an hour
//Here we get all ids for an offset of -7 hours from UTC
String[] ids = TimeZone.getAvailableIDs(-1000*60*60*7);
//Loop through ids and output
for(int x = 0; x < ids.length; x++){
    System.out.println(ids[x]);
}


 

Output:

America/Boise
America/Cambridge_Bay
America/Chihuahua
America/Dawson_Creek
America/Denver
America/Edmonton
America/Hermosillo
America/Inuvik
America/Mazatlan
America/Phoenix
America/Shiprock
America/Yellowknife
Canada/Mountain
Etc/GMT+7
MST
MST7MDT
Mexico/BajaSur
Navajo
PNT
SystemV/MST7
SystemV/MST7MDT
US/Arizona
US/Mountain

Get the best date format pattern

 Problem:

You know what parts of a date you want to display but you don't know the exact pattern to use.

Solution:

Often a Java programmer will know what type of pattern he wants, but not exactly what the pattern would be.  With icu4j's DateTimePatternGenerator you can specify a pattern skeleton, and it will return the most appropriate localized match.

 

To get the best pattern for the skeleton, "MMMddYYYYH" in Japanese:

//Get a Locale object

ULocale locale = new ULocale("ja_JP");

//Get an instance of the DatePatternGenerator for the locale

DateTimePatternGenerator dp = DateTimePatternGenerator.getInstance(locale);

//Get the best pattern match

String best = dp.getBestPattern("MMMddYYYYHH");

//output the best pattern match

System.out.println(best);

//Get a DateFormat for the pattern

DateFormat df = new SimpleDateFormat(best);

//output a formatted date

System.out.println(df.format(new Date()));

 


The output:

 

YYYY年MM月dd日 HH

2008年12月06日 15

 

As you can see the closest match uses a 4 digit year followed by a year symbol, a 2 digit month followed by a month symbol, a 2 digit day followed by a day symbol, and a 0~24 hour.

 

 

Get the display name for a Timezone

Problem:

You want to get a localized display name for a time zone.

Solution:

You can get a display name for a TimeZone in Java very easily by specifying a locale in the getDisplayName method.

 

To get a display name for Canada/Mountain in Japanese:

//Get a locale for japanese in Japan
Locale jp = new Locale("ja","JP");
//Get a TimeZone for the id Canada/Mountain
TimeZone tz = TimeZone.getTimeZone("Canada/Mountain");
//output the display name
System.out.println(tz.getDisplayName(jp));

 


The output:

山地標準時

Parse a formatted date string

Problem:

You want to parse a localized date string to a Java Date.

Solution:

As important as date formatting is, you have to be able to parse the formatted dates.  Parsing a date is very similar to formatting the date.  You just call the parse method on a DateFormat instance.

 

One important point is you need to specify the length of the DateFormat.  This can be difficult to know in advance sometimes.  You can wrap the parse attempt in a try catch to trap the ParseException and change the length of the DateFormat until you return a success.

 

To parse a date:

//Get a Locale
Locale chinese = new Locale("zh","CN");
//Get an instance of DateFormat.
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, chinese);
System.out.println(df.format(new Date()));
//Parse the date
//We need to handle the ParseException the parse method can throw
//The length specified in the DateFormat.getDateInstance method has to be the
//same as the string you are trying to parse, or you will get a ParseException in many cases.
try {
    //parse(String str) returns a Date
    Date date = df.parse("2008年11月30日 星期日");
    System.out.println(date.toString());
} catch (ParseException e) {
    e.printStackTrace();
}


 

The output:

2008年11月30日 星期日 Sun Nov 30 00:00:00 EST 2008