Handling TimeZone change with Date class in JAVA - java

I am trying to print the current system date and time as below,
public class PrintDate {
public void getDate(){
while(true){
System.out.println(new Date());
}
}
public static void main(String[] args) {
new PrintDate().getDate();
}
}
This endless loop prints the current system time stamp as expected and it works fine when i make change in date or time in the OS but not with the timezone change..
Example :
I started the above code , which continuously print the current system time stamp as expected.
When i change the system date or time , it successfully gets reflected in the code.
When i change the system timezone , It is not reflecting in the code. It still show the same timezone since the program started.
May i know the reason behind this?

The time zone is part of the environment of the process. Changing the time zone globally for your system only affects new processes.
See also How to set time zone of a java.util.Date?:
Be aware that java.util.Date objects do not contain any timezone
information by themselves - you cannot set the timezone on a Date
object. The only thing that a Date object contains is a number of
milliseconds since the "epoch" - 1 January 1970, 00:00:00 UTC.
As ZZ Coder shows, you set the timezone on the DateFormat object, to
tell it in which timezone you want to display the date and time.

The answer by neuhaus is correct.
If you meant you changed the time zone of your host operating system while running that code, know that the Java Virtual Machine (JVM) has its own current default time zone.
Usually that default is picked up from that of the host OS. If so in your case, that must mean your Java implementation is detecting the host time zone only at launch and not checking for later changes in the host OS‘ time zone.
The time zone of your JVM can also be set as a configuration parameter upon launch. In that case I should think the JVM would purposely ignore the host OS’ time zone changes.
Any Java code in any thread of any app within that JVM can change the JVM’s current default time zone at any moment during runtime. Again, I should think the JVM would purposely ignore the host OS’ time zone changes.
The class doc for java.util.TimeZone.getDefault() outlines steps taking in determining the current default time zone.
If the cached default TimeZone is available, its clone is returned. Otherwise, the method takes the following steps to determine the default time zone.
• Use the user.timezone property value as the default time zone ID if it's available.
• Detect the platform time zone ID. The source of the platform time zone and ID mapping may vary with implementation.
• Use GMT as the last resort if the given or detected time zone ID is unknown.
The default TimeZone created from the ID is cached, and its clone is returned. The user.timezone property value is set to the ID upon return.
In my reading of that, it says the JVM is not going to detect any changes to the host OS setting. Once launched, and once a default has been determined, it is stored in that user.timezone property (and a value in cache) until changed with a call to setDefault.
java.time
You are using the old java.util.Date class which has been supplanted by the java.time framework in Java 8.
Use the java.time.ZonedDateTime class and specify the desired/expected time zone.
ZoneId zoneId = ZoneId.of( " America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.now( ZoneId );
You should almost never depend on the JVM’s current default time zone ( nor the current default Locale).

import java.util.Date;
public class DateDemo {
public static void main(String args[]) {
//Instantiate a Date object
Date date = new Date();
//display time and date using toString()
System.out.println(date.toString());
}
}

Related

Strange behavior of OffsetDateTime.now() in Android

If I do in a generally Java program:
OffsetDateTime offsetDateTime = OffsetDateTime.now();
then I have an output of 2020-04-01T20:22:04.604+02:00.
If I do the same on Android then I have the output 2020-04-01T18:22:04.604Z.
Also with formatting to local_time:
String format = DateTimeFormatter.ISO_LOCAL_TIME.format(now);
the output is 18:22:04.604
But I want from now() my local DateTime 20.22 and not the UTC time.
The systems timezone in Android is European Summertime +02:00.
What is going on here?
The safest way is to pass the time zone that you want to the now method:
OffsetDateTime offsetDateTime = OffsetDateTime.now(ZoneId.of("Europe/Vienna"));
System.out.println(offsetDateTime);
Output when I ran just now:
2020-04-04T09:02:05.059927+02:00
Giving time zone explicitly frees us from relying on the default time zone of the JVM.
If I understand your question correctly, the JVM time zone setting didn’t reflect the time zone setting of your device. It’s possible for the two to be different, but how that came to be in your case, I cannot tell. Possible explanations include:
Your JVM was launched with a setting of the user.timeaone equal to UTC.
Some place in your program or another program running in the same JVM the time zone is set to UTC, either by setting the above mentioned system property or by calling TimeZone.setDefault().

Java: Fix incorrect timezone in date object

An external API returns an object with a date.
According to their API specification, all dates are always reported in GMT.
However, the generated client classes (which I can't edit) doesn't set the timezone correctly. Instead, it uses the local timezone without converting the date to that timezone.
So, long story short, I have an object with a date that I know to be GMT but it says CET. How can I adjust for this mistake withouth changing my local timezone on the computer or doing something like this:
LocalDateTime.ofInstant(someObject.getDate().toInstant().plus(1, ChronoUnit.HOURS),
ZoneId.of("CET"));
Thank you.
tl;dr ⇒ use ZonedDateTime for conversion
public static void main(String[] args) {
// use your date here, this is just "now"
Date date = new Date();
// parse it to an object that is aware of the (currently wrong) time zone
ZonedDateTime wrongZoneZdt = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("CET"));
// print it to see the result
System.out.println(wrongZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// extract the information that should stay (only date and time, NOT zone or offset)
LocalDateTime ldt = wrongZoneZdt.toLocalDateTime();
// print it, too
System.out.println(ldt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
// then take the object without zone information and simply add a zone
ZonedDateTime correctZoneZdt = ldt.atZone(ZoneId.of("GMT"));
// print the result
System.out.println(correctZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}
Output:
2020-01-24T09:21:37.167+01:00[CET]
2020-01-24T09:21:37.167
2020-01-24T09:21:37.167Z[GMT]
Explanation:
The reason why your approach did not just correct the zone but also adjusted the time accordingly (which is good when desired) is your use of a LocalDateTime created from an Instant. An Instant represents a moment in time which could have different representations in different zones but it stays the same moment. If you create a LocalDateTime from it and put another zone, the date and time are getting converted to the target zone's. This is not just replacing the zone while keeping the date and time as they are.
If you use a LocalDateTime from a ZonedDateTime, you extract the date and time representation ignoring the zone, which enables you to add a different zone afterwards and keep the date and time as it was.
Edit: If the code is running in the same JVM as the faulty code, you can use ZoneId.systemDefault() to get the same time zone as the faulty code is using. And depending on taste you may use ZoneOffset.UTC instead of ZoneId.of("GMT").
I am afraid you will not get around some calculations here. I'd strongly suggest to follow an approach based on java.time classes, but alternatively you might use the java.util.Calendar class and myCalendar.get(Calendar.ZONE_OFFSET) for those calculations:
https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#ZONE_OFFSET

Clock.fixed what is the role of zone

According to the javadoc for Clock.fixed, zone is:
zone - the time-zone to use to convert the instant to date-time, not null
But my code doesn't seem to be affected by using a different zone.
Clock mockClock = Clock.fixed(Instant.parse("2017-04-10T17:59:00Z"),
ZoneId.of("UTC"));
System.out.println("ZonedDateTime using clock "+ZonedDateTime.now(mockClock));
In the above code, whether I set the timezone as UTC or America/Chicago, the output is the same:
ZonedDateTime using clock 2017-04-10T17:59Z[UTC]
If it doesn't change the timezone, what is the role of zone?
Normally, a Clock instance retrieved using one of the static methods
Clock.system(ZoneId z)
Clock.systemDefaultZone()
Clock.systemUTC()
is a "running" clock that returns the current time. A Clock always tracks UTC, but also knows its timezone, which it uses when returning date/time values.
If you read the Javadoc carefully you'll see that Clock.fixed() returns a special type of clock that is not running, that is, it is always set to a specific instant and does not change with time.
ZonedDateTime.now(Clock clock) queries the given clock and returns the current time adjusted for the Clock's timezone.
So when you do
Clock mockClock = Clock.fixed(Instant.parse("2017-04-10T17:59:00Z"), ZoneId.of("UTC"));
ZonedDateTime zdt = ZonedDateTime.now(mockClock);
the following happens:
A special "not running" clock is created that is set to the date/time you gave, with a timezone specification of UTC.
The ZonedDateTime.now(mockClock) call reads the current value of the clock, which in your case is fixed, and creates a ZonedDateTime with the clock value and a timezone of UTC.

google appengine - Time zone changed

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.

how to set timezone for jvm through command line

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.

Categories

Resources