Reputation: 2616
I am trying to set the Timezone to the different country's timezone with help of SimpleDateFormat. SimpleDateFormat.format() returns correct current time of the given Timezone, but SimpleDateFormat.parse() returns local current time, I don't know why this is happening.
Here is the my code:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
System.out.println("Time1 : " + dateFormat.format(new Date()));
System.out.println("Time2 : " + dateFormat.parse(dateFormat.format(new Date())));
The output is:
Time1 : 2013-01-17 21:01:55
Time2 : Fri Jan 18 10:30:55 IST 2013
Time1 is the output of "America/Los_Angeles" and Time2 is the output of local (i.e. "Asia/Calcutta").
I just want the current time of given Timezone in UTC Seconds format (ie Seconds since Jan 1, 1970).
Why SimpleDateFormat.format() and SimpleDateFormat.parse() are giving different time though setting only one Timezone?
Upvotes: 3
Views: 15562
Reputation: 339342
The terrible old date-time classes are quite confusing, especially in their handling of implicit default time zones. But your mystery is moot, as these terrible old classes were supplanted years ago by modern java.time classes.
Instant.now() // Capture current moment in UTC. This class replaces `java.util.Date`.
.atZone( // Adjust from UTC to the wall-clock time used by the people of a particular region, a time zone.
ZoneId.of( "America/Montreal" )
) // Returns a `ZonedDateTime`
.format(
DateTimeFormatter.ISO_LOCAL_DATE_TIME
) // Returns a String like: `2013-01-17T21:01:55`.
.replace( "T" , " " ) // Replace the `T` in the middle (from the standard ISO 8601 format) with a SPACE.
2013-01-17 21:01:55
The issue is moot as the terrible old date-time classes such as SimpleDateFormat
have been supplanted by the java.time.
The java.util.Date
class is replaced by java.time.Instant
. Both represent a moment in UTC, always in UTC. (Despite Date::toString
lying to you, in applying the JVM’s current default time zone.)
Instant instant = Instant.now() ; // Capture current moment in UTC.
Adjust into a time zone.
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Adjust into another time zone.
ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ; // Contemporary time in India.
ZonedDateTime zdtKolkata = instant.atZone( zKolkata ) ;
All three objects (instant
, zdt
, & zdtKolkata
) represent the very same simultaneous moment, the same point on the timeline. Only the wall-clock time is different.
When generating strings representing date-time values, I recommend always including the offset/zone information unless the context is absolutely crystal-clear. I have seen much confusion in the business world caused by reports where the time frame was ambiguous.
But if you insist, either define your own formatting pattern with DateTimeFormatter
class, or use the given formatter ISO_LOCAL_DATE_TIME
and replace the T
in the middle with a SPACE.
DateTimeFormatter f = DateTimeFormatter.ISO_LOCAL_DATE_TIME ;
String output = zdt.format( f ) ;
2013-01-17 21:01:55
Part of the problem is the ambiguity of your string 2013-01-17 21:01:55
. That string lacks any indicator of time zone or offset-from-UTC. Such a value is not a moment, is not a point on the timeline. For example, 9 PM in India comes several hours sooner than 9 PM in Québec. Without a zone or offset, that string represents only potential moments along a range of about 26-27 hours, the range of time zones around the globe.
The legacy classes had no such class to represent this kind of value. In the modern classes, we have LocalDateTime
for this purpose, a non-moment, date and time-of-day without zone/offset.
The java.time classes use ISO 8601 standard formats by default when parsing/generating strings. Your input nearly complies. We need only replace the SPACE in the middle with a T
.
LocalDateTime ldt = LocalDateTime.parse( "2013-01-17 21:01:55".replace( "" , "T" ) ) ;
If you know for a fact that the intent behind that string was to represent a moment in a particular time zone, apply a ZoneId
to get a ZonedDateTime
. For example, if you are certain it represents a moment on most of the west coast of North America, use America/Los_Angeles
.
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
To adjust from that zone to UTC, extract a Instant
object. The Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = zdt.toInstant() ; // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock 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
, YearQuarter
, and more.
Upvotes: 1
Reputation: 41
dateFormat.format() will give you the output in given format and it will change the timezone to the one set in formatter. (eg dateFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));)
Whereas dateFormat.parse() assumes date is already in mentioned timezone and it will convert the date to your local timezone.
Upvotes: 3
Reputation: 3274
With the first line, you are formatting your local date to specific timezone.It will return a string which represents the argument date passed in specific time zone.But parse function is different.It will return a date object represents a number of milliseconds since January 1, 1970, 12:00 AM, UTC. It does not contain any time zone information.
Upvotes: 0
Reputation: 136062
dateFormat.parse() in the second println
System.out.println("Time2 : " + dateFormat.parse(dateFormat.format(new Date())));
returns Date and Date.toString() returns string representation of the date in EEE MMM dd HH:mm:ss zzz yyyy
format. See Date.toString() API
Upvotes: 0
Reputation: 3880
with Parse, you command the compiler to understand the given date in specific format. It understands and keep it in its own format and ready to give whatever format you want!
You are getting a output, which is a signal that you input date is parsed successfully. You dont have a control over the format of the date , that the variable is storing.
using format, you can convert the date to any desired format.
Simply Parse -> Reading ( I may read it in whatever manner and store in whatever manner I want) Format -> Write ( I will give you in the format you wanted )
Upvotes: 7