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

Aru*_*unK 1 java timezone simpledateformat

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

这是一个测试用例,它生成一个结果为 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Bas*_*que 5

tl;dr

\n\n

Use modern java.time classes, specifically ZonedDateTime and ZoneId. See Oracle Tutorial.

\n\n
ZonedDateTime                         // Represent a date and time-of-day in a specific time zone.\n.now(                                 // Capture the current moment as seen in the wall-clock time used by the people of a particular region (a time zone). \n    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.\n)                                     // Returns a `ZonedDateTime` object.\n.withZoneSameInstant(                 // Adjust from one time zone to another. Same point on the timeline, same moment, but different wall-clock time.\n    ZoneId.of( "Africa/Tunis" )       \n)                                     // Returns a new fresh `ZonedDateTime` object rather than altering/\xe2\x80\x9cmutating\xe2\x80\x9d the original, per immutable objects pattern.\n.toString()                           // Generate text in standard ISO 8601 format, extended to append name of zone in square brackets.\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

2018-09-18T21:47:32.035960+01:00[Africa/Tunis]

\n
\n\n

For UTC, call ZonedDateTime::toInstant.

\n\n

Avoid 3-Letter Time Zone Codes

\n\n

Avoid those three-letter time zone codes. They are neither standardized nor unique. For example, your use of "IST" may mean India Standard Time, Irish Standard Time, and maybe others.

\n\n

Use proper time zone names. The definition of time zones and their names change frequently, so keep your source up-to-date. For example the old "Asia/Calcutta" is now "Asia/Kolkata". And not just names; governments are notorious for changing the rules/behavior of a time zone, occasionally at the last minute.

\n\n

Avoid j.u.Date

\n\n

Avoid using the bundled java.util.Date and Calendar classes. They are notoriously troublesome and will be supplanted in Java 8 by the new java.time.* package (which was inspired by Joda-Time).

\n\n

java.time

\n\n

Instant

\n\n

Learn to think and work in UTC rather than your own parochial time zone. Logging, data-exchange, and data-storage should usually be done in UTC.

\n\n
Instant instant = Instant.now() ;  // Capture the current moment in UTC.\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

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

\n
\n\n

ZonedDateTime

\n\n

Adjust into a time zone. Same moment, same point on the timeline, different wall-clock time. Apply a ZoneId (time zone) to get a ZonedDateTime object.

\n\n
ZoneId zMontreal = ZoneId.of( "America/Montreal" ) ;  \nZonedDateTime zdtMontreal = instant.atZone( zMontreal ) ;  // Same moment, different wall-clock time.\n
Run Code Online (Sandbox Code Playgroud)\n\n

We can adjust again, using either the Instant or the ZonedDateTime.

\n\n
ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;\nZonedDateTime zdtKolkata = zdtMontreal.withZoneSameInstant\xe2\x80\x8b( zKolkata ) ;\n
Run Code Online (Sandbox Code Playgroud)\n\n

ISO 8601

\n\n

Calling toString on any of these classes produce text in standard ISO 8601 class. The ZonedDateTime class extends the standard wisely by appending the name of the time zone in square brackets.

\n\n

When exchanging date-time values as text, always use ISO 8601 formats. Do not use custom formats or localized formats as seen in your Question.

\n\n

The java.time classes use the standard formats by default for both parsing and generating strings.

\n\n
Instant instant = Instant.parse( "2018-01-23T01:23:45.123456Z" ) ;\n
Run Code Online (Sandbox Code Playgroud)\n\n

Using standard formats avoids all that messy string manipulation seen in the Question.

\n\n

Adjust to UTC

\n\n

You can always take a ZonedDateTime back to UTC by extracting a Instant.

\n\n
Instant instant = zdtKolkata.toInstant() ;\n
Run Code Online (Sandbox Code Playgroud)\n\n

DateTimeFormatter

\n\n

To represent your date-time value in other formats, search Stack Overflow for DateTimeFormatter class. You will find many examples and discussions.

\n\n
\n\n

UPDATE: The Joda-Time project is now in maintenance-mode, and advises migration to the java.time classes. I am leaving this section intact as history.

\n\n

Joda-Time

\n\n

Beware of java.util.Date objects that seem like they have a time zone but in fact do not. In Joda-Time, a DateTime does indeed know its assigned time zone. Generally should specify a desired time zone. Otherwise, the JVM\'s default time zone will be assigned.

\n\n

Joda-Time uses mainly immutable objects. Rather than modify an instance, a new fresh instance is created. When calling methods such as toDateTime, a new fresh DateTime instance is returned leaving the original object intact and unchanged.

\n\n
ZonedDateTime                         // Represent a date and time-of-day in a specific time zone.\n.now(                                 // Capture the current moment as seen in the wall-clock time used by the people of a particular region (a time zone). \n    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.\n)                                     // Returns a `ZonedDateTime` object.\n.withZoneSameInstant(                 // Adjust from one time zone to another. Same point on the timeline, same moment, but different wall-clock time.\n    ZoneId.of( "Africa/Tunis" )       \n)                                     // Returns a new fresh `ZonedDateTime` object rather than altering/\xe2\x80\x9cmutating\xe2\x80\x9d the original, per immutable objects pattern.\n.toString()                           // Generate text in standard ISO 8601 format, extended to append name of zone in square brackets.\n
Run Code Online (Sandbox Code Playgroud)\n\n

Dump to console\xe2\x80\xa6

\n\n
Instant instant = Instant.now() ;  // Capture the current moment in UTC.\n
Run Code Online (Sandbox Code Playgroud)\n\n

When run\xe2\x80\xa6

\n\n
ZoneId zMontreal = ZoneId.of( "America/Montreal" ) ;  \nZonedDateTime zdtMontreal = instant.atZone( zMontreal ) ;  // Same moment, different wall-clock time.\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

About java.time

\n\n

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

\n\n

Joda -Time项目目前处于维护模式,建议迁移到java.time classes.

\n\n

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310.

\n\n

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC 驱动程序。不需要字符串,不需要java.sql.* classes.

\n\n

从哪里获取 java.time 类?

\n\n\n\n

ThreeTen -Extra项目通过附加类扩展了 java.time。该项目是 java.time 未来可能添加的内容的试验场。您可能会在这里找到一些有用的类,例如Interval、、YearWeekYearQuarter.

\n