简体   繁体   中英

Java Calendar Timezone

I am trying to convert a timestamp (milliseconds) to another time zone (GMT-7:00 America/Los Angeles) but the time I get after conversion is not what I expect it to be. Can someone explain to me why this is happening and how can I do it correctly ? My Local timezone is "GMT+5:30"

long timeMillis = 1567697400000l; // Thu 5 September 2019 21:00:00

TimeZone laTimeZone = TimeZone.getTimeZone("GMT-07:00");

Calendar losAngelesTime = Calendar.getInstance(laTimeZone);
losAngelesTime.setTimeInMillis(timeMill);

// I expect the date to be Thu 5 September 2019 14:00:00, 
// but I am getting Thu 5 September 2019 08:30:00

System.out.println(losAngelesTime.get(Calendar.HOUR_OF_DAY) + ":" + losAngelesTime.get(Calendar.MINUTE)+"  "+ losAngelesTime.get(Calendar.DAY_OF_WEEK));

The time in ms that you have provided is Thu 5 September 2019 21:00:00 in GMT+5:30 which is actually Thu 5 September 2019 15:30:00 in UTC. Now you're simply converting this time to LA timezone. This gives you Thu 5 September 2019 08:30:00 in GMT-7:00.

Whenever time is represented in ms, it is actually the time as UTC milliseconds from the epoch. The documentation clearly states this.

An instant in time can be represented by a millisecond value that is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian).

As Aditi Gupta already said, 8:30 is correct. 21:00+05:30 equals 15:30 UTC, which in turn equals 08:30-07:00, which agrees with Pacific Daylight Time in Los Angeles. You can also check with an online epoch converter such as this one that 1 567 697 400 (seoncds) equals Thursday September 5, 2019 15:30:00 UTC. I believe that your expectation came from subtracting 7 hours from your local time where instead you should subtract 7 hours from the UTC time.

I recommend you don't use TimeZone and Calendar . Those classes are poorly designed and long outdated. Instead use Instant , ZonedDateTime and ZoneId , all from java.time, the modern Java date and time API. For the correct and modern way to do the conversion see for example this answer by Basil Bourque (your question may be regarded as a duplicate of that other question, it depends on how you look at it).

Don't use GMT+5:30 nor GMT-07:00 as time zones. The latter is incorrect for Los Angeles during the standard time of year. Use something like Asia/Colombo or Asia/Kolkata , which is more appropriate for your zone, and then America/Los_Angeles . They convey your intention better, and they work correctly all year for historic and present-day dates.

tl;dr

Instant                                 // Represent a moment in UTC with resolution of nanoseconds. 
.ofEpochMilli(                          // Parsing a count of milliseconds. 
    1_567_697_400_000L                  // Count of whole seconds since first moment of 1970 in UTC.
)                                       // Returns an `Instant` object.
.atZone(                                // Adjust from UTC to some time zone. Same moment, different wall-clock time.
    ZoneId.of( "America/Los_Angeles" )  // Use proper time zone names in `Continent/Region` format rather than mere offset-from-UTC (hours-minutes-seconds). 
)                                       // Returns a `ZonedDateTime` object. 
.toString()                             // Generate text in standard ISO 8601 format, wisely extended to append name of time zone in square brackets.

Details

The other two Answers by Aditi Gupta and by Ole VV are both correct. I'll add a bit of example code.

You are using terrible date-time classes year ago supplanted by java.time classes .

Instant

I am trying to convert a timestamp (milliseconds)

If your count of milliseconds is since the epoch reference of first moment of 1970 in UTC, parse as a Instant .

long input = 1_567_697_400_000L ;  // Count of milliseconds since 1970-01-01T00:00:00Z.
Instant instant = Instant.ofEpochMilli( input ) ;

instant.toString(): 2019-09-05T15:30:00Z

Time zone

to another time zone (GMT-7:00 America/Los Angeles)

Use a proper time zone name rather than a mere offset-from-UTC.

Apply a time zone ( ZoneId ) to your Instant to adjust into a time zone, yielding a ZonedDateTime object.

ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

zdt.toString(): 2019-09-05T08:30-07:00[America/Los_Angeles]

Always specify time zone

My Local timezone is "GMT+5:30"

Your own local time zone should be irrelevant to your date-time handling, as should the JVM's default time time.

In java.time , the time zone and offset arguments are optional. If omitted, the JVM's current default time zone is implicitly applied. This is one of the very few flaws in the design of java.time , in my opinion – those zone arguments should be required. I recommend you always specify your desired/expected time zone explicitly .

We can adjust to your own time zone if you care to see. Ask for the JVM's current default time zone explicitly to make the intentions of your code crystal-clear to the reader.

ZoneId zDefault = ZoneId.systemDefault() ;
ZonedDateTime zdtDefault = zdt.withZoneSameInstant( zDefault ) ;

zdtDefault.toString(): 2019-09-05T21:00+05:30[Asia/Kolkata]

IdeOne.com demo

See all this code run live at IdeOne.com .


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 .

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

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

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 , YearQuarter , and more .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM