In ServletContextListener initialization method we are setting Time Zone as
public void contextInitialized(ServletContextEvent event) {
TimeZone.setDefault(TimeZone.getTimeZone("GMT+00:00"));
}
But when i check the Time Zone information in servlets and filters the Time Zone got changed.
Any one know what might be the reason.
Thanks
See, I've following class
public class TimeZ {
public static void main(String args[]){
System.out.println("1."+TimeZone.getTimeZone("GMT+00:00"));
System.out.println("2. "+TimeZone.getDefault());
TimeZone.setDefault(TimeZone.getTimeZone("GMT+00:00"));
System.out.println("3. "+TimeZone.getDefault());
System.out.println("4. "+TimeZone.getTimeZone("GMT+00:00"));
}
}
my output is:
1.sun.util.calendar.ZoneInfo[id="GMT+00:00",offset=0,dstSaving...
2. sun.util.calendar.ZoneInfo[id="Asia/Calcutta",offset=19800000,...
3. sun.util.calendar.ZoneInfo[id="GMT+00:00",offset=0,dstSaving...
4. sun.util.calendar.ZoneInfo[id="GMT+00:00",offset=0,dstSaving...
explanation: by default my timezone is india. It's going to return the
timezone of the JVM TimeZone.getDefault() is executed on. So if the
application is running on a server in India, it will be something like
"Asia/Calcutta" .when you set default timezone to GMT, it changes its timezone to
GMT zone. thats simple...
I cannot address your Question specifically as you do not show us the code for how you get time zone. But I can give you some tips.
Your code should be working. The problem is likely to be in (a) how you are getting the time zone or (b) the default zone being set somewhere else.
Add a line of code before and after where you set the zone to get the zone so as to log the change taking effect. See this done in the Answer by Sheeran.
Use the modern java.time classes rather than the troublesome old legacy date-time classes.
The default time zone applies to the entire JVM. Any code in any thread of any app within the JVM can change the default at any moment at runtime. Such a change affects all code in all threads of all apps within the JVM. So relying on the JVM’s current default time zone is risky and ill-advised in general but especially so on a server and even more so on a Servlet container.
Furthermore, the best practice on servers is to keep the default time zone in UTC. Though, again, you should not rely on that default.
There is almost never a need to set the default. Instead, pass explicitly the desired/expected time zone as a ZoneId (or ZoneOffset) as the optional argument to the various methods in java.time. Frankly I wish all those zone arguments were required rather than optional as most programmers fail to think about the crucial issue of zones and offsets.
Instant instant = Instant.now() ; // Current moment in UTC.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Much of your work should be done in UTC rather than with zoned values. Programmers should generally be thinking, working, logging, exchanging data, and serializing data all in UTC. As a programmer, you should stop thinking parochially about your own personal time zone while on the job, as constant conversions in/out of that zone will muddy your thoughts, lead to errors, and drive you crazy. Generally you should assign zones only where expected by your user in presentation in the user-interface.
Related
I have a simple spring boot REST API application, using plain jdbc to fetch data from a MSSQL DB. I am trying to figure out how best to retrieve a DATETIME2 column from the DB (which stores no timezone info), and serialize it as a UTC timestamp (and treat it as such in general in code).
My DB server timezone is set to UTC. I know that everything stored to this column is stored as UTC and I cannot change the column type unfortunately. It's a bit of a legacy DB, so all the dates will need to fetch will have this same problem, hence looking for a clean neat and tidy solution.
Ideally in my Java app, I would ideally like all my "date" fields to be of type java.time.Instant, since it is easy to handle and will serialize to json looking something like "someDate": "2022-05-30T15:04:06.559896Z".
The options as I see them are:
Use a custom RowMapper to do something like myModel.setDate(rs.getTimestamp("Date").toLocalDateTime().toInstant(ZoneOffset.UTC));, but this just seems verbose. I suppose I could tuck it away in some utility class static function?
Use LocalDateTime everywhere and do myModel.setDate(rs.getTimestamp("Date").toLocalDateTime()). But then Jackson will serialize it without timezone information.
Set the whole app timezone to UTC on startup. But this could be changed by other code, and from what I read is generally a bad idea.
Caveat: I am not a user of Spring.
moment versus not-a-moment
You need to get clear on one fundamental issue with date-time handling: moment versus not-a-moment.
By “moment” I mean a specific point on the timeline. Without even thinking about time zones and such, we all know that time flows forward, one moment at a time. Each moment is simultaneous for everyone around the world (sticking with Newtonian time, ignoring Einstein Relativity here 😉). To track a moment in Java, use Instant, OffsetDateTime, or ZonedDateTime. These are three different ways to represent a specific point on the timeline.
By “not-a-moment” I mean a date with a time-of-day, but lacking the context of a time zone or offset-from-UTC. If I were to say to you, “Call me at noon tomorrow” without the context of a time zone, you would have no way of knowing if you should call at noon time in Tokyo Japan, noon time in Toulouse France, or noon time in Toledo Ohio US — three very different moments, several hours apart. For not-a-moment, use LocalDateTime.
So never mix LocalDateTime with the other three classes, Instant, OffsetDateTime, or ZonedDateTime. You would be mixing your apples with your oranges.
You said:
I would ideally like all my "date" fields to be of type java.time.Instant
Yes, I would agree on generally using Instant as the member field on any Java object tracking a moment. This is generally a good idea — but only for moments. For not-a-moment, as discussed above, you should use LocalDateTime instead.
TIMESTAMP WITH TIME ZONE
Another issue, Instant was not mapped in JDBC 4.2 and later. Some JDBC drivers may optionally handle an Instant object, but doing so is not required.
So convert your Instant to a OffsetDateTime. The OffsetDateTime class is mapped in JDBC to a database column of a type akin to the SQL-standard type TIMESTAMP WITH TIME ZONE.
OffsetDateTime odt = instant.atOffset( Offset.UTC ) ;
Writing to database.
myPreparedStatement.setObject( … , odt ) ; // Pass your `OffsetDateTime` object.
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
TIMESTAMP WITHOUT TIME ZONE
For database columns of a type akin to the SQL-standard type TIMESTAMP WITHOUT TIME ZONE, use LocalDateTime class.
Writing to database.
myPreparedStatement.setObject( … , ldt ) ; // Pass your `LocalDateTime` object.
Retrieval.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
Specify time zone
You said:
My DB server timezone is set to UTC.
That should be irrelevant. Always write your Java code in such as way as to not rely on the JVM’s current default time zone, the host OS’ current default time zone, or the database’s current default time zone. All of those lay outside your control as a programmer.
Specify your desired/expected time zone explicitly.
Retrieve a moment from the database, and adjust into a desired time zone.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Generate text localized to the user's preferred locale.
Locale locale = Locale.JAPAN ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ).withLocale( locale ) ;
String output = zdt.format( f ) ;
DATETIME2 in MS SQL Server
The type DATETIME2 type in MS SQL Server stores a date with time-of-day, but lacks the context of a time zone or offset-from-UTC.
That is exactly the wrong type to use for storing a moment. As discussed above, that type is akin to the SQL standard type TIMESTAMP WITHOUT TIME ZONE, and maps to the Java class LocalDateTime.
You seem to understand that fact given your comment:
I know that everything stored to this column is stored as UTC and I cannot change the column type unfortunately. It's a bit of a legacy DB …
Let me point out that you do not know the values in that column are intended to represent a moment as seen with an offset of zero. You can expect that, and hope so. But without using the protection of the database’s type system, you cannot be certain. Every user, every DBA, and every SysAdmin must have always been aware of this unfortunate scenario, and must have always done the right thing. You’ll need lots of luck with that.
I must mention that the ideal solution is to refactor your database, to correct this wrong choice of data type for that column. But I understand this could be a burdensome and challenging fix.
So given this unfortunate scenario without a fix being feasible, what to do?
Options 1, 2, & 3 you listed
Option 1
Regarding your option # 1, yes that makes sense to me. Except two things:
I would change the name of your model method to be more precise: setInstant. Or use a descriptive business name such as setInstantWhenContractGoesIntoEffect.
Never use the awful legacy date-time classes in Java such as Timestamp. Change this:
myModel.setDate(rs.getTimestamp("Date").toLocalDateTime().toInstant(ZoneOffset.UTC));
… to:
myModel
.setInstantWhenContractGoesIntoEffect
(
resultSet
.getObject( "Date" , LocalDateTime.class ) // Returns a `LocalDateTime` object.
.toInstant( ZoneOffset.UTC ) // Returns an `Instant` object.
)
;
Option 2
As for your option # 2, I am not quite sure what you have in mind. But my impression is that would be the wrong way to go. I believe the best approach, for long-term maintenance without "technical debt", and for avoiding confusing and mishaps, is to “tell the truth”. Do not pretend to have a zebra when you actually have donkey. So:
On the database side, be clear and explicit that you have a date with time but lack the context of an offset. Add lots of documentation to explain that this is based on a faulty design, and that we are intend to store moments as seen in UTC.
On the app side, the Java side, deal only with Instant, OffsetDateTime, and ZonedDateTime objects, because within the data model we are representing moments. So use classes that represent a moment. So no use of LocalDateTime where you really mean a specific point on the timeline.
Obviously, there is some kind of a dividing line between your database side and your app side. Crossing that line is where you must convert between your Java type for a moment and your database type faking it as a moment. Where you draw that line, that transition zone, is up to you.
Option 3
As for your option # 3, yes that would be a very bad idea.
Setting such a default is not reliable. Any SysAdmin, or even an unfortunate OS update, could change the OS’s current default time zone. Like wise for the database’s current default time zone. And likewise for the JVM’s current default time zone.
So you end up three default time zones that could be changing, with each affecting various parts of your environment. And changing the current default time zone in any of those places immediately affects all other software depending on that default, not just your particular app.
As mentioned above, I recommend just the opposite: Code without any reliance on default time zones anywhere.
The one place for accessing a default time zone is maybe for presentation to the user. But even then, if the context in crucial, you must confirm the desired/expected time zone with the user. And where you do make use of a current default time zone, do so explicitly rather than implicitly. That is, make explicit calls such as ZoneId.getSystemDefault() rather than using omitted optional arguments.
I'm not sure I see a problem.
Instant values are UTC by definition, and java.sql.Timestamps have no zone other than the one implied by the database setting. You know the database is strictly UTC. This is lucky for you since it eliminates one error-prone conversion. Then, reading java.sql.Timestamps and keeping them as Instants at runtime is trivial, given java.sql.Timestamp#toInstant(). DON'T convert through LocalDateTime.
This has nothing to do with setting any "default" timezone in your application. Design and write your code so that internally (i.e. runtime memory and database) you deal ONLY with UTC (i.e. instants). The only point at which you should convert instants to anything local is at external interface points... i.e.
when outputting date/time values, either for human consumption or for other software that expects a specific timezone.
when reading date/time values from the user or another program (for which you will need to know any implied zone if it's not explicit)
Leave your "default" timezone as whatever is given to you by your environment. Then, no matter where your code is running, it will produce meaningful local dates/times.
Establish a strict rule that you deal only with UTC internally. This will make reasoning about your code MUCH simpler in the long run.
I guess the only real stumbling block is realizing that things depending on local conditions, such as day boundaries, have to be done in the local zone... but write your code to "think" UTC internally.
Sometimes, we find it is difficult to make judgement, whether to use ZonedDateTime or LocalDateTime, when we want to solve certain date/ time problem.
For instance, given an epoch, we would like to know the day of the week.
We find we can accomplish this task, with either ZonedDateTime or LocalDateTime. Here's the code example
import java.time.*;
public class Main {
public static void main(String[] args) {
long currentTimeMillis = System.currentTimeMillis();
// Yield correct result.
System.out.println("useLocalDateTime -> " + useLocalDateTime(currentTimeMillis));
// Also yield correct result.
System.out.println("useZonedDateTime -> " + useZonedDateTime(currentTimeMillis));
}
public static DayOfWeek useLocalDateTime(long currentTimeMillis) {
LocalDateTime localDateTime = LocalDateTime.ofInstant(
Instant.ofEpochMilli(currentTimeMillis),
ZoneId.systemDefault()
);
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
return dayOfWeek;
}
public static DayOfWeek useZonedDateTime(long currentTimeMillis) {
ZonedDateTime zonedDateTime = Instant.ofEpochMilli(currentTimeMillis).atZone(ZoneId.systemDefault());
DayOfWeek dayOfWeek = zonedDateTime.getDayOfWeek();
return dayOfWeek;
}
}
In the above case, is it better to use ZonedDateTime or LocalDateTime? Is there any guideline, so that we can pick up the correct class as tool?
I always have the impression that ZonedDateTime is more "feature rich" than LocalDateTime. Whatever can be accomplished by LocalDateTime, it can be accomplished by ZonedDateTime too, but not vice-versa. Hence, if I get stuck on which to choose, I will go to ZonedDateTime as default. Is that a correct concept?
Do you need to store time data that is attached to a specific time zone, or do you need to process time data that has an associated offset?
If you do, use ZonedDateTime.
If you don't, use LocalDateTime.
Some examples of when I would want to use ZonedDateTime:
I'm parsing an ISO 8601 timestamp with zone information.
I'm looking at data from two different sources located in two physically different locations.
I'm trying to calculate what the day of the week is given a timestamp.
Some examples of when I would want to use LocalDateTime:
I'm assured that my system only needs to care about one time zone - mine.
The data that I'm parsing does not have time stamp information.
I want to know how many seconds have passed between two time stamps. This may get converted to a ZonedDateTime first before it eventualy decants into a Duration if the time stamps are in ISO 8601 format.
Definitely be careful about days of the week across time zones, since the International Date Line can offset the day of the week depending on where you are physically located.
Instead of using System.currentTimeMillis() use ZonedDateTime.now(ZoneId) or Instant.now(). You should almost never need currentTimeMillis() in modern Java. Use the dedicated java.time APIs throughout your application, so that you're working with well-typed data structures instead of primitives like long currentTimeMillis.
given an epoch, we would like to know the day of the week
It's worth recognizing that this isn't a meaningful question without a time zone; at any moment in time there are two (or more?) days of the week in different places on earth. So before we go further we need to ask which time zone(s) do you care about?
Generally speaking, the systemDefault() time zone is not what you want. Instead the caller should provide the time zone they expect. If your program is running locally and only ever needs your machine's clock it may be fine, but the very reason for the split between LocalDateTime and ZonedDateTime is because the system is very often not the correct time zone to be using.
For trivial cases, e.g. a Java process running on your local machine that doesn't care about time zone changes over time, you might correctly use the system time zone. But in such cases it's a good idea to query the system near your main() method and then pass that zone through your application. This makes the application more scalable and testable, if the system zone stops being the right approach down the road.
Why does Clock.systemDefaultZone().instant() return a different time than LocalTime.now()?
I understand that LocalTime has no timezone, but it shows just what my system clock (in tray on my computer) shows, right? Both "use" default time zone (Europe/Moscow), so time shall be the same?
My computer clock is Europe/Moscow, so both shall show exactly my computer time?
System.out.println(Clock.systemDefaultZone().instant()); // 2018-03-19T10:10:27.156Z
System.out.println(Clock.systemDefaultZone().getZone()); // Europe/Moscow
System.out.println(LocalTime.now()); // 13:10:27.166
If I found out correctly, the Instant returned by .instant() does not take care of any timezone information. With the correct timezone (ZoneId returned by Clock.systemDefaultZone().getZone()) you can get a ZonedDateTime from the Instant though (which does provide timezone information).
Example
System.out.println(Clock.systemDefaultZone().instant());
System.out.println(Clock.systemDefaultZone().instant().atZone(Clock.systemDefaultZone().getZone()));
Output
2018-03-19T10:30:47.032Z
2018-03-19T13:30:47.048+03:00[Europe/Moscow]
java.time
public abstract class Clock extends Object
A clock providing access to the current instant, date and time using a time-zone.
Instances of this class are used to find the current instant, which can be interpreted using the stored time-zone to find the current date and time. As such, a clock can be used instead of System.currentTimeMillis() and TimeZone.getDefault().
Use of a Clock is optional. All key date-time classes also have a now() factory method that uses the system clock in the default time zone. The primary purpose of this abstraction is to allow alternate clocks to be plugged in as and when required. Applications use an object to obtain the current time rather than a static method. This can simplify testing.
Best practice for applications is to pass a Clock into any method that requires the current instant. A dependency injection framework is one way to achieve this:
public class MyBean {
private Clock clock; // dependency inject
...
public void process(LocalDate eventDate) {
if (eventDate.isBefore(LocalDate.now(clock)) {
...
}
}
}
This approach allows an alternate clock, such as fixed or offset to be used during testing.
The system factory methods provide clocks based on the best available system clock This may use System.currentTimeMillis(), or a higher resolution clock if one is available.
Implementation Requirements:
This abstract class must be implemented with care to ensure other classes operate correctly. All implementations that can be instantiated must be final, immutable and thread-safe.
The principal methods are defined to allow the throwing of an exception. In normal use, no exceptions will be thrown, however one possible implementation would be to obtain the time from a central time server across the network. Obviously, in this case the lookup could fail, and so the method is permitted to throw an exception.
The returned instants from Clock work on a time-scale that ignores leap seconds, as described in Instant. If the implementation wraps a source that provides leap second information, then a mechanism should be used to "smooth" the leap second. The Java Time-Scale mandates the use of UTC-SLS, however clock implementations may choose how accurate they are with the time-scale so long as they document how they work. Implementations are therefore not required to actually perform the UTC-SLS slew or to otherwise be aware of leap seconds.
Implementations should implement Serializable wherever possible and must document whether or not they do support serialization.
Implementation Note:
The clock implementation provided here is based on System.currentTimeMillis(). That method provides little to no guarantee about the accuracy of the clock. Applications requiring a more accurate clock must implement this abstract class themselves using a different external clock, such as an NTP server.
Since:
1.8
java.time.Clock
public static Clock systemDefaultZone()
Obtains a clock that returns the current instant using the best available system clock, converting to date and time using the default time-zone.
This clock is based on the best available system clock. This may use System.currentTimeMillis(), or a higher resolution clock if one is available.
Using this method hard codes a dependency to the default time-zone into your application. It is recommended to avoid this and use a specific time-zone whenever possible. The UTC clock should be used when you need the current instant without the date or time.
The returned implementation is immutable, thread-safe and Serializable. It is equivalent to system(ZoneId.systemDefault()).
Returns:
a clock that uses the best available system clock in the default zone, not null
See Also:
ZoneId.systemDefault()
java.time.Clock
public abstract Instant instant()
Gets the current instant of the clock.
This returns an instant representing the current instant as defined by the clock.
Returns:
the current instant from this clock, not null
Throws:
DateTimeException - if the instant cannot be obtained, not thrown by most implementations
To understand those results, we must first see how the Clock is intended to work. Taking a look at the javadoc, we can see the following description for the methods:
public abstract Instant instant()
Gets the current instant of the clock.
This returns an instant representing the current instant as defined by the clock.
public abstract ZoneId getZone()
Gets the time-zone being used to create dates and times.
A clock will typically obtain the current instant and then convert that to a date or time using a time-zone. This method returns the time-zone used.
So the instant() method will get the current instant as a java.time.Instant, which is a class that always works in UTC. And the key point here is: "as defined by the clock".
The Clock class allows you to create lots of different clock definitions - such as a fixed clock that always returns the same thing - and the most common is the one returned by systemDefaultZone(), which uses the system's current date/time.
As the instant() method returns a java.time.Instant and this class works only in UTC, the result will always be UTC.
The getZone() method will return the timezone used to create dates and times, and this is done by combining the Instant (returned by instant()) with the ZoneId returned by getZone().
You can create a clock with any timezone you want, but systemDefaultZone() just uses the JVM default timezone, which is - in your case - Europe/Moscow.
When you call LocalTime.now(), it internally uses the clock returned by systemDefaultZone().
Then, it uses the results from instant() and getZone(), and combine both to get the LocalTime.
Usage
According to javadoc:
Use of a Clock is optional. All key date-time classes also have a now() factory method that uses the system clock in the default time zone. The primary purpose of this abstraction is to allow alternate clocks to be plugged in as and when required. Applications use an object to obtain the current time rather than a static method. This can simplify testing.
So I wouldn't use the clock directly. Instead, I'd use the now methods from each class, depending on what I need.
If I want the current moment in UTC: Instant.now()
only the current date: LocalDate.now()
and so on...
The now() method without parameters can be very handy and convenient, but it has some drawbacks. It always uses the JVM default timezone behind the scenes. The problem, though, is that the default timezone can be changed at anytime, either by JVM/system's config or even by any application running in the same VM, and you have no control over it.
To not depend on the default configurations, you can use the alternatives now(ZoneId) (which uses an explicity timezone), or now(Clock), which makes your code more testable - see examples here.
While some of the other Answers have correct information, here is a simple summary.
UTC
Instant is in UTC, always, by definition.
Instant instant = Instant.now() // Captures the current moment in UTC. Your default time zone settings are irrelevant.
Implicit default time zone
Calling LocalTime.now() implicitly applies your JVM’s current default time zone.
When you type this code:
LocalTime.now()
… the JVM at runtime does this:
LocalTime.now( ZoneId.systemDefault() )
Not obvious which is why I recommend always passing the desired/expected time zone explicitly as the optional argument.
ZoneId z = ZoneId.systemDefault() ; // Make explicit the fact that you are intentionally relying on the user’s JVM’s current default time zone.
LocalTime lt = LocalTime.now( z ) ; // Capture the current moment in the Wall-clock time used by people of a particular region (a time zone).
Beware: The user’s JVM’s current default time zone can be changed at any moment during runtime. So if the zone is critical, confirm with the user as to their intended time zone, and pass as optional argument.
ZoneId z = ZoneId.of( “Africa/Tunis” ) ; // Or “Europe/Moscow”, whatever.
LocalTime lt = LocalTime.now( z ) ;
My local machine's timezone is HST. But JVM giving me CUT/UTC timezone. I tried using java -Duser.timezone=America/Adak Example, but it sets HST only for Example.class . How/where can I See/Change the JVM's timezone?
The ZONE value in /etc/sysconfig/clock is pointing to HST timezone only.
class Example {
public static void main(String[] args) {
System.out.println(java.util.TimeZone.getDefault());
}
}
The Above code is giving me UTC timezone.
I am using CentOS vagrant box and java 8.
I can Set the Timezone by using java -Duser.timezone=America/Adak
by using above statement we are externally setting the timezone. But we are not taking the Default/machine's timezone.
I am asking how can we get/see/change the system's timezone using java.
You can see your JVM's timezone by
System.out.println(TimeZone.getDefault());
You can set it in the JVM call for example by
java -Duser.timezone=HST ...
or programmatically by something like
TimeZone.setDefault(TimeZone.getTimeZone("HST"));
See your JVM’s current default time zone by calling ZoneId.systemDefault().
You do not explain what is the default time zone of your host OS (which you have not described) versus that of your Vagrant box. I'm not knowledgeable with running Java containerized but I imagine your Java implementation (which you have not yet described) is picking up its default from either the host OS or the container.
Always specify your desired/expected zone
But here is the thing: You should not care. Your Java programming should never rely implicitly on the JVM’s current default time zone. Your Question itself is evidence for my point.
Instead, always specify a time zone explicitly in your code.
Never rely on default zone
Another reason you should never depend on the default is that it can be changed at any moment during runtime(!) by any code in any thread of any app running within the JVM.
Instead pass your desired/expected time zone as an optional argument.
For example, to get the current moment in a zone:
ZoneId z = ZoneId.of( "America/Adak" );
ZonedDateTime zdt = ZonedDateTime( z );
Look throughout the java.time classes and you'll see that wherever a time zone or offset is relevant you can pass a ZoneId or ZoneOffset object as an optional argument. Personally I believe Java programmers would be better off if those arguments were required rather than optional as so many of us fail to think about the issue of time zone and offset.
I have an ec2 instance running in Singapore zone. By default time zone for this instance is UTC. So I've set it to IST assuming, application which is running in this instance generates time in IST which we store in the database.
i.e new Date() in my application shoud return time in IST. But it's still generating time in UTC which isn't we needed.
So, how to make new Date() gives time in IST in ec2 instance without adding explicit java code?
Try to set -Duser.timezone="Asia/India" as Environment Variable or run your java app with that switch from terminal using java filename -Duser.timezone="Asia/India"
java.time
ZonedDateTime.now(
ZoneId.of( "Asia/Kolkata" )
)
Details
The toString method of Date confusingly applies the JVM’s current default time zone while generating the string. This misleads you into thinking it has an assigned time zone but does not^. The Date object actually represents a value in UTC. One of many reasons to avoid these troublesome old legacy date-time classes.
This class is now supplanted by the java.time classes.
The Instant class represents a moment in UTC.
Instant instant = Instant.now();
Adjust into your desired time zone. Never use 3-4 letter abbreviations such as IST. Not a real time zone. Use real time zone names.
ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );
This Question is really a duplicate of many others. Search Stack Overflow for much more discussions and examples.
Do not alter the time zone of your host operating system nor the JVM’s default time zone. You simply should not rely on the default time zone as it can be changed at any moment at runtime by any code in any thread of any app within your JVM. Always specify the optional argument for time zone when calling the java.time classes, problem solved.
^To make things even more confusing, there actually is a time zone within the Date class, but without getters or setters. Used internally, but irrelevant to our discussion here. These old legacy date-time classes are a very confusing mess.