将日期从一个时区转换为java中的另一个时区

时间:2014-01-25 05:58:45

标签: java timezone simpledateformat

我想在java中使用SimpleDateFormat类将日期从一个时区转换为另一个时区。但不知何故,它产生了不同的结果,假设它们位于同一个TimeZone中。

这是一个测试用例,它生成一个结果作为IST,另一个结果作为GMT。我认为它应该只为这两种情况产生GMT。

public class TestOneCoreJava {

    public static void main(String[] args) throws ParseException {// Asia/Calcutta
        DateFormat formatter = new SimpleDateFormat("dd-MMM-yy hh:mm:ss a");
        System.out.println(getDateStringToShow(formatter.parse("26-Nov-10 03:31:20 PM +0530"),"Asia/Calcutta", "Europe/Dublin", false));
        System.out.println(getDateStringToShow(formatter.parse("02-Oct-10 10:00:00 AM +0530"),"Asia/Calcutta", "Europe/Dublin", false));
        //------Output--
        //26-Nov-10 GMT
        //02-Oct-10 IST
    }

    public static String getDateStringToShow(Date date,
            String sourceTimeZoneId, String targetTimeZoneId, boolean includeTime) {
        String result = null;

        // System.out.println("CHANGING TIMEZONE:1 "+UnitedLexConstants.SIMPLE_FORMAT.format(date));
        String date1 = new SimpleDateFormat("dd-MMM-yy hh:mm:ss a").format(date);

        SimpleDateFormat sourceTimeZoneFormat = new SimpleDateFormat("Z");
        sourceTimeZoneFormat.setTimeZone(TimeZone.getTimeZone(sourceTimeZoneId));

        date1 += " " + sourceTimeZoneFormat.format(date);

        // Changed from 'Z' to 'z' to show IST etc, in place of +5:30 etc.
        SimpleDateFormat targetTimeZoneFormat = new SimpleDateFormat("dd-MMM-yy hh:mm:ss a z");
        targetTimeZoneFormat.setTimeZone(TimeZone.getTimeZone(targetTimeZoneId));

        SimpleDateFormat timeZoneDayFormat = null;
        if (includeTime) {
            timeZoneDayFormat = targetTimeZoneFormat;
        } else {
            timeZoneDayFormat = new SimpleDateFormat("dd-MMM-yy z");
        }
        timeZoneDayFormat.setTimeZone(TimeZone.getTimeZone(targetTimeZoneId));
        try {
            result = timeZoneDayFormat.format(targetTimeZoneFormat.parse(date1));
            // System.out.println("CHANGING TIMEZONE:3 "+result);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return result;
    }
}

2 个答案:

答案 0 :(得分:1)

TL;博士

使用现代 java.time 类,特别是ZonedDateTimeZoneId。请参阅Oracle Tutorial

ZonedDateTime                         // Represent a date and time-of-day in a specific time zone.
.now(                                 // Capture the current moment as seen in the wall-clock time used by the people of a particular region (a time zone). 
    ZoneId.of( "Pacific/Auckland" )   // Specify time zone using proper name in `Continent/Region` format. Never use 3-4 letter pseudo-zone such as IST or PST or EST.
)                                     // Returns a `ZonedDateTime` object.
.withZoneSameInstant(                 // Adjust from one time zone to another. Same point on the timeline, same moment, but different wall-clock time.
    ZoneId.of( "Africa/Tunis" )       
)                                     // Returns a new fresh `ZonedDateTime` object rather than altering/“mutating” the original, per immutable objects pattern.
.toString()                           // Generate text in standard ISO 8601 format, extended to append name of zone in square brackets.
  

2018-09-18T21:47:32.035960 + 01:00 [非洲/突尼斯]

对于UTC,请致电ZonedDateTime::toInstant

避免使用3个字母的时区代码

避免使用这三个字母的时区代码。它们既不标准也不独特。例如,您使用“IST”可能意味着印度标准时间,爱尔兰标准时间以及其他可能。

使用正确的time zone names。时区及其名称的定义经常更改,因此请保持您的源代码最新。例如,旧的“亚洲/加尔各答”现在是“亚洲/加尔各答”。而不只是名字;政府因改变时区的规则/行为而臭名昭着,偶尔会在最后一刻。

避免使用j.u.Date

避免使用捆绑的java.util.Date和Calendar类。众所周知,它们很麻烦,将被新的java.time.* package(受Joda-Time启发)在Java 8中取代。

java.time

Instant

学习以UTC而不是自己的狭隘时区思考和工作。记录,数据交换和数据存储通常应以UTC格式完成。

Instant instant = Instant.now() ;  // Capture the current moment in UTC.
  

instant.toString():2018-09-18T20:48:43.354953Z

ZonedDateTime

调整为时区。同一时刻,时间轴上的同一点,不同的挂钟时间。应用ZoneId(时区)来获取ZonedDateTime对象。

ZoneId zMontreal = ZoneId.of( "America/Montreal" ) ;  
ZonedDateTime zdtMontreal = instant.atZone( zMontreal ) ;  // Same moment, different wall-clock time.

我们可以使用InstantZonedDateTime再次进行调整。

ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdtKolkata = zdtMontreal.withZoneSameInstant​( zKolkata ) ;

ISO 8601

在任何这些类上调用toString会生成标准ISO 8601类中的文本。 ZonedDateTime类通过在方括号中附加时区名称来明智地扩展标准。

将日期时间值作为文本交换时,请始终使用ISO 8601格式。不要使用问题中所示的自定义格式或本地化格式。

java.time 类默认使用标准格式来解析和生成字符串。

Instant instant = Instant.parse( "2018-01-23T01:23:45.123456Z" ) ;

使用标准格式可以避免在问题中看到的所有混乱的字符串操作。

调整为UTC

您始终可以通过提取ZonedDateTimeInstant带回UTC。

Instant instant = zdtKolkata.toInstant() ;

DateTimeFormatter

以其他格式表示您的日期时间值search Stack Overflow for DateTimeFormatter。你会发现很多例子和讨论。


更新: Joda-Time 项目现在处于维护模式,并建议迁移到 java.time 类。我将此部分保留为历史。

约达时间

小心java.util.Date对象,它们看起来像是时区但实际上却没有。在Joda-Time中,DateTime确实知道其指定的时区。通常应指定所需的时区。否则,将分配JVM的默认时区。

Joda-Time主要使用不可变对象。不是修改实例,而是创建新的新实例。在调用诸如toDateTime之类的方法时,会返回一个新的DateTime实例,使原始对象保持原样并保持不变。

//DateTime now = new DateTime(); // Default time zone automatically assigned.

// Convert a java.util.Date to Joda-Time.
java.util.Date date = new java.util.Date();
DateTime now = new DateTime( date );  // Default time zone automatically assigned.

DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime nowIndia = now.toDateTime( timeZone );

// For UTC/GMT, use built-in constant.
DateTime nowUtcGmt = nowIndia.toDateTime( DateTimeZone.UTC );

// Convert from Joda-Time to java.util.Date.
java.util.Date date2 = nowIndia.toDate();

转储到控制台...

System.out.println( "date: " + date );
System.out.println( "now: " + now );
System.out.println( "nowIndia: " + nowIndia );
System.out.println( "nowUtcGmt: " + nowUtcGmt );
System.out.println( "date2: " + date2 );

跑步时......

date: Sat Jan 25 16:52:28 PST 2014
now: 2014-01-25T16:52:28.003-08:00
nowIndia: 2014-01-26T06:22:28.003+05:30
nowUtcGmt: 2014-01-26T00:52:28.003Z
date2: Sat Jan 25 16:52:28 PST 2014

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:0)

在Google API中处理时区问题时。我遇到过这样的问题。

看看你的这段代码: -

 System.out.println(getDateStringToShow(formatter.parse("26-Nov-10 03:31:20 PM 
 +0530"),"Asia/Calcutta", "Europe/Dublin", false));
 System.out.println(getDateStringToShow(formatter.parse("02-Nov-10 10:00:00 AM 
 +0530"),"Asia/Calcutta", "Europe/Dublin", false));

如果我将上面的内容作为输入,它将以我们想要的方式运行。


如果您仍然想要这样做,那么您必须根据需要进行计算。

喜欢在数学上调整时间和类似的东西。


或者您的案例的简单修复将是这样的

SimpleDateFormat d =new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
d.setTimeZone(TimeZone.getTimeZone("Europe/Dublin"));
Date firsttime = d.parse("2013-12-19T03:31:20");
Date seondtime = d.parse("2013-12-19T10:00:00");

System.out.println(getDateStringToShow(firsttime,"Asia/Calcutta",
"Europe/Dublin", false));
System.out.println(getDateStringToShow(seondtime,"Asia/Calcutta", 
"Europe/Dublin", false));

我的建议是提及JODA API。比旧学校日期更受欢迎。

相关问题