tl;dr
Use the ZoneId & ZonedDateTime classes found in the java.time package.
ZonedDateTime.now() // Implicitly applies the JVM’s current default time zone.
Better to specify your desired/expected time zone explicitly.
ZonedDateTime.now(
ZoneId.of( "Africa/Tunis" )
)
java.time
The modern approach uses the java.time classes that years ago supplanted the terrible legacy classes such as Timestamp, Calendar, Date, TimeZone, and SimpleDateFormat.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
Capture the current moment as seen through the wall-clock time used by the people of a particular region, that time zone named above.
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

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?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
How to get the current date and time of your timezone in Java? - Stack Overflow
oracle database - Is java.sql.Timestamp timezone specific? - Stack Overflow
java - Clarification on using timestamp without time zone and LocalDateTime in UTC-centric systems - Software Engineering Stack Exchange
Is there a straightforward way to render Instant timestamp into user’s local time zone?
tl;dr
Use the ZoneId & ZonedDateTime classes found in the java.time package.
ZonedDateTime.now() // Implicitly applies the JVM’s current default time zone.
Better to specify your desired/expected time zone explicitly.
ZonedDateTime.now(
ZoneId.of( "Africa/Tunis" )
)
java.time
The modern approach uses the java.time classes that years ago supplanted the terrible legacy classes such as Timestamp, Calendar, Date, TimeZone, and SimpleDateFormat.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
Capture the current moment as seen through the wall-clock time used by the people of a particular region, that time zone named above.
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

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?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
You can get the timestamp with time zone with this method :
public static long getTimestampWithGMT() {
long timestamp = System.currentTimeMillis() / 1000;
int offset = (TimeZone.getDefault().getRawOffset() + TimeZone.getDefault().getDSTSavings()) / 1000;
return timestamp + offset;
}
Date is always UTC-based... or time-zone neutral, depending on how you want to view it. A Date only represents a point in time; it is independent of time zone, just a number of milliseconds since the Unix epoch. There's no notion of a "local instance of Date." Use Date in conjunction with Calendar and/or TimeZone.getDefault() to use a "local" time zone. Use TimeZone.getTimeZone("Europe/Madrid") to get the Madrid time zone.
... or use Joda Time, which tends to make the whole thing clearer, IMO. In Joda Time you'd use a DateTime value, which is an instant in time in a particular calendar system and time zone.
In Java 8 you'd use java.time.ZonedDateTime, which is the Java 8 equivalent of Joda Time's DateTime.
As Jon Skeet already said, java.util.Date does not have a time zone. A Date object represents a number of milliseconds since January 1, 1970, 12:00 AM, UTC. It does not contain time zone information.
When you format a Date object into a string, for example by using SimpleDateFormat, then you can set the time zone on the DateFormat object to let it know in which time zone you want to display the date and time:
Date date = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Use Madrid's time zone to format the date in
df.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));
System.out.println("Date and time in Madrid: " + df.format(date));
If you want the local time zone of the computer that your program is running on, use:
df.setTimeZone(TimeZone.getDefault());
Although it is not explicitly specified for setTimestamp(int parameterIndex, Timestamp x), drivers have to follow the rules established by the setTimestamp(int parameterIndex, Timestamp x, Calendar cal) javadoc (emphasis mine):
Sets the designated parameter to the given
java.sql.Timestampvalue, using the givenCalendarobject. The driver uses theCalendarobject to construct an SQLTIMESTAMPvalue, which the driver then sends to the database. With aCalendarobject, the driver can calculate the timestamp taking into account a custom time zone. If noCalendarobject is specified, the driver uses the default time zone, which is that of the virtual machine running the application.
When you call with setTimestamp(int parameterIndex, Timestamp x) the JDBC driver uses the time zone of the virtual machine to calculate the date and time of the timestamp in that time zone. This date and time is what is stored in the database, and if the database column does not store time zone information, then any information about the zone is lost (which means it is up to the application(s) using the database to use the same time zone consistently or come up with another scheme to discern timezone (e.g. store in a separate column).
For example: Your local time zone is GMT+2. You store "2012-12-25 10:00:00 UTC". The actual value stored in the database is "2012-12-25 12:00:00". You retrieve it again: you get it back again as "2012-12-25 10:00:00 UTC" (but only if you retrieve it using getTimestamp(..)), but when another application accesses the database in time zone GMT+0, it will retrieve the timestamp as "2012-12-25 12:00:00 UTC".
If you want to store it in a different timezone, then you need to use the setTimestamp(int parameterIndex, Timestamp x, Calendar cal) with a Calendar instance in the required timezone. Just make sure you also use the equivalent getter with the same time zone when retrieving values (if you use a TIMESTAMP without timezone information in your database).
So, assuming you want to store the actual GMT timezone, you need to use:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
stmt.setTimestamp(11, tsSchedStartTime, cal);
With JDBC 4.2 a compliant driver should support java.time.LocalDateTime (and java.time.LocalTime) for TIMESTAMP (and TIME) through get/set/updateObject. The java.time.Local* classes are without time zones, so no conversion needs to be applied (although that might open a new set of problems if your code did assume a specific time zone).
That is:
- replace
getDate(..)withgetObject(.., LocalDate.class) - replace
setDate(.., dateValue)withsetObject(.., localDateValue) - replace
getTime(..)withgetObject(.., LocalTime.class) - replace
setTime(.., timeValue)withsetObject(.., localTimeValue) - replace
getTimestamp(..)withgetObject(.., LocalDateTime.class) - replace
setTimestamp(.., timestampValue)withsetObject(.., localDateTimeValue)
I think the correct answer should be java.sql.Timestamp is NOT timezone specific. Timestamp is a composite of java.util.Date and a separate nanoseconds value. There is no timezone information in this class. Thus just as Date this class simply holds the number of milliseconds since January 1, 1970, 00:00:00 GMT + nanos.
In PreparedStatement.setTimestamp(int parameterIndex, Timestamp x, Calendar cal) Calendar is used by the driver to change the default timezone. But Timestamp still holds milliseconds in GMT.
API is unclear about how exactly JDBC driver is supposed to use Calendar. Providers seem to feel free about how to interpret it, e.g. last time I worked with MySQL 5.5 Calendar the driver simply ignored Calendar in both PreparedStatement.setTimestamp and ResultSet.getTimestamp.
So my application (android) uses Instant to log timestamped events. The events are printed to a csv file and being reviewed by a technologically-illiterate human being. The time is printed using Instant.toString() and it‘s in UTC. I want to render it to the user’s local time zone; the time zone can very.
So my thought process is to first get the user’s timezone using either ZoneOffset or ZoneID and then applying that offset to the Instant timestamp. But I am getting all sorts of confused with all the different possible classes to use from Java Time and their naming and all of that. Been going through a lot of SO posts and a lot of them use outdated/deprecated classes from before Java 8 Time and the ones that don’t, just confused me even more.
What’s the straightforward way of rendering the UTC Instant Timestamp to the user’s local time zone date and time? Is ZonedDateTime the class representation of what I’m looking for? How do I use ZoneOffset to convert the original timestamp to the local date and time?
Your code using java.time classes:
ZonedDateTime zdt = ZonedDateTime.now();
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
DateTimeFormatter dfGMT = df.withZone(ZoneId.of("GMT"));
String dateString = dfGMT.format(zdt);
System.out.println("DateString: "+dateString);
ZonedDateTime parsedDate = ZonedDateTime.parse(dateString,dfGMT);
System.out.println("ParsedDate: "+ parsedDate);
Timestamp timestamp = Timestamp.from(parsedDate.toInstant());
System.out.println("Zoned Timestamp: "+timestamp);
//ignoring zone info from date string
LocalDateTime ldt = LocalDateTime.from(dfGMT.parse(dateString));
timestamp = Timestamp.valueOf(ldt);
System.out.println("Zone stripped GMT timestamp: "+timestamp);
ZonedDateTime zdt1 = ldt.atZone(ZoneId.of("GMT"));
zdt1 = zdt1.withZoneSameInstant(ZoneId.of("America/Chicago"));
timestamp = Timestamp.valueOf(zdt1.toLocalDateTime());
System.out.println("Zone stripped CST timestamp: "+timestamp);
Output:
DateString: 2021-03-26T09:10:37.537+0000
ParsedDate: 2021-03-26T09:10:37.537Z[GMT]
Zoned Timestamp: 2021-03-26 14:40:37.537
Zone stripped GMT timestamp: 2021-03-26 09:10:37.537
Zone stripped CST timestamp: 2021-03-26 04:10:37.537
java.time and JDBC 4.2
You don’t need any formatting, parsing nor conversion. To insert the current timestamp into your SQL database:
OffsetDateTime currentTimestamp = OffsetDateTime.now(ZoneOffset.UTC);
String sql = "insert into your_table(your_timestamp_with_time_zone_column) values (?);";
try (PreparedStatement prepStmt = yourDatabaseConnection.prepareStatement(sql)) {
prepStmt.setObject(1, currentTimestamp);
prepStmt.executeUpdate();
}