Java - преобразование даты и времени между часовыми поясами
В этом руководстве мы покажем вам несколько примеров (ZonedDateTime (Java 8),Date,Calendar иJoda Time) для преобразования даты и времени между разными часовыми поясами.
Все примеры будут конвертировать дату и время из
(UTC+8:00) Asia/Singapore - Singapore Time Date : 22-1-2015 10:15:55 AM
to
(UTC-5:00) America/New_York - Eastern Standard Time Date : 21-1-2015 09:15:55 PM
Which to use?
Для часового пояса избегайте какDate
, так иCalendar
-
Если вы используете JDK> = 8, используйте новую структуру
java.time.*
. -
Если вы используете JDK <8, используйте Joda Time. (Новая структура Java 8
java.time.*
вдохновлена этой библиотекой)
1. ZonedDateTime
Всегда используйте этот новый Java 8java.time.ZonedDateTime
для представления даты и времени, содержащих часовой пояс.
ZonedDateTimeExample.java
package com.example.date; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; public class ZonedDateTimeExample { private static final String DATE_FORMAT = "dd-M-yyyy hh:mm:ss a"; public static void main(String[] args) { String dateInString = "22-1-2015 10:15:55 AM"; LocalDateTime ldt = LocalDateTime.parse(dateInString, DateTimeFormatter.ofPattern(DATE_FORMAT)); ZoneId singaporeZoneId = ZoneId.of("Asia/Singapore"); System.out.println("TimeZone : " + singaporeZoneId); //LocalDateTime + ZoneId = ZonedDateTime ZonedDateTime asiaZonedDateTime = ldt.atZone(singaporeZoneId); System.out.println("Date (Singapore) : " + asiaZonedDateTime); ZoneId newYokZoneId = ZoneId.of("America/New_York"); System.out.println("TimeZone : " + newYokZoneId); ZonedDateTime nyDateTime = asiaZonedDateTime.withZoneSameInstant(newYokZoneId); System.out.println("Date (New York) : " + nyDateTime); DateTimeFormatter format = DateTimeFormatter.ofPattern(DATE_FORMAT); System.out.println("\n---DateTimeFormatter---"); System.out.println("Date (Singapore) : " + format.format(asiaZonedDateTime)); System.out.println("Date (New York) : " + format.format(nyDateTime)); } }
Выход
TimeZone : Asia/Singapore Date (Singapore) : 2015-01-22T10:15:55+08:00[Asia/Singapore] TimeZone : America/New_York Date (New York) : 2015-01-21T21:15:55-05:00[America/New_York] ---DateTimeFormatter--- Date (Singapore) : 22-1-2015 10:15:55 AM Date (New York) : 21-1-2015 09:15:55 PM
Note
Обратитесь к этомуZonedDateTime
tutorial для получения дополнительных примеров часового пояса, настраиваемого смещения и перехода на летнее время (DST).
2. Date
Notejava.util.Date
не имеет понятия о часовом поясе и представляет только количество секунд, прошедших с момента эпохи Unix - 1970-01-01T00: 00: 00Z. Но если вы напечатаете объект Date напрямую, объект Date всегда будет печататься с системным часовым поясом по умолчанию. Проверьте исходный кодDate.toString()
.
2.1 Set a time zone to DateFormat
and format the java.util.Date
SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a"); sdfAmerica.setTimeZone(TimeZone.getTimeZone("America/New_York")); String sDateInAmerica = sdfAmerica.format(date);
2.2 Full example
DateExample.java
package com.example.date; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; public class DateExample { private static final String DATE_FORMAT = "dd-M-yyyy hh:mm:ss a"; public static void main(String[] args) throws ParseException { SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT); String dateInString = "22-01-2015 10:15:55 AM"; Date date = formatter.parse(dateInString); TimeZone tz = TimeZone.getDefault(); // From TimeZone Asia/Singapore System.out.println("TimeZone : " + tz.getID() + " - " + tz.getDisplayName()); System.out.println("TimeZone : " + tz); System.out.println("Date (Singapore) : " + formatter.format(date)); // To TimeZone America/New_York SimpleDateFormat sdfAmerica = new SimpleDateFormat(DATE_FORMAT); TimeZone tzInAmerica = TimeZone.getTimeZone("America/New_York"); sdfAmerica.setTimeZone(tzInAmerica); String sDateInAmerica = sdfAmerica.format(date); // Convert to String first Date dateInAmerica = formatter.parse(sDateInAmerica); // Create a new Date object System.out.println("\nTimeZone : " + tzInAmerica.getID() + " - " + tzInAmerica.getDisplayName()); System.out.println("TimeZone : " + tzInAmerica); System.out.println("Date (New York) (String) : " + sDateInAmerica); System.out.println("Date (New York) (Object) : " + formatter.format(dateInAmerica)); } }
Выход
TimeZone : Asia/Kuala_Lumpur - Malaysia Time TimeZone : sun.util.calendar.ZoneInfo[id="Asia/Kuala_Lumpur",...] Date (Singapore) : 22-1-2015 10:15:55 AM TimeZone : America/New_York - Eastern Standard Time TimeZone : sun.util.calendar.ZoneInfo[id="America/New_York",...] Date (New York) (String) : 21-1-2015 09:15:55 PM Date (New York) (Object) : 21-1-2015 09:15:55 PM
3. Календарь
3.1 A Calendar example to set a time zone :
Calendar calendar = new GregorianCalendar(); calendar.setTime(date); calendar.setTimeZone(tzInAmerica);
Очень распространенная ошибка - получитьjava.util.Date
прямо вот так:
//Wrong, it will display 22-1-2015 10:15:55 AM, time is still in the system default time zone! Date dateInAmerican = calendar.getTime());
В приведенном выше примере независимо от того, какой часовой пояс вы установили в календаре, объект Date всегда будет печататься с системным часовым поясом по умолчанию. (Проверьте исходный кодDate.toString()
)
3.2 The correct way should be using the DateFormat
to format it :
SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a"); TimeZone tzInAmerica = TimeZone.getTimeZone("America/New_York"); sdfAmerica.setTimeZone(tzInAmerica); sdfAmerica.format(calendar.getTime())
или получите дату черезcalendar.get()
:
int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); // Jan = 0, dec = 11 int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); int hour = calendar.get(Calendar.HOUR); // 12 hour clock int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY); // 24 hour clock int minute = calendar.get(Calendar.MINUTE); int second = calendar.get(Calendar.SECOND); int ampm = calendar.get(Calendar.AM_PM); //0 = AM , 1 = PM
3.3 Full example
CalendarExample.java
package com.example.date; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; public class CalendarExample { private static final String DATE_FORMAT = "dd-M-yyyy hh:mm:ss a"; public static void main(String[] args) throws ParseException { SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT); String dateInString = "22-01-2015 10:15:55 AM"; Date date = formatter.parse(dateInString); TimeZone tz = TimeZone.getDefault(); // From TimeZone Asia/Singapore System.out.println("TimeZone : " + tz.getID() + " - " + tz.getDisplayName()); System.out.println("TimeZone : " + tz); System.out.println("Date (Singapore) : " + formatter.format(date)); // To TimeZone America/New_York SimpleDateFormat sdfAmerica = new SimpleDateFormat(DATE_FORMAT); TimeZone tzInAmerica = TimeZone.getTimeZone("America/New_York"); sdfAmerica.setTimeZone(tzInAmerica); Calendar calendar = new GregorianCalendar(); calendar.setTime(date); calendar.setTimeZone(tzInAmerica); System.out.println("\nTimeZone : " + tzInAmerica.getID() + " - " + tzInAmerica.getDisplayName()); System.out.println("TimeZone : " + tzInAmerica); //Wrong! It will print the date with the system default time zone System.out.println("Date (New York) (Wrong!): " + calendar.getTime()); //Correct! need formatter System.out.println("Date (New York) (Correct!) : " + sdfAmerica.format(calendar.getTime())); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); // Jan = 0, dec = 11 int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); int hour = calendar.get(Calendar.HOUR); // 12 hour clock int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY); // 24 hour clock int minute = calendar.get(Calendar.MINUTE); int second = calendar.get(Calendar.SECOND); int ampm = calendar.get(Calendar.AM_PM); //0 = AM , 1 = PM //Correct System.out.println("\nyear \t\t: " + year); System.out.println("month \t\t: " + month + 1); System.out.println("dayOfMonth \t: " + dayOfMonth); System.out.println("hour \t\t: " + hour); System.out.println("minute \t\t: " + minute); System.out.println("second \t\t: " + second); System.out.println("ampm \t\t: " + ampm); } }
Выход
TimeZone : Asia/Kuala_Lumpur - Malaysia Time TimeZone : sun.util.calendar.ZoneInfo[id="Asia/Kuala_Lumpur",...] Date (Singapore) : 22-1-2015 10:15:55 AM TimeZone : America/New_York - Eastern Standard Time TimeZone : sun.util.calendar.ZoneInfo[id="America/New_York",...]] Date (New York) (Wrong!): Thu Jan 22 10:15:55 MYT 2015 Date (New York) (Correct!) : 21-1-2015 09:15:55 PM year : 2015 month : 01 dayOfMonth : 21 hour : 9 minute : 15 second : 55 ampm : 1
4. Время йода
4.1 A Joda Time example to set a time zone :
DateTime dt = new DateTime(date); DateTimeZone dtZone = DateTimeZone.forID("America/New_York"); DateTime dtus = dt.withZone(dtZone);
Опять же, распространенная ошибка - получить дату прямо вот так, часовой пояс будет потерян.
//Output : 22-1-2015 10:15:55 AM Date dateInAmerica = dtus.toDate();
Правильный способ сначала конвертируется в JodaLocalDateTime
.
//Output : 21-1-2015 09:15:55 PM Date dateInAmerica = dtus.toLocalDateTime().toDate();
4.2 Full example
JodaTimeExample.java
package com.example.date; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; public class JodaTimeExample { private static final String DATE_FORMAT = "dd-M-yyyy hh:mm:ss a"; public static void main(String[] args) throws ParseException { SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT); String dateInString = "22-01-2015 10:15:55 AM"; Date date = formatter.parse(dateInString); TimeZone tz = TimeZone.getDefault(); // From TimeZone Asia/Singapore System.out.println("TimeZone : " + tz.getID() + " - " + tz.getDisplayName()); System.out.println("TimeZone : " + tz); System.out.println("Date (Singapore) : " + formatter.format(date)); // To TimeZone America/New_York SimpleDateFormat sdfAmerica = new SimpleDateFormat(DATE_FORMAT); DateTime dt = new DateTime(date); DateTimeZone dtZone = DateTimeZone.forID("America/New_York"); DateTime dtus = dt.withZone(dtZone); TimeZone tzInAmerica = dtZone.toTimeZone(); Date dateInAmerica = dtus.toLocalDateTime().toDate(); //Convert to LocalDateTime first sdfAmerica.setTimeZone(tzInAmerica); System.out.println("\nTimeZone : " + tzInAmerica.getID() + " - " + tzInAmerica.getDisplayName()); System.out.println("TimeZone : " + tzInAmerica); System.out.println("DateTimeZone : " + dtZone); System.out.println("DateTime : " + dtus); System.out.println("dateInAmerica (Formatter) : " + formatter.format(dateInAmerica)); System.out.println("dateInAmerica (Object) : " + dateInAmerica); } }
Выход
TimeZone : Asia/Kuala_Lumpur - Malaysia Time TimeZone : sun.util.calendar.ZoneInfo[id="Asia/Kuala_Lumpur",...] Date (Singapore) : 22-1-2015 10:15:55 AM TimeZone : America/New_York - Eastern Standard Time TimeZone : sun.util.calendar.ZoneInfo[id="America/New_York",...] DateTimeZone : America/New_York DateTime : 2015-01-21T21:15:55.000-05:00 dateInAmerica (Formatter) : 21-1-2015 09:15:55 PM dateInAmerica (Object) : Wed Jan 21 21:15:55 MYT 2015
P.S Tested with Joda-time 2.9.4