This problem has several different aspects:
Astronomical aspects
- For a given date and time in location A, what time is it in location B?
- What is the UTC time, now?
Legal aspects
- For a given UTC time, what legal time is it in location X?
- What is the first week of the year in country A?
- What is the first week of the year in country B?
Misc aspects
- What is the difference between Time Zone and Time Offset?
- java.util.Date
- java.util.Calendar
- java.text.SimpleDateFormat
- java.util.TimeZone
- the format
- the calendar
When you set the TimeZone at the Calendar level, you are setting the date at a given TimeZone. For example, March 1st 2012 at 12:00 Pacific Time.
When you set the TimeZone at the Format level, you do so to display the date & time set previously as viewed from another time zone. For example you set the date as above (US West Coast), and you want to view it from the US East Coast. Notice that in that case, the date remains unchanged. Only the way to display it is modified.
- Note:
- We are explicitly setting the TimeZones here, for clarity. If not explicitly set, the default TimeZone is used.
private final static SimpleDateFormat SDF = new SimpleDateFormat("EEE dd MMMM yyyy HH:mm:ss.SSS Z (z)"); ... Calendar cal = Calendar.getInstance(); cal.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); cal.set(Calendar.YEAR, 2012); cal.set(Calendar.MONTH, Calendar.MARCH); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 12); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); SDF.setTimeZone(TimeZone.getTimeZone("America/New_York")); System.out.println("New York: \t Date is " + SDF.format(cal.getTime())); SDF.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); System.out.println("San Francisco:\t Date is " + SDF.format(cal.getTime()));Output:
New York: Date is Thu 01 March 2012 15:00:00.000 -0500 (EST) San Francisco: Date is Thu 01 March 2012 12:00:00.000 -0800 (PST)More examples will be given below.
The default time zone is found from the TimeZone Object:
TimeZone tz = TimeZone.getDefault(); System.out.println("Default Time Zone:" + tz.getID() + ", " + tz.getDisplayName());Output:
Default Time Zone:America/Los_Angeles, Pacific Standard TimeThe TimeZone object will also provide the list of all the valid time zones.
String[] ids = TimeZone.getAvailableIDs(); for (String s : ids) System.out.println(s);Output:
Etc/GMT+12 Etc/GMT+11 MIT Pacific/Apia Pacific/Midway Pacific/Niue Pacific/Pago_Pago Pacific/Samoa US/Samoa America/Adak America/Atka Etc/GMT+10 HST Pacific/Fakaofo Pacific/Honolulu Pacific/Johnston Pacific/Rarotonga Pacific/Tahiti SystemV/HST10 US/Aleutian ...Notice in the list above the different kind of time zones:
- Etc/GMT+12
- PDT
- America/Los_Angeles
- Etc/GMT+12 refers to a fixed time offset, of 12 hours in that case
- PDT refers to the time in use during the winter on the US West Coast
- America/Los_Angeles refers to a location where the time in use can be PDT and PST. The time offset is different for those two times.
private final static SimpleDateFormat SDF = new SimpleDateFormat("EEE dd MMMM yyyy HH:mm:ss.SSS Z (z)"); ... // March 1st 2012 Calendar cal = GregorianCalendar.getInstance(); SDF.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); cal.set(Calendar.YEAR, 2012); cal.set(Calendar.MONTH, Calendar.MARCH); cal.set(Calendar.DAY_OF_MONTH, 1); System.out.println("Pacific Coast:\t Date is " + SDF.format(cal.getTime())); // June 1st 2012 cal.set(Calendar.YEAR, 2012); cal.set(Calendar.MONTH, Calendar.JUNE); cal.set(Calendar.DAY_OF_MONTH, 1); System.out.println("Pacific Coast:\t Date is " + SDF.format(cal.getTime()));Output:
Pacific Coast: Date is Thu 01 March 2012 00:00:00.000 -0800 (PST) Pacific Coast: Date is Fri 01 June 2012 00:00:00.000 -0700 (PDT)Notice the Time in use, and the Time Offset. The Time Zone remains the same.
Some Time Zones use Daylight saving, other do not:
cal.set(Calendar.YEAR, 2012); cal.set(Calendar.MONTH, Calendar.MARCH); cal.set(Calendar.DAY_OF_MONTH, 1); SDF.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); System.out.println("Pacific Coast:\t Date is " + SDF.format(cal.getTime())); SDF.setTimeZone(TimeZone.getTimeZone("Pacific/Honolulu")); System.out.println("Hawaii:\t Date is " + SDF.format(cal.getTime())); cal.set(Calendar.YEAR, 2012); cal.set(Calendar.MONTH, Calendar.JUNE); cal.set(Calendar.DAY_OF_MONTH, 1); SDF.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); System.out.println("Pacific Coast:\t Date is " + SDF.format(cal.getTime())); SDF.setTimeZone(TimeZone.getTimeZone("Pacific/Honolulu")); System.out.println("Hawaii:\t Date is " + SDF.format(cal.getTime()));Output:
Pacific Coast: Date is Thu 01 March 2012 00:00:00.000 -0800 (PST) Hawaii: Date is Wed 29 February 2012 22:00:00.000 -1000 (HST) Pacific Coast: Date is Fri 01 June 2012 00:00:00.000 -0700 (PDT) Hawaii: Date is Thu 31 May 2012 21:00:00.000 -1000 (HST)Hawaiian Standard Time remains the same, Pacific Time goes form Daylight to Standard.
The TimeZone can be set at the Format level, or at the Calendar level:
Calendar cal = GregorianCalendar.getInstance(); System.out.println("Cal:" + cal.getTime()); System.out.println("Default Time zone:\t Date is " + SDF.format(cal.getTime())); // Set the time zone on the FORMAT to display the UTC time SDF.setTimeZone(TimeZone.getTimeZone("Etc/UTC")); System.out.println("Mask set to UTC:\t Date is " + SDF.format(cal.getTime())); // Set the TimeZone at the DATE level System.out.println("HOUR is " + cal.get(Calendar.HOUR_OF_DAY) + ", before changing the Date's TZ"); cal.setTimeZone(TimeZone.getTimeZone("Etc/UTC")); System.out.println("HOUR is now " + cal.get(Calendar.HOUR_OF_DAY)); System.out.println("Date changed to UTC:\t Date is " + SDF.format(cal.getTime())); // The date remains the same. System.out.println("Cal:" + cal.getTime());Output:
Cal:Tue Jun 26 10:26:35 PDT 2012 Default Time zone: Date is Tue 26 June 2012 10:26:35.606 -0700 (PDT) Mask set to UTC: Date is Tue 26 June 2012 17:26:35.606 +0000 (UTC) HOUR is 10, before changing the Date's TZ HOUR is now 17 Date changed to UTC: Date is Tue 26 June 2012 17:26:35.606 +0000 (UTC) Cal:Tue Jun 26 10:26:35 PDT 2012Notice above that changing the Date's TimeZone automatically adjusts the offsets (the HOUR_OF_DAY in that case). Only the TimeZone is changed, not the actual original date, it still describes the same instant, the exact same point in time.
For a given UTC Time, what time is it in San Francisco, and in Hawai'i:
Calendar cal = GregorianCalendar.getInstance(); cal.setTimeZone(TimeZone.getTimeZone("Etc/UTC")); cal.set(Calendar.YEAR, 2012); cal.set(Calendar.MONTH, Calendar.MARCH); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 12); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); SDF.setTimeZone(TimeZone.getTimeZone("Etc/UTC")); System.out.println("UTC:\t Date is " + SDF.format(cal.getTime())); SDF.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); System.out.println("San Francisco:\t Date is " + SDF.format(cal.getTime())); SDF.setTimeZone(TimeZone.getTimeZone("Pacific/Honolulu")); System.out.println("Hawaii:\t Date is " + SDF.format(cal.getTime()));In the code, we set the TimeZone at the Calendar level, meaning that we set the date at March 1st, 2012, at 12:00 UTC. Then we display it, viewed from "Etc/UTC", "America/Los_Angeles", and "Pacific/Honolulu".
UTC: Date is Thu 01 March 2012 12:00:00.000 +0000 (UTC) San Francisco: Date is Thu 01 March 2012 04:00:00.000 -0800 (PST) Hawaii: Date is Thu 01 March 2012 02:00:00.000 -1000 (HST)Also, notice something important: some TimeZones do not have the same TimeOffsets all over the year. The Time Offset is automatically adjusted when you use a TimeZone subject to daylight saving.
You can manipulate the Calendar directly, without having to use a format. Let's assume you've set - like above - a Calendar at 12:00 UTC, on March 1st 2012. And you want to know the hour of the day on the US West Coast:
cal.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); System.out.println(cal.get(Calendar.YEAR) + "-" + (cal.get(Calendar.MONTH) + 1) + "-" + cal.get(Calendar.DAY_OF_MONTH) + ", " + cal.get(Calendar.HOUR_OF_DAY) + " hour(s).);Output:
2012-3-1, 4 hour(s).Notice that the months index begins with 0 (we had to add 1).
An aspect of the Country, the legal time and time zone
In some countries, the week begins on Sundays. In some others, it begins on Mondays.Let us run the following code different ways:
Calendar cal = new GregorianCalendar(2012, Calendar.JANUARY, 1); SimpleDateFormat sdf = new SimpleDateFormat("EEEE dd-MMMM-yyyy '\tis in week' w"); System.out.println(sdf.format(cal.getTime()));The US way:
Prompt> java -Duser.language=en -Duser.country=US sometests.FirstWeekTest Sunday 01-January-2012 is in week 1The British way:
Prompt> java -Duser.language=en -Duser.country=GB sometests.FirstWeekTest Sunday 01-January-2012 is in week 52The French way:
Prompt> java -Duser.language=fr -Duser.country=FR sometests.FirstWeekTest dimanche 01-janvier-2012 is in week 52The Swedish way:
Prompt> java -Duser.language=sv -Duser.country=SE sometests.FirstWeekTest söndag 01-januari-2012 is in week 52Sunday is the first day of the week in the US, but not in Europe. As a result, the number of the week is affected! Week #1 is the first one to begin in the year.
In Europe, January 1st 2012 is part of the last week of 2011. This last week's number is 53 (yes 53, this is not a typo) in the US, 52 in Europe.
This can be something to consider when making cross-continent appointments, like in "Let us meet on week 17".
Never underestimate date and time management, it can be a quite complex problem, to say the least.
At the end of the XIXth century, a clerk was affected to the synchronization of the clocks on the railroad network of Switzerland.
He was later awarded the Nobel Price of Physics in 1921.
His name was Albert Einstein...
Excellent! Great article, thank you!
ReplyDelete