Reputation: 433
Lets say I have a timestamp value.
Edit
Calendar curCal = new GregorianCalendar(TimeZone.getDefault());
curCal.setTimeInMillis(System.currentTimeMillis());
TimeZone fromTz = TimeZone.getDefault();
curCal.setTimeZone(fromTz);
TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
Calendar toCal = new GregorianCalendar(gmtTZ);
toCal.setTimeInMillis(curCal.getTimeInMillis());
Date dd = toCal.getTime();
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a",Locale.US);
format.setTimeZone(gmtTZ);
String ff = format.format(dd);
java.sql.Timestamp curTimeInGMT = new java.sql.Timestamp(dateInLong(ff, "dd/MM/yyyy hh:mm:ss a"));
Now I am getting the milliseconds value of the above time using getTime()
;
Long l = t.getTime();
Definition of the getTime() method as per Java docs is
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Timestamp object.
So, from what I have understood by testing so many times, getTime()
will give the milliseconds difference between the given time and January 1, 1970, 00:00:00 GMT.
For getTime()
to get the difference from January 1, 1970, 00:00:00 GMT, it need another GMT time.
So it needs to convert the given time to GMT time.For that conversion it needs the timezone of the given time.
It will consider timezone of the given time as SYSTEM TIME ZONE and it will get the corresponding GMT time and then it will find the difference between the two GMT time and it will return the difference.
Is my understanding correct?
Upvotes: 3
Views: 11717
Reputation: 338516
Two points will make this work much easier:
First we must either specify a formatter by which to parse your input string, or alter it to meet the ISO 8601 standard used by default in java.time. The ISO 8601 format is close to SQL format, replacing the space in the middle with a T
.
String input = "2016-01-08 08:03:52.0";
String inputIso8601 = input.replace ( " ", "T" );
Parse that string as a local date-time, which means any locality. The input string lacks any time zone or offset-from-UTC info, so we start with a local and will apply an assumed time zone afterwards.
LocalDateTime localDateTime = LocalDateTime.parse ( inputIso8601 );
Let's apply the assumed time zone. I am arbitrarily choosing Montréal but obviously you need to know and use whatever time zone was intended for that string input. If you are sure that string meant UTC, use the ZoneOffset.UTC
.
ZoneId zoneId = ZoneId.of ( "America/Montreal" ); // Or perhaps ZoneOffset.UTC constant.
ZonedDateTime zdt = ZonedDateTime.of ( localDateTime, zoneId );
Now we are ready to convert to a java.sql.Timestamp
object, to be sent to the database. That old class has a new method, for converting to/from java.time objects. The conversion requires an Instant
object which is a moment on the timeline in UTC. We can extract an Instant
from our ZonedDateTime
.
Instant instant = zdt.toInstant ( );
java.sql.Timestamp ts = java.sql.Timestamp.from ( instant );
Dump to console.
System.out.println ( "input: " + input + " in ISO 8601: " + inputIso8601 + " is localDateTime: " + localDateTime + " in zoneId: " + zoneId + " is zdt: " + zdt + " gives instant: " + instant + " which converts to java.sql.Timestamp ts: " + ts );
input: 2016-01-08 08:03:52.0 in ISO 8601: 2016-01-08T08:03:52.0 is localDateTime: 2016-01-08T08:03:52 in zoneId: America/Montreal is zdt: 2016-01-08T08:03:52-05:00[America/Montreal] gives instant: 2016-01-08T13:03:52Z which converts to java.sql.Timestamp ts: 2016-01-08 05:03:52.0
Read that console output carefully. Note the time-of-day on ts
. This shows the unfortunate behavior of the java.sql.Timestamp
method toString
to silently apply the JVM’s current default time zone when generating the textual representation of the date-time value. My JVM here had a default time zone of America/Los_Angeles
. So the time-of-day was adjusted (confusingly).
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.
With a JDBC driver complying with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings or 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: 2170
I cannot really assess your understanding, but here's mine:
The Timestamp class inherits from Date. Date is - in line with what you quoted from the Javadoc - just a wrapper for a long value. What happens is that the String is converted (somehow - please update the codefragment if you want to share your mechanism) to a time value. This implicitly or explicitly uses a time zone, but the resulting long value is independent of a time zone, it is the same as when you would have called System.currentTimeMillis()
in the time zone used in the conversion at the given time. If you want to control the time zone used for conversion, you can use a SimpleDateFormat
and set the time zone as follows:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
simpleDateFormat.parse("2016-01-08 08:03:52.0");
} catch (ParseException e) {
// handle the error here
}
Following your edit (which is missing the definition of the function dateInLong), I have created the following test class in which I have added some console output:
public class test {
@Test
public void test() throws ParseException {
Calendar curCal = new GregorianCalendar(TimeZone.getDefault());
curCal.setTimeInMillis(System.currentTimeMillis());
System.out.println("curCal 1: " + curCal.getTimeInMillis());
TimeZone fromTz = TimeZone.getDefault();
curCal.setTimeZone(fromTz);
System.out.println("curCal 2: " + curCal.getTimeInMillis());
TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
Calendar toCal = new GregorianCalendar(gmtTZ);
toCal.setTimeInMillis(curCal.getTimeInMillis());
Date dd = toCal.getTime();
System.out.println("dd: " + dd.getTime());
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a", Locale.US);
format.setTimeZone(gmtTZ);
String ff = format.format(dd);
long time = dateInLong(ff, "dd/MM/yyyy hh:mm:ss a");
System.out.println("time: " + time);
java.sql.Timestamp curTimeInGMT = new java.sql.Timestamp(time);
System.out.println("curTimeGMT: " + curTimeInGMT.getTime());
}
private long dateInLong(String dateString, String formatStr) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat(formatStr);
return format.parse(dateString).getTime();
}
}
It produces the following output:
curCal 1: 1452603245943
curCal 2: 1452603245943
dd: 1452603245943
time: 1452599645000
curTimeGMT: 1452599645000
As you can see, the only occasion the inner long value changes is when the date is converted to and from a String (i.e. after invoking dateInLong) namely due to the use of two different time zones (to String: GMT, from String: default - CET here). As long as you pass the inner long value around, the moment in time stays the same - regardless of whether it is wrapped by a Calendar
or a descendant of Date
).
Upvotes: 2