I have web apps for 3 regions(Mongolia,Turkmenia, etc). And they are deployed on tomcat's virtual host. Now I need set timezone for each application. How can I do that? I implemented ServerContextListener interface for each apps to set TimeZone:
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
TimeZone timeZone=TimeZone.getTimeZone("Asia/Ulan_Bator");
// TimeZone timeZone=TimeZone.getTimeZone("Asia/Ashgabat");
timeZone.setDefault(timeZone);
}
But after deploy each apps has same TimeZone.
P.S: Sorry for my English :)
ZoneId
, notTimeZone
The terrible legacy date-time classes were supplanted years ago by the modern java.time classes with the adoption of JSR 310.
TimeZone
in replaced byZoneId
&ZoneOffset
.Avoid default time zone
Avoid relying on the JVM’s current default time zone.
There is only one default time zone for the JVM. Calling
TimeZone.setDefault
immediately affects all code in all threads of all apps within that JVM.So you cannot set a different default time zone per web app. If all the web apps are running in the same Servlet container, then all the web apps share the same default time zone.
Pass desired time zone
A better approach is to explicitly pass the desired/expected time zone as the optional argument to various java.time methods. For example, if you want to capture the current moment as seen in a particular time zone, pass the desired
ZoneId
object to thenow
method.Rather than depend on the JVM’s current default time zone, set a time zone for each of your web apps.
ServletContextListener::contextInitialized
You were close to a solution. When each web app launches, you need to specify its default. The place to do that is in the
contextInitialized
method in your class implementing theServletContextListener
as shown in your Question.Inside that method, specify the desired time zone.
But that variable goes out of scope and disappears at the end of the
contextInitialized
method. So we need to store a reference to thatZoneId
object somewhere. But where? The Servlet spec defines a place just for such “global” variables or constants you need across code within your app.Your
contextInitialized
method is passed aServletContextEvent
. That object holds a reference to theServletContext
object representing the current instance of your web app that is launching.Attributes (key-value store)
That
ServletContext
conveniently maintains a simple key-value store of “attributes”. The key is aString
, the value anObject
. We can make up a string name for our per-web-app default time zone, and pass theZoneId
as theObject
value. Pass these toServletContext::setAttribute
.In your app's code, look up the context and attribute anytime you need. Ask the Servlet request being serviced for its context.
Ask for the value from the stored attribute.
Cast the
Object
back to aZoneId
. We know that should work, but for defensive programming you may want to checkinstanceof
.Then proceed with your work. Perhaps you want to capture the time as seen in that zone, just as we discussed above.
Tip: You might want to define an enum to handle those multiple region strings for the attributes names. Copy-pasting string values is risk business. See tutorial.
Thread-safety
Note that while each web app instance has its own
ZoneId
object, that object is being shared across threads. A Servlet environment is by definition highly-threaded, each request being serviced on a thread. So thatZoneId
is being shared across any number of threads. But that is okay. Fortunately, the java.time classes are thread-safe by design, using the immutable objects pattern.Obligatory Servlet threading concurrency tip: Anyone doing Servlet coding should be reading and re-reading this book: Java Concurrency in Practice by Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea.
You can set JVM timezone for tomcat. For that you need to add below option in your JVM options, in tomcat configuration file.
-Duser.timezone=UTC
Use your timezone in place of UTC. It will start your JVM in that timezone.