Strange behavior of OffsetDateTime.now() in Android - java

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().

Related

Java Instant to Date - With Different Timezone

I am running my code in EST timezone.
Using Instant.now() in my code and it returns time in UTC.
But, I am trying to test a method which gets data from DB as Date not Instant and hence trying to convert this to Date using
Date.from(Instant.now())
Since, I am running this in EST, this Date gives me time in EST.
Actual code,
final Optional<Date> dbTime = dbService.getUpdatedTime();
final Instant lastInstant = dbTime.orElseGet(() -> Date.from(Instant.now())).toInstant();
Test Code,
final Date dbTime = Date.from(Instant.now().minusSeconds(36000));
when(dbService.getUpdatedTime().thenReturn(Optional.of(dbTime));
Here, the dbTime gets converted to EST time. I can make that to return UTC time by setting TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Is there any other better way? Is this ok to set TimeZone.setDefault(TimeZone.getTimeZone("UTC")); in the main Application class so that it will always be treated as UTC?
First recommendation, since you can use the modern Java date and time API, use it as much as you can and minimize the use of the outdated Date class. Best will be if you can modify getUpdatedTime() to return an Optional<Instant> rather than an Optional<Date> (a modern JDBC driver can give you the datetime from your database as an Instant directly). Since an Instant prints in UTC, this should wipe away all of your issue and your question.
In this answer I am assuming that you either cannot do that or don’t want to do it just yet. You can still get close, though:
final Optional<Instant> dbTime = dbService.getUpdatedTime().map(Date::toInstant);
final Instant lastReconInstant = dbTime.orElseGet(Instant::now);
Avoid TimeZone.setDefault(). Since the JVM only has one global time zone setting, this may unintentionally change the behaviour of other parts of your program or other programs running in the same JVM.
A detail, in your stub code I recommend to make it explicit that you subtract 10 hours. Two options are
final Date dbTime = Date.from(Instant.now().minus(10, ChronoUnit.HOURS));
final Date dbTime = Date.from(Instant.now().minus(Duration.ofHours(10)));
All of this said, it still seems to me that you didn’t have a problem in the first place. A Date does not have a time zone in it. Its toString method just grabs the JVM’s default time zone and uses it for rendering the date and time. This has fooled many and is just one of the reasons to avoid that class when you can.

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.

Handling TimeZone change with Date class in 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());
}
}

SimpleDateFormat give inconsistent results

I am trying to parse a date and I am getting different results when I run the code locally/BST compare to a server in Paris/CEST.
I've reproduced the issue in a the following sample. This is trying to parse the start date for the Australian Grand Prix.
TimeZone tz = TimeZone.getTimeZone("AET");
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH mm");
dateFormat.setTimeZone(tz);
long time = dateFormat.parse("28/03/2010 17 00").getTime();
System.out.println("Time "+time);
It seems like I am setting the timezone correctly on the date format and the current timezone shouldn't be affecting the code. But locally it prints 1269756000000 and in Paris 1269759600000. Any idea?
Answer:
It seems like I was testing with an edge case: the Timezone definition is different on my mac compare to the linux server. If I change the timezone to be: "America/Los_Angeles" I am getting a consistent result. The linux box giving me the wrong result is running java 1.6.0-b105 which might be outdated. I'll try an upgrade
Interesting. According to the TimeZone documentation:
Three-letter time zone IDs For
compatibility with JDK 1.1.x, some
other three-letter time zone IDs (such
as "PST", "CTT", "AST") are also
supported. However, their use is
deprecated because the same
abbreviation is often used for
multiple time zones (for example,
"CST" could be U.S. "Central Standard
Time" and "China Standard Time"), and
the Java platform can then only
recognize one of them.
It would be interesting to see the results if you use "Australia/Melbourne" instead of "AET", but just from a quick experiment that I did, it doesn't seem like it makes a difference.
It's curious that the results are an hour apart, like Daylight Savings Time isn't being taken into account in one of the cases. Stupid question; if you're running on two separate computers, are you sure the times are set correctly on each?
On my system here, the result is "1269756000000" (like on your local system). I would try to check the server in Paris, especially the settings that concern the timezone:
System.out.println(System.getProperty("user.timezone"));
System.out.println(System.getProperty("user.country"));
Maybe this brings up some differences that helps you to solve this issue.

Categories

Resources