Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
502 views
in Technique[技术] by (71.8m points)

timezone - converting date from one time zone to other time zone in java

I wanted to convert a date from one time zone to another, using SimpleDateFormat class in java. But somehow it is generating different results which are suppose to be in the same TimeZone.

Here is a test case, and its generating one result as IST and other one as GMT. i think it should be generating only GMT's for both cases.

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;
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

tl;dr

Use modern java.time classes, specifically ZonedDateTime and ZoneId. See 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[Africa/Tunis]

For UTC, call ZonedDateTime::toInstant.

Avoid 3-Letter Time Zone Codes

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.

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.

Avoid j.u.Date

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).

java.time

Instant

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.

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

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

ZonedDateTime

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.

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

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

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

ISO 8601

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.

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.

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

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

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

Adjust to UTC

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

Instant instant = zdtKolkata.toInstant() ;

DateTimeFormatter

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


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.

Joda-Time

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.

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.

//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();

Dump to console…

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 );

When run…

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

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, <a href="http://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/Ye


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...