2

The following code is what I already have:

DateFormat f = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Java_Locale);
SimpleDateFormat sf = (SimpleDateFormat) f;
String pattern = sf.toPattern();

With the above code, I am able to get the PROPER date/time pattern based on the locale. For example: "M/d/yy h:mm a" for US English, "yy-M-d ah:mm" for Chinese.

However, this pattern does not have the time zone information. I hope to be able to add time zone into the pattern. For example, "M/d/yy h:mm a z" for English, but I don't want to specify the pattern for other locales. I hope to get the proper pattern with time zone based on a given locale, something similar to "M/d/yy h:mm a z" for other locales.

I use Java 8.

curious1
  • 14,155
  • 37
  • 130
  • 231
  • Are the time-zones locale-specific? Why not to just retrieve the current timezone and add to already formatted string? – Alexey R. Aug 22 '17 at 19:58
  • Time zones can be any of of Java supports, and they are independent of locales. I am not sure simply appending the "z" to the formatted pattern string would create a new format that is proper to any given locale. – curious1 Aug 22 '17 at 20:53
  • Is there some reason you aren't using the `java.time` classes like `DateTimeFormatter`? – Sean Van Gorder Aug 22 '17 at 21:26
  • 2
    FYI, if you don't strictly need localized formats, you might consider using standard [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formats which include the offset-from-UTC, further extended by the java.time class [`ZonedDateTime`] to append the name of the time zone in square brackets. The standard formats are generally understandable across cultures. Ex: `2017-08-22T16:30:48.399-07:00[America/Los_Angeles]` – Basil Bourque Aug 22 '17 at 23:31

2 Answers2

4

z is a valid pattern for SimpleDateFormat (according to javadoc, it's the timezone designator) for any locale.

The only difference is that for some values the result might be locale dependent (example: if you use zzzz, the timezone America/Los_Angeles can be formatted as Pacific Daylight Time in English (as it's currently in Daylight Saving Time) or Horário de luz natural do Pacífico in Portuguese), but the pattern z itself is not invalid regardless of the locale.

And getDateTimeInstance will use predefined built-in hardcoded patterns. As the short patterns usually don't include the timezone, you'll have to add the z manually:

DateFormat f = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ENGLISH);
SimpleDateFormat sf = (SimpleDateFormat) f;
String pattern = sf.toPattern();

// add z to the format, use the same locale
SimpleDateFormat sdf = new SimpleDateFormat(pattern + " z", Locale.ENGLISH);

Java new Date/Time API

The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.

As you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.

Unfortunately the predefined built-in patterns are still hardcoded and you have to add the timezone manually, but at least you'll get rid of all the problems explained in the links above:

import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.FormatStyle;
import java.time.ZonedDateTime;

// get built-in localized format for a specified locale
String pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT,
                     FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.ENGLISH);
// create a formatter, add the timezone manually, use same locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern + " z", Locale.ENGLISH);
// format a date
System.out.println(fmt.format(ZonedDateTime.now()));

As you're printing the timezone, I'm using a ZonedDateTime, which represents a date and a time in a specific timezone. Check the tutorial for more details about the new date types.

DateTimeFormatter also have more options than SimpleDateFormat. Check the javadoc for details.


If you still need interoperability with a java.util.Date, you can easily convert it to the new API:

// convert to Instant (UTC)
ZonedDateTime z = new Date().toInstant()
    // convert to some timezone
    .atZone(ZoneId.of("Europe/London"));

The API uses IANA timezones names (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin). Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.

  • Hi Hugo, adding "z" to the pattern is not always accurate, which is why I posted the question in the first place. Please see Sean's answer. Thanks SO much for your detailed answer, which will surely help many others. Regards. – curious1 Aug 23 '17 at 13:28
  • 1
    @curious1 No problem. When changing these pre-defined built-in formats, there's always a risk to mess up something. Glad you found an answer, good luck! –  Aug 23 '17 at 13:30
1
DateFormat f = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL, Java_Locale);

The FULL time style includes the time zone. This will make the time more complex, though.

Note: just adding a z to the pattern string is not always accurate. For instance, Arabic language locales put the time zone between the date and time:

Locale Java_Locale = Locale.forLanguageTag("ar");
DateFormat f = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL, Java_Locale);
SimpleDateFormat sf = (SimpleDateFormat) f;
String pattern = sf.toPattern(); // "dd/MM/yy z hh:mm:ss a"
Sean Van Gorder
  • 3,393
  • 26
  • 26
  • Thanks, Sean. `just adding a z to the pattern string is not always accurate.`-->this is exactly what I am concerned about. – curious1 Aug 23 '17 at 02:18