Reputation: 43
In the following snippet, I want to change the time-zone used by String.format()
long mls = System.currentTimeMillis();
String time = String.format("%tT %tZ", mls, mls);
System.out.println("TIME: " + time + " \n");
Upvotes: 2
Views: 2179
Reputation: 86343
The format strings used by the Formatter
class, String.format()
and others accept a wealth of types for dates and times. For example:
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Lisbon"));
String time = String.format("%tT %<tZ", zdt);
System.out.println("TIME: " + time + " \n");
Output:
TIME: 18:33:05 WEST
I believe it’s WEST for Western European Summer Time.
Not that you should really want to output a four letter time zone abbreviation, now we’re at it. These abbreviations tend to be ambiguous and are not standardized. Over uppercase Z
for time zone I’d prefer lowercase z
for offset from UTC. They are never ambiguous. Unfortunately it doesn’t seem that the long time zone name like Europe/Lisbon is an option here. For that you could use DateTimeFormatter
.
From the docs: “Date/Time - may be applied to Java types which are capable of encoding a date or time: long
, Long
, Calendar
, Date
and TemporalAccessor
”. The last is an interface implemented by most of the modern date and time classes including DayOfWeek
, HijrahDate
, HijrahEra
, Instant
, IsoEra
, JapaneseDate
, JapaneseEra
, LocalDate
, LocalDateTime
, LocalTime
, MinguoDate
, MinguoEra
, Month
, MonthDay
, OffsetDateTime
, OffsetTime
, ThaiBuddhistDate
, ThaiBuddhistEra
, Year
, YearMonth
, ZonedDateTime
and ZoneOffset
.
I am using <
in the format string to use the same argument again so I don’t have to pass zdt
twice to format()
.
Upvotes: 2
Reputation: 159165
There are many ways to format a time with time zone in Java, String.format()
is the least flexible of them.
All 6 suggestions below are going to assume that you have a long
millisecond value (mls
), and need to format a time from that. The output from all 6 suggestions are the same.
If you insist on using String.format()
, you can control the time zone in various ways:
Since a long
, Long
, or java.util.Date
argument will use the default time zone of the JVM, you can change it using TimeZone.setDefault(TimeZone zone)
, however that is generally a bad idea, so I'd highly discourage you from doing this.
Since a Calendar
argument has a time zone, you can change your long
millisecond argument to use that:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Pacific/Honolulu"));
cal.setTimeInMillis(mls);
String time = String.format("%tT %tZ", cal, cal);
In Java 8, you can also use the new java.time
objects:
ZonedDateTime zdt = Instant.ofEpochMilli(mls).atZone(ZoneId.of("Pacific/Honolulu"));
String time = String.format("%tT %tZ", zdt, zdt);
If you don't have to use String.format()
, you should use new java.time
objects in Java 8. If on Java 6 or 7, you can add the ThreeTen Backport jar:
Using ZonedDateTime
to specify time zone:
ZonedDateTime zdt = Instant.ofEpochMilli(mls).atZone(ZoneId.of("Pacific/Honolulu"));
String time = zdt.format(DateTimeFormatter.ofPattern("HH:mm:ss z"));
Specifying time zone in the DateTimeFormatter
:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss z")
.withZone(ZoneId.of("Pacific/Honolulu"));
String time = fmt.format(Instant.ofEpochMilli(mls));
If you're on pre-Java 8, and don't want to add extra jar for ThreeTen Backport, you can do this:
Use SimpleDateFormat
:
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss z");
fmt.setTimeZone(TimeZone.getTimeZone("Pacific/Honolulu"));
String time = fmt.format(mls);
Note: All the code above uses Honolulu time, because that's the time zone I want to be in.
Upvotes: 4
Reputation:
If you take a look at javadoc, you'll see that the Z
pattern uses your JVM's default timezone:
'Z' A string representing the abbreviation for the time zone. This value will be adjusted as necessary for Daylight Saving Time. For long, Long, and Date the time zone used is the default time zone for this instance of the Java virtual machine. The Formatter's locale will supersede the locale of the argument (if any).
So, the easiest way is to change the default timezone, using the java.util.TimeZone
class. Example with some random timezone:
TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
long mls = System.currentTimeMillis();
String time = String.format("%tT %tZ", mls, mls);
System.out.println("TIME: " + time + " \n");
Output:
TIME: 14:03:54 BST
I don't think that's the best way to format a date, specially because it depends on the system's default timezone (which can be changed at runtime and break your code), and it uses the old API (TimeZone
class).
Now Java has a new API which makes things much easier.
If 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.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time
and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp
), but the classes and methods names are the same.
As you want just the time (hour/minute/second), you can use the LocalTime
class, and a DateTimeFormatter
to customize the output format. I also used the ZoneId
class, to specify the timezone:
// get current time in London
LocalTime now = LocalTime.now(ZoneId.of("Europe/London"));
// formatter for HH:mm:ss output
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(fmt.format(now)); // 14:09:22
The output is:
14:09:22
Note that I used Europe/London
as timezone. Prefer to use these long names, because the short names (like CST
or IST
) are ambiguous and not standard.
You can get a list of all available timezones with ZoneId.getAvailableZoneIds()
.
If you want to output the timezone short name (like the pattern %tZ
does), you'll have to use a ZonedDateTime
class, because a LocalTime
has no timezone information on it:
// get current date/time in London
ZonedDateTime z = ZonedDateTime.now(ZoneId.of("Europe/London"));
// formatter for "HH:mm:ss zone" output
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss z");
System.out.println(fmt.format(z)); // 14:09:22 BST
In this case, the output will be:
14:09:22 BST
You can take a look at DateTimeFormatter
javadoc to see all possible formats.
Upvotes: 3