时区转换

时间:2011-07-04 06:15:18

标签: java datetime timezone

我需要在项目中将一个时区转换为另一个时区。

我可以将当​​前时区转换为另一个时区,但不能从不同的时区转换为另一个时区。

例如我在印度,我可以使用Date d=new Date();从印度转换为美国并将其分配给日历对象并设置时区。

但是,我不能从不同的时区到另一个时区。例如,我在印度,但我无法将时区从美国转换到英国。

14 个答案:

答案 0 :(得分:43)

TL;博士

ZonedDateTime.now( ZoneId.of( "Pacific/Auckland" ))              // Current moment in a particular time zone.
             .withZoneSameInstant( ZoneId.of( "Asia/Kolkata" ))  // Same moment adjusted into another time zone. 

详细

java.util.Date类没有分配的时区,但它的toString实现混乱地应用了JVM的当前默认时区。

避免使用java.util.Date& .Calendar

这是避免与Java捆绑的臭名昭着的java.util.Date,.Calendar和SimpleDateFormat类的众多原因之一。避免他们。而是使用:

java.time

Java 8及更高版本内置了Joda-Time。这个包的灵感来自java.time package。虽然它们有一些相似之处和类名,但它们是不同的;每个都有其他缺乏的功能。一个值得注意的区别是java.time避免使用构造函数,而是使用静态实例化方法。两个框架都由同一个人Joda-Time领导。

许多java.time功能已经被反向移植到Java 6& Stephen Colbourne项目中的7。在ThreeTen-Backport项目中进一步适应Android。

就本课题而言,它们的工作方式相同。指定一个时区,并调用ThreeTenABP方法获取当前时刻,然后根据旧的不可变实例创建一个新实例以调整时区。

请注意两个不同的时区类。一个是命名时区,包括夏令时的所有规则和其他此类异常加上与UTC的偏移,而另一个只是偏移。

ZoneId zoneMontréal = ZoneId.of("America/Montreal"); 
ZonedDateTime nowMontréal = ZonedDateTime.now ( zoneMontréal );

ZoneId zoneTokyo = ZoneId.of("Asia/Tokyo"); 
ZonedDateTime nowTokyo = nowMontréal.withZoneSameInstant( zoneTokyo );

ZonedDateTime nowUtc = nowMontréal.withZoneSameInstant( ZoneOffset.UTC );

约达时间

Joda-Time 2.3中的一些示例代码如下。搜索StackOveflow以获取更多示例和讨论。

DateTimeZone timeZoneLondon = DateTimeZone.forID( "Europe/London" );
DateTimeZone timeZoneKolkata = DateTimeZone.forID( "Asia/Kolkata" );
DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" );

DateTime nowLondon = DateTime.now( timeZoneLondon ); // Assign a time zone rather than rely on implicit default time zone.
DateTime nowKolkata = nowLondon.withZone( timeZoneKolkata );
DateTime nowNewYork = nowLondon.withZone( timeZoneNewYork );
DateTime nowUtc = nowLondon.withZone( DateTimeZone.UTC );  // Built-in constant for UTC.

我们在宇宙的时间轴上有四个相同时刻的表示。


实际上java.util.Date确实的时区埋没在now之内。但是为了大多数实际目的,该课程忽略了该时区。因此,作为速记,经常说j.u.Date没有指定时区。混乱?是。避免混乱是j.u.Date并使用Joda-Time和/或java.time。

答案 1 :(得分:38)

一些例子

Convert time between timezone

Converting Times Between Time Zones

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class TimeZoneExample {
    public static void main(String[] args) {
        // Create a calendar object and set it time based on the local
        // time zone
        Calendar localTime = Calendar.getInstance();
        localTime.set(Calendar.HOUR, 17);
        localTime.set(Calendar.MINUTE, 15);
        localTime.set(Calendar.SECOND, 20);

        int hour = localTime.get(Calendar.HOUR);
        int minute = localTime.get(Calendar.MINUTE);
        int second = localTime.get(Calendar.SECOND);


        // Print the local time
        System.out.printf("Local time  : %02d:%02d:%02d\n", hour, minute, second);


        // Create a calendar object for representing a Germany time zone. Then we
        // wet the time of the calendar with the value of the local time

        Calendar germanyTime = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"));
        germanyTime.setTimeInMillis(localTime.getTimeInMillis());
        hour = germanyTime.get(Calendar.HOUR);
        minute = germanyTime.get(Calendar.MINUTE);
        second = germanyTime.get(Calendar.SECOND);


        // Print the local time in Germany time zone
        System.out.printf("Germany time: %02d:%02d:%02d\n", hour, minute, second);
    }
}

答案 2 :(得分:7)

    Date date = new Date();
    String formatPattern = ....;
    SimpleDateFormat sdf = new SimpleDateFormat(formatPattern);

    TimeZone T1;
    TimeZone T2;

    // set the Calendar of sdf to timezone T1
    sdf.setTimeZone(T1);
    System.out.println(sdf.format(date));

    // set the Calendar of sdf to timezone T2
    sdf.setTimeZone(T2);
    System.out.println(sdf.format(date));

    // Use the 'calOfT2' instance-methods to get specific info
    // about the time-of-day for date 'date' in timezone T2.
    Calendar calOfT2 = sdf.getCalendar();

答案 3 :(得分:5)

只需为Calendar对象设置适当的时区,即可完全避免“默认”时区。但是,我个人建议您使用Joda Time作为Java中日期和时间操作的优秀API。除此之外,在Joda中,时区转换非常简单。

目前还不清楚您当前的代码是什么样的,以及为什么您只能通过默认时区进行转换,但在Joda Time中,您只需在创建(例如){{3}时明确指定时区} object,然后使用withZone(DateTimeZone zone)

如果您可以告诉我们更多关于您如何获取输入数据的信息,我们可以提供更全面的示例。

答案 4 :(得分:4)

您可以使用以下代码段

String dateString = "14 Jul 2014 00:11:04 CEST";
date = formatter.parse(dateString);
System.out.println(formatter.format(date));

// Set the formatter to use a different timezone - Indochina Time
formatter.setTimeZone(TimeZone.getTimeZone("Asia/Bangkok"));
System.out.println("ICT time : "+formatter.format(date));

答案 5 :(得分:2)

如果您不想使用Joda,这是使用内置库的确定性方法。

首先,我建议您强制JVM默认为时区。这解决了将JVM从一台计算机移动到另一台设置为不同时区但您的源数据始终是特定时区时可能遇到的问题。例如,假设您的数据始终是PDT / PST时区,但您运行的是设置为UTC时区的框。

以下代码段设置了JVM中的默认时区:

 //You can either pass the JVM a parameter that 
 //enforces a TZ: java -Duser.timezone=UTC or you can do it
 //programatically like this
 TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
 TimeZone.setDefault(tz);

现在假设您的源日期是以PDT / PST格式进入,但您需要将其转换为UTC。这些是步骤:

    DateFormat dateFormatUtc = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    dateFormatUtc.setTimeZone(TimeZone.getTimeZone("UTC"));

    String dateStrInPDT = "2016-05-19 10:00:00";
    Date dateInPDT = dateFormat.parse(dateStrInPDT);


    String dateInUtc = dateFormatUtc.format(dateInPDT);

    System.out.println("Date In UTC is " + dateInUtc);

输出结果为:

Date In UTC is 2016-05-19 17:00:00

答案 6 :(得分:2)

java.time

java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*

此外,下面引用的是 Home Page of Joda-Time 处的通知:

<块引用>

请注意,从 Java SE 8 开始,要求用户迁移到 java.time (JSR-310) - JDK 的核心部分,取代了该项目。

如何切换到现代 API?

使用 Date#toInstantjava.util.Date 转换为 Instant,例如

Date date = new Date();
Instant instant = date.toInstant();
System.out.println(instant); // 2021-05-30T13:10:01.890Z

Instant 与我的要求有什么关系?

Instant 代表 UTC 时间线上的一个瞬时点。示例输出中的 Z 是零时区偏移的 timezone designator。它代表祖鲁语并指定 Etc/UTC 时区(时区偏移为 +00:00 小时)。它的零时区偏移量使其独立于时区,即世界上每个地方的瞬间都是相同的。它类似于物理世界中的水。

您可以将时区(即 ZoneId)与 Instant 混合使用,方法是调用 Instant.atZone 以获取该时区(即 ZonedDateTime)中相应的日期时间。< /p>

同样,您可以通过调用 Instant#atOffset 将时区偏移量(即 ZoneOffset)与 Instant 混合以获取具有该时区偏移量的相应日期时间(即 {{1} }).

相反的方式,您还可以通过在 OffsetDateTime 或 {{1} 上调用 Instant 来获得 toInstant }}。

ZonedDateTime

输出:

OffsetDateTime

到目前为止,您已经学会了一种简单方法来转换 import java.time.Instant; import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Date; public class Main { public static void main(String[] args) { Date date = new Date(); Instant instant = date.toInstant(); System.out.println(instant); // The corresponding Date-Time in Chicago ZonedDateTime zdtChicago = instant.atZone(ZoneId.of("America/Chicago")); System.out.println(zdtChicago); // The corresponding Date-Time in Kolkata ZonedDateTime zdtKolkata = instant.atZone(ZoneId.of("Asia/Kolkata")); System.out.println(zdtKolkata); // The corresponding Date-Time at timezone offset of -05:00 hours OffsetDateTime odtAtOffsetMinus0500 = instant.atOffset(ZoneOffset.of("-05:00")); System.out.println(odtAtOffsetMinus0500); // The corresponding Date-Time at timezone offset of +05:30 hours OffsetDateTime odtAtOffset0530 = instant.atOffset(ZoneOffset.of("+05:30")); System.out.println(odtAtOffset0530); } } (您直接创建或从 2021-05-30T13:44:26.599Z 2021-05-30T08:44:26.599-05:00[America/Chicago] 2021-05-30T19:14:26.599+05:30[Asia/Kolkata] 2021-05-30T08:44:26.599-05:00 2021-05-30T19:14:26.599+05:30 Instantjava.util.Date) 到任何时区或任何时区偏移的日期时间。

或者

另一种方法可以将 ZonedDateTime 从一个时区转换为另一个时区。同样,有一种类似的方法可以将 OffsetDateTime 从一个时区偏移量转换为另一个时区偏移量。

ZonedDateTime

输出:

OffsetDateTime

何时使用import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; public class Main { public static void main(String[] args) { // Current Date-Time in Chicago ZonedDateTime zdtChicago = ZonedDateTime.now(ZoneId.of("America/Chicago")); System.out.println(zdtChicago); // The corresponding Date-Time in Kolkata ZonedDateTime zdtKolkata = zdtChicago.withZoneSameInstant(ZoneId.of("Asia/Kolkata")); System.out.println(zdtKolkata); // Current Date-Time at a timezone offset of -05:00 hours OffsetDateTime odtAtOffsetMinus0500 = OffsetDateTime.now(ZoneOffset.of("-05:00")); System.out.println(odtAtOffsetMinus0500); // The corresponding Date-Time at timezone offset of +05:30 hours OffsetDateTime odtAtOffset0530 = odtAtOffsetMinus0500.withOffsetSameInstant(ZoneOffset.of("+05:30")); System.out.println(odtAtOffset0530); } } ,何时使用2021-05-30T10:03:59.895923-05:00[America/Chicago] 2021-05-30T20:33:59.895923+05:30[Asia/Kolkata] 2021-05-30T10:03:59.897782-05:00 2021-05-30T20:33:59.897782+05:30

  • 如果您正在处理固定的时区偏移值,例如ZonedDateTime 小时,使用 OffsetDateTime。所有 JDBC 驱动程序也支持它。查看 this answer 以了解更多信息。
  • 如果您希望时区偏移量根据 DST 自动更改,请使用 02:00。遗憾的是,JDBC 不支持 OffsetDateTime

modern Date-Time API 中详细了解 ZonedDateTimeTrail: Date Time*


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

答案 7 :(得分:1)

您可以执行以下操作以获取其他时区的当前时间。

Calendar japanCal = new GregorianCalendar(TimeZone.getTimeZone("Japan"));
japanCal.setTimeInMillis(local.getTimeInMillis());

答案 8 :(得分:1)

取决于“转换”的真正含义。

它可能就像在FORMATTER中设置时区一样简单,而不是简单地使用日历。

Calendar cal = Calendar.getInstance();

TimeZone tzUTC = TimeZone.getTimeZone( "UTC" );
TimeZone tzPST = TimeZone.getTimeZone( "PST8PDT" );

DateFormat dtfmt = new SimpleDateFormat( "EEE, yyyy-MM-dd KK:mm a z" );

dtfmt.setTimeZone( tzUTC );
System.out.println( "UTC: " + dtfmt.format( cal.getTime() ));

dtfmt.setTimeZone( tzPST );
System.out.println( "PST: " + dtfmt.format( cal.getTime() ));

答案 9 :(得分:1)

您可以使用java.time.ZoneDateTime#ofInstant()方法:

import java.time.*;

public class TimeZonesConversion {
    static ZonedDateTime convert(ZonedDateTime time, ZoneId newTimeZone) {
        return ZonedDateTime.ofInstant(
                time.toInstant(),
                newTimeZone);
    };

    public static void main(String... args) {
        ZonedDateTime mstTime = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("-07")); 
        ZonedDateTime localTime = convert(mstTime, Clock.systemDefaultZone().getZone());
        System.out.println("MST(" + mstTime + ") = " + localTime);
    }
}

答案 10 :(得分:1)

这不是答案,但可以帮助某些人尝试使用相同的时区生成日期并应用另一个时区的偏移量。 当您的应用程序服务器在一个时区中运行而您的数据库在另一个时区中运行时非常有用。

public static Date toGreekTimezone (Date date) {
  ZoneId greek = ZoneId.of(EUROPE_ATHENS);
  ZonedDateTime greekDate = ZonedDateTime.ofInstant(date.toInstant(), greek);

  ZoneId def = ZoneId.systemDefault();
  ZonedDateTime defDate = greekDate.withZoneSameLocal(def);

  return Date.from(defDate.toInstant());
}

答案 11 :(得分:1)

这里有个故事: 我在美国的用户在网页中输入日期。我的服务器将此作为java.util.Date对象获取。 Date个对象没有时区的概念。

因此,假设用户输入了11PM(== 4AM伦敦时间)。对她来说,这是美国时间晚上11点。 您的服务器将其获取,并将其解释为JVM时区的11PM。 但是您需要的是一个Date对象,它表示4AM。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeStringInUS =  sdf.format("2020-05-04 23:00:00");

SimpleDateFormat dateFormatInUS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat dateFormatInUK = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

dateFormatInUS.setTimeZone(TimeZone.getTimeZone("America/New_York"));
dateFormatInUK.setTimeZone(TimeZone.getTimeZone("Europe/London"));

Date dateInUS = dateFormatInUS.parse(timeStringInUS);
Date dateInUK = sdf.parse(dateFormatInUK.format(dateInUS));

答案 12 :(得分:0)

public static String convertTimeBasedOnTimeZoneAndTimePattern(String dateTime,
  String fromTimeZone, String toTimeZone, String originalTimePattern, String timePattern) {

  DateTimeFormatter formatterNew = DateTimeFormatter.ofPattern(timePattern);

  DateTimeFormatter formatter = DateTimeFormatter.ofPattern(originalTimePattern);

  TemporalAccessor temporalAccessor = formatter.parse(dateTime);
  ZoneId z = ZoneId.of(fromTimeZone);
  LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);
  ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, z);
  Instant instant = Instant.from(zonedDateTime);

  ZonedDateTime fromZonedDateTime = instant.atZone(ZoneId.of(toTimeZone));

  String fromZoneDateTime = fromZonedDateTime.format(formatterNew);

return fromZoneDateTime;}

要使用任何时间模式将任何时间转换为特定时区(例如:UTC->本地时区,反之亦然),可以使用java.time库。

此方法将采用时间模式(原始格式和所需格式),时区(原始时区和所需时区)将给出String作为输出。您可以使用SimpleDateFormatter将String转换为日期,也可以使用ZoneDateTime / Instant类的parse方法。

要将String转换为日期:

public static final DATE_FORMAT="yyyy-MM-dd HH:mm:ss.SSSSS";
public static Date convertStringToDate(String date) {
    SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);

    Date parsedDate = null;

    try {
      parsedDate = formatter.parse(date);
    } catch (Exception e) {
      throw new DateTimeParseException("Please provide date time in proper format", null, 0, null);
    }
    return parsedDate;
  }

要将日期转换为字符串:

public String convertTextDateToDate(Date textDate) {
    // SimpleDateFormat sdf = new SimpleDateFormat("EE MMM dd HH:mm:ss z yyyy", //Locale.ENGLISH);

    SimpleDateFormat date = new SimpleDateFormat(DATE_FORMAT);
    String dateFormatted = date.format(textDate);
    return dateFormatted;
  }

答案 13 :(得分:-2)

public static void convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone) {
    long milliseconds = date.getTime();
    milliseconds += (fromTimeZone.getRawOffset() * -1);
    if (fromTimeZone.inDaylightTime(date)) {
        milliseconds += (fromTimeZone.getDSTSavings() * -1);
    }
    milliseconds += toTimeZone.getRawOffset();
    if (toTimeZone.inDaylightTime(date)) {
        milliseconds += toTimeZone.getDSTSavings();
    }
    date.setTime(milliseconds);
}