This is not clear to me. For some reason when I am trying to format LocalDateTime instance using DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withLocale(...), I am getting an exception:
java.time.DateTimeException: Unable to extract value: class
java.time.LocalDateTime
It happens only if I am using FormatStyle.LONG, works fine for FormatStyle.MEDIUM, for example.
Here is my test:
#Test
public void dateTest() {
LocalDateTime now = LocalDateTime.now();
// this is ok. prints a value
System.out.println("LocalDateTime now (formatted with locale): "
+ now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(new Locale("it"))));
// this fails with java.time.DateTimeException: Unable to extract value: class java.time.LocalDateTime
// only if FormatStyle.LONG (as it is now)
System.out.println("LocalDateTime now (formatted with locale): "
+ now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(new Locale("it"))));
}
Is there any good explanation for that?
With FormatStyle.LONG You have to use :
ZonedDateTime.now()
Instead of :
LocalDateTime.now()
Because ZonedDateTime gives you lots of detail, not like LocalDateTime.
When you use FormatStyle.LONG, the formater search for other information like ZoneId which is not found in LocalDateTime, so you get exceptions
tl;dr
Is there any good explanation for that?
Yes.
The LONG and FULL formats requires a time zone or offset-from-UTC. Your LocalDateTime lacks any zone or offset.
Your use of LocalDateTime.now is incorrect. You should only capture the current moment with Instant (or OffsetDateTime/ZonedDateTime).
Instant.now() // Capture the current moment as seen in UTC.
For more flexibility in generating strings, use OffsetDateTime or ZonedDateTime.
ZonedDateTime.now(
ZoneId.of( "Pacific/Auckland" )
)
.format(
DateTimeFormatter.ofLocalizedDateTime(
FormatStyle.LONG // Or `FULL`.
)
.withLocale( Locale.ITALY )
)
6 marzo 2019 10:22:23 NZDT
And, with FormatStyle.FULL:
mercoledì 6 marzo 2019 10:23:25 Ora legale della Nuova Zelanda
LocalDateTime is not a moment
The LocalDateTime class is simply a date and a time-of-day. It purposely lacks any concept of time zone or offset-from-UTC. So, by definition, it cannot represent a moment.
Never call LocalDateTime.now()
LocalDateTime.now();
Never do this, never call now on LocalDateTime. I cannot think of any practical situation would ever call for that.
Never use LocalDateTime when tracking moments. A LocalDateTime is merely a date and a time-of-day, and nothing more. Without the context of a time zone or offset-from-UTC, a LocalDateTime cannot represent a moment. It represents potential moments along a range of about 26-27 hours, the current range of time zones around the globe.
A LocalDateTime is like saying “noon on the 23rd of January this year”. Do you mean noon in Tokyo Japan or Kolkata India? Or maybe Paris France? Montréal Québec? Noon in these various places happen at different moments, with hours elapsed between each.
The “Local” in LocalDateTime means any locality, or every locality, but does not mean any particular locality.
Capturing the current moment
To track a moment, use one of these classes:
InstantA moment in UTC, always in UTC
OffsetDateTimeA moment with an offset-from-UTC, that is, a number of hours-minutes-seconds ahead of or behind the baseline of UTC (the meridian at Royal Observatory in Greenwich).
ZonedDateTimeA moment as seen through the wall-clock time used by the people of a particular region (a time zone).
Generally, best practice is to work in UTC and forget about your own parochial time zone.
Instant instant = Instant.now() ;
If you want to use the wall-clock time of some region:
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( instant ) ;
Both the instant and the zdt represent the very same simultaneous moment, the same single point on the timeline. Only the wall-clock time is different.
Or you can skip the Instant.
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
Formats LONG & FULL require a time zone
These two format styles:
FormatStyle.LONG
FormatStyle.FULL
…both require a time zone as part of their display.
As discussed above, a LocalDateTime object has no zone or offset. So it makes no sense to use the LONG or FUL formats with such an object.
Tip: LocalDateTime is not often the class you want in most common business-oriented apps. Only use that class when you have a specific issue clearly in mind, such as booking appointments far enough out in the future that you run the risk of politicians redefining the offset of your time zone (which they often do, in most any polity). When tracking a specific moment, think first of using Instant.
Related
Good day, it's not some errors. But can someone explain to me what happened here?
I'am using free sql database with Spring framework so basically my sql database was on the cloud. Then I'm inserted date time value to my database using my local time zone (Indonesia (GMT+8)). But the time zone is not correct with my time zone even I'm already used localdatetime.now()
This was the case :
Set up my localdatetime zone
LocalDateTime ldt = LocalDateTime.now();
Using my system default time zone
ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
This is the output (My time zone showing at 22:47)
'2022-10-26 16:05:52'
Using (GMT+8)
ZonedDateTime gmt = zdt.withZoneSameInstant(ZoneId.of("GMT+8"));
This is the output (My time zone showing at 23:10)
''2022-10-26 17:10:30''
Using (GMT+12)
This is the output (My time zone showing at 23:15)
''2022-10-26 21:15:47''
Using (GMT+14) I'm even dont know anymore are this time zone literally correct
This is the output (My time zone showing at 23:20)
''2022-10-26 23:20:47'' This was my time zone (basically, this is the right one)
Using GMT+14 was right according to my own clock, but my time zone (Indonesia, GMT+8). Then I'm checked to my server where my database are located at the cloud, then I found it at Asia Pacific.
This is my lines of code :
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
ZonedDateTime gmt = zdt.withZoneSameInstant(ZoneId.of("GMT+14"));
Timestamp timestamp = Timestamp.valueOf(gmt.toLocalDateTime());
transaction.setDate(timestamp);
transactionServices.saveTransaction(transaction);
So are this happened because where my database are located or because something else? Can someone explain so I can improve my code.
I'am expecting using GMT+8 not GMT+14, I'm affraid this can be a problem when this application is produced.
LocalDateTime.now()
I cannot imagine a scenario where calling LocalDateTime.now is the right thing to do.
ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
Skip the LocalDateTime variable ldt. Just ask ZonedDateTime to capture the current moment as seen in your desired time zone.
ZoneId z = ZonedId.systemDefault() ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
ZonedDateTime gmt = zdt.withZoneSameInstant(ZoneId.of("GMT+8"));
For an offset, use the subclass ZoneOffset rather than ZoneID.
ZoneOffset offset = ZoneOffset.of( 8 ) ;
And, this code does not make sense in couple ways. Firstly, if you want to represent a moment as seen through an offset, use OffsetDateTime.
OffsetDateTime odt = OffsetDateTime.now( offset ) ;
Secondly, you should generally 👉 prefer a time zone to a mere offset. When adding or subtracting to move through time, using a mere offset means you will fail to account for changes to the offset used by the people in a particular time zone. For example, you will fail to account for Daylight Saving Time (DST) cut-overs. DST is only one example; politicians frequently change the offset of the time zones under their jurisdiction for various reasons including diplomatic, martial, practical, and fashionable.
A reminder of definitions:
An offset is merely a number of hours, minutes, and seconds ahead of, or behind, UTC.
A time zone is much more. A time zone is a named history of the past, present, and future changes to the offset used by the people of a particular region as decided by their politicians.
For example, the time zone Australia/Perth currently uses an offset of +08:00.
ZoneId z = ZoneId.of( "Australia/Perth" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
By the way, stick with standard ISO 8601 formats for date-time values. So use +08:00 rather than "GMT+8". And I recommend always (a) including both hours and minutes, and (b) using padding zero for single-digit numbers. I have seen more than one library that expects only such values.
Tripping through time zones
You say your own time zone is in Indonesia. I will presume you mean Asia/Jakarta.
Capture the current moment as seen there.
ZoneId zJakarta = ZoneId.of( "Asia/Jakarta" ) ;
ZonedDateTime zdtJakarta = ZonedDateTime.now( zJakarta ) ;
Adjust to UTC, meaning an offset from UTC of zero hours-minutes-seconds. Simply extract a Instant. An Instant is always in UTC, by definition.
Instant instant = zdt.toInstant() ;
Adjust from UTC to another time zone.
ZoneId zEdmonton = ZoneId.of( "America/Edmonton" ) ;
ZonedDateTime zdtEdmonton = instant.atZone( zEdmonton ) ;
Or skip the Instant class. Move from Indonesia time to Canada time.
ZonedDateTime zdtEdmonton = zdtJakarta.withZoneSameInstant( zEdmonton ) ;
👉 Note that all of these moment objects (zdtJakarta, instant, zdtEdmonton) refer to the very same simultaneous moment. All three represent the same point on the time line, just different wall-clock/wall-calendar time.
Avoid legacy classes
Your code:
Timestamp timestamp = Timestamp.valueOf(gmt.toLocalDateTime());
transaction.setDate(timestamp);
👉 Never use the terribly flawed java.sql.Timestamp. This is one of the bloody awful date-time classes that are now legacy, years ago supplanted by the modern java.time classes.
Do not bother trying to study the behavior of these classes. Unless you want a masterclass in how to not design an object-oriented time-tracking framework.
Sun, Oracle, and the JCP community all gave up on the legacy classes with the adoption of JSR 310. I suggest you do the same.
Database
To write a moment to a database, 👉 use OffsetDateTime. Standard SQL lacks the concept of a ZonedDateTime.
To store a moment, a point on the time line, be sure your database table column is of a type akin to the SQL standard type TIMESTAMP WITH TIME ZONE rather than WITHOUT.
ZonedDateTime zdt = … ;
OffsetDateTime odt = zdt.toOffsetDateTime() ; // Discard time zone, keeping only the offset.
myPreparedStatement.setObject( … , odt ) ;
Retrieve.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZonedDateTime zdt = odt.withOffsetSameInstant( myZoneId ) ;
You said:
So are this happened because where my database are located
Do not write code that depends on the current default time zone of your database session, the server OS, or your JVM. If you write database code as I showed here, you are in control of the time zone adjustments.
Not a moment
Notice that nowhere did I use the LocalDateTime class. That is because your Question is asking about moments, specific points on the time line.
A LocalDateTime contains only a date and a time-of-day. The class purposely lacks the concept of a time zone or offset. Therefore, the values in LocalDateTime objects are inherently ambiguous. If you say "noon on the 23rd of January 2023", I have no idea if you mean noon in Tokyo, noon in Toulouse, or noon in Toledo — three different moments several hours apart.
👉 LocalDateTime cannot represent a moment.
The equivalent type in standard SQL is TIMESTAMP WITHOUT TIME ZONE.
All this and more has been covered many many times already on Stack Overflow. Search to learn more.
I am using the Java Instant to get the current date-time information, but it returns to me the UTC Datetime with Z or with [Europe/Berlin]. How do I get the only Datetime information with timezone offset?
Following is the code I have:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Test {
public static void main(String[] args) {
Instant instant = Instant.now();
System.out.println("Current Time : " + instant);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println("LocalDateTime : " + localDateTime);
ZonedDateTime zonedDateTime1 = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println("ZonedDateTime1: " + zonedDateTime1);
}
}
Following is the output I have:
Current Time : 2022-04-13T08:22:35.362644Z
LocalDateTime : 2022-04-13T10:22:35.362644
ZonedDateTime1: 2022-04-13T10:22:35.362644+02:00[Europe/Berlin]
My expected output is:
expected output: 2022-04-13T10:22:35.362644+02:00
How can I get my expected output 2022-04-13T10:22:35.362644+02:00 using Instant? I am aware that I can do the substring(), but I do not want to do that. I am looking for some direct approach to achieve this. Please provide some suggestion.
Also, I do not wish to pass the region information as the application can be accessed across various regions so do not wish to hardcode the region in code.
tl;dr
How do I get the only Datetime information with timezone offset?
OffsetDateTime
.now()
.toString()
2022-04-13T22:47:58.123793+02:00
Or, state your desired/expected time zone explicitly rather than rely implicitly on the JVM’s current default time zone.
OffsetDateTime
.now(
ZoneId.of( "Europe/Berlin" )
)
.toString()
OffsetDateTime
You asked:
How do I get the only Datetime information with timezone offset?
To represent a date with time-of-day as seen in an offset of some number of hours-minutes-seconds from the meridian of UTC, use the OffsetDateTime class.
Calling OffsetDateTime.now() implicitly applies the offset of your JVM’s current default time zone.
OffsetDateTime odt = OffsetDateTime.now() ; // Uses current offset.
See that code run live at IdeOne.com.
2022-04-13T20:47:58.059193Z
The Z on the end means an offset of zero from UTC, and is pronounced “Zulu”.
The IdeOne.com site happens to use a default time zone of UTC itself, a.k.a. “Zulu time”. So let’s specify a time zone to see a different offset in action.
OffsetDateTime odt2 = OffsetDateTime.now( ZoneId.of( "Europe/Berlin" ) ) ; // Use the offset currently in effect for this particular time zone.
2022-04-13T22:47:58.123793+02:00
ZonedDateTime
Usually it is better to use a full time zone rather than a mere offset. A time zone is a named history of the past, present, and future changes to the offset used by the people of a particular region as decided by their politicians.
ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "Europe/Berlin" ) ) ;
2022-04-13T22:47:58.126001+02:00[Europe/Berlin]
But occasionally we need to deal with an offset rather than a zone. Doing SQL work with a database is one important example, as the SQL standard was written only for offsets rather than time zones.
Instant
You asked:
How can I get my expected output 2022-04-13T10:22:35.362644+02:00 using Instant?
You cannot.
The Instant class represents a moment as seen with an offset of zero hours-minutes-seconds from the meridian of UTC. An Instant object by definition is always “in UTC”, that is, carries an offset of zero.
If you have an Instant in hand, you can adjust into a time zone or offset. Rather than assume you know the correct offset, I suggest going through a time zone to let java.time look up the offset in effect at the moment.
ZoneId z = ZoneId.of( "Europe/Berlin" ) ;
ZonedDateTime zdt = myInstant.atZone( z ) ;
OffsetDateTime odt = zdt.toOffsetDateTime() ;
Tip: Be aware that politicians change the time zone rules, and therefore the offset, with surprising frequency and disturbingly little forewarning. Be sure to keep the tzdata up to date if any zone of interest to you is changing. You will find tzdata file in (a) your JVM, (b) your host operating system, and (c) perhaps in ancillary systems such as your database server.
LocalDateTime
Never use LocalDateTime class when tracking a moment, a specific point on the timeline. This class purposely lacks the context of a time zone or offset-from-UTC. An object of LocalDateTime carries only a date and a time-of-day, nothing more.
I cannot imagine any scenario where calling LocalDateTime#now or LocalDateTime.ofInstant would be the right thing to do. In doing so, you would be purposely discarding vital information (the time zone or offset).
I don't see why you need Instant. The following code gives your desired output:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Test {
public static void main(String[] args) {
System.out.println(ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}
}
When I run the above code, I get the following output:
2022-04-13T12:25:31.1157466+03:00
My local time zone is three hours ahead of UTC.
I need to do a LocalDateTime conversion of a UTC date to another LocalDateTime variable considering a specific timezone tz.
During my research I found many solutions, but they all convert the LocalDateTime to another type, like ZonedDateTime.
I need something like that, but LocalDateTime wont work with ZoneId:
LocalDateTime output = input.getInitDate().of(ZoneId.of(tz))
Considering a -3 timezone:
input: 2019-12-03T18:24:07
output: 2019-12-03T15:24:07
Your Question makes no sense.
You need to understand that LocalDateTime holds nothing but a date and a time-of-day. The class purposely lacks any concept of time zone or offset-from-UTC. So LocalDateTime does not represent a moment. The name can be misleading, as a LocalDateTime is not about any particular locality.
If you want to track a moment in UTC, use Instant.
Instant instant = Instant.now() ; // Capture the current moment in UTC. Always in UTC, by definition.
If you want to track a moment as seen in the wall-clock time used by the people of a particular region (a time zone), use ZonedDateTime.
ZoneId z = ZoneId.of( "America/Montevideo" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
LocalDateTime conversion of a UTC date
Do you mean you have particular date and time in mind as seen at the prime meridian? Or as seen in Iceland which uses UTC as their time zone?
LocalDate ld = LocalDate.of( 2020 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 15 , 0 ) ; // 3 PM.
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;
This ldt object means "3 PM on the 23rd of January this year" somewhere, or anywhere. But that LocalDateTime object does not 3 PM in one particular place. We have no idea if the intention here is 3 PM in Tokyo Japan or 3 PM in Toulouse France or 3 PM in Toledo Ohio US. Those would be three different moments, several hours apart. A LocalDateTime represents none of them, or all of them, whichever way you want to see it, but not any one of them.
To determine a moment from a date and a time-of-day, you need the context of a time zone or offset-from-UTC. In other words the third piece of information, in addition to the date and the time-of-day, we need is "as seen in Paris France" or "as seen in Palmer Station in Antarctica". With such a context, we get either ZonedDateTime or OffsetDateTime, respectively.
ZoneId z = ZoneId.of( "Antarctica/Palmer" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ldt , z ) ; // Giving context of time zone to the date-with-time `LocalDateTime` object. Determines a moment.
To see that same moment in UTC (an offset of zero hours-minutes-seconds), extract an Instant.
Instant instant = zdt.toInstant() ; // Adjust from time zone to UTC.
Time zone versus offset-from-UTC
Considering a -3 timezone:
No, -3 is not a time zone, it is an offset.
The -3 is short for -03:00. Practically speaking, I suggest you avoid abbreviating the offset as some libraries expect a full hours-with-minutes including the colon character, and including the leading zero on single-digit hours or minutes.
The -3 or -03:00 means simply "three hours behind UTC".
A time zone is much more. A time zone is a history of the past, present, and future changes to the offset used by the people of a particular region. A time zone has a name in the form of Continent/Region such as Africa/Tunis or Europe/Paris.
See the list of time zones on Wikipedia. Sort by offset column. Notice how around three dozen time zones may today be sharing the offset of -03:00 such as America/Montevideo, Atlantic/Stanley, and Antarctica/Palmer.
Always prefer a time zone to a mere offset. When doing date-time math and adding/subracting spans of time, the results may vary by time zone. Time zones may be using different offsets other than -03:00 on other dates in the past and in the future.
You need to convert it first to ZonedDateTime, change the timezone, and then extract LocalDateTime from that:
ZoneId from = ...;
ZoneId to = ...;
LocalDateTime input = ...;
LocalDateTime output = input.atZone(from).withZoneSameInstant(to).toLocalDateTime();
Try this solution:
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
ZonedDateTime ldtZoned = ldt.atZone(ZoneId.systemDefault());
ZonedDateTime utcZoned = ldtZoned.withZoneSameInstant(ZoneId.of("UTC-3"));
System.out.println(utcZoned.toLocalDateTime());
It gives the output:
2020-02-03T20:55:33.313882
2020-02-03T17:55:33.313882
below is the code I have to print out the current EST date time, but it prints out time in my Time zone which is Arizona Time. What am I missing in this code. Thankyou!
public static void main(String args[]) {
LocalDateTime datetime = LocalDateTime .now();
ZonedDateTime zdtNewYork = ZonedDateTime.of ( datetime , ZoneId.of ( "America/New_York" ) );
System.out.println(zdtNewYork.format(DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss.SSS")));
}
tl;dr
You captured Arizona date and time-of-day, then slapped on a time zone to claim (incorrectly) that New York has the same time-of-day at that moment.
So of course when you generated text to display these values, you saw the time-of-day first captured in Arizona. At no point did you adjust from Arizona to New York.
LocalDateTime is the wrong class
Never use LocalDateTime for tracking moments. By definition, that class cannot represent a specific moment in time, a point on the timeline. It holds a date and time-of-day but lacks the context of a time zone or offset-from-UTC. Telling us "Noon on the 23rd of January this year" is meaningless if we do not know whether you meant noon in Tokyo Japan, Kolkata India, Paris France, or Montréal Québec — all very different moments, hours apart.
Always specify time zone
To compound on using the wrong class, you called LocalDateTime.now without specifying the time zone. So your JVM’s current default time zone was implicitly applied. You claim that default is some time zone in Arizona. So that would be zone applied.
So, you captured the date & time-of-day as seen in Arizona. But then you discarded the fact that the value was in Arizona time zone, because of your use of LocalDateTime. Discarding the time zone is the entire point of the LocalDateTime class. There are cases where that is useful, but certainly not in your situation.
You then took that Arizona date & time-of-day, and claimed that was the date and time in New York. The actual time-of-day in New York was hours ahead of that, so you told a fib. Lastly you generated text showing that fib.
In other words, apparently you thought this line:
ZonedDateTime.of ( datetime , ZoneId.of ( "America/New_York" ) )
…adjusted from Arizona to New York. But that datetime argument no longer knows it came from Arizona, because LocalDateTime has no concept of zone/offset. No adjustment was made.
You can think of it this way:
LocalDateTime = date + time-of-day
OffsetDateTime = date + time-of-day + offset
ZonedDateTime = date + time-of-day + zone
Instant = date + time-of-day + UTC
Instead, I recommend always specifying explicitly your desired/expected time zone. Even if you want the current default time zone, say so explicitly by calling ZoneId.systemDefault so any programmer reading your code knows your intention clearly. Letting the time zone or offset-from-UTC be optional is one of the few things I would change in the otherwise amazing class design found in java.time. Making the zone/offset arguments required would help to educate more programmers about date-time handling.
ZonedDateTime is the right class
To represent a moment as seen through the wall-clock time used by the people of a particular region (a time zone), use ZonedDateTime.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
See this code run live at IdeOne.com.
zdt.toString(): 2019-03-04T18:17:08.014-05:00[America/New_York]
Generate text
We can generate the text you want easily.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu HH:mm:ss.SSS" ) ;
String output = zdt.format( f ) ;
See this code run live at IdeOne.com.
03/04/2019 18:17:08.014
Adjusting zones
If you do want to adjust between zones, call the ZonedDateTime::withZoneSameInstant method.
ZonedDateTime zdtPhoenix = ZoneDateTime.now( ZoneId.of( "America/Phoenix" ) ) ;
ZonedDateTime zdtNewYork = zdtPhoenix.withZoneSameInstant( ZoneId.of( "America/New_York" ) ) ; // Same moment, same point on the timeline, different wall-clock time.
Notice the phrase SameInstant that means you want the same moment, the same simultaneous point on the timeline, but you want to see it through the wall-clock time used by the people of the New York region.
Time zones
print out the current EST date time
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use or refer to the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
Try something like:
LocalDateTime datetime = LocalDateTime .now(ZoneId.of ( "America/New_York" ));
System.out.println(datetime.format(DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss.SSS")));
ZoneId dubai = ZoneId.of("Asia/Dubai");
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDate, localTime, dubai);
System.out.println("Dubai Tiime:"+zonedDateTime);
Above code is still printing the time of my current zone (i.e Asia/Kolkata)
Also i tried the following code to achieve the same but it is also printing time in my current zone(Asia/Kolkata):
ZoneOffset offset = ZoneOffset.of("+04:00");
LocalDateTime localDateTime = LocalDateTime.now();
OffsetDateTime plusFour = OffsetDateTime.of(localDateTime, offset);
System.out.println("Dubai Time :"+plusFour);
I am unable to figure out why its not providing desired result.
The answer by Kokorin is correct. Here's a bit more discussion.
Problems
When you called the now method and passed no arguments, you failed to specify a time zone. In that omission, java.time silently applied your JVM’s current default time zone in determining the current local time and current local date.
You claim your JVM’s current default time zone is Asia/Kolkata (India time). If when you ran that code it was 15:30 time in your office, your code is saying “let's take my 15:30 and use that as input to represent a wall-clock time in Dubai”. So while the current moment in Dubai was actually 14:00 (an hour and half closer to UTC than India I presume, not sure), you created a date-time for an hour and a half in the Dubai’s future: 15:30.
When you passed dubai in the line ZonedDateTime.of( localDate, localTime, dubai ) you assumed you were asking for an adjustment between time zones. But in fact you were assigning a time zone to a plain (“Local”) date and time that had no time zone at all. All three of the Local… classes store no time zone internally; their very purpose is to ignore time zone. Your code did not match your intentions.
Note how in this revision to your code I pass your ZoneId object to both now methods. This would solve your problem.
ZoneId dubai = ZoneId.of ( "Asia/Dubai" );
LocalDate localDate = LocalDate.now ( dubai );
LocalTime localTime = LocalTime.now ( dubai ); // Capturing `14:00` in Dubai rather than than `15:30` in India as in your version of code.
ZonedDateTime zonedDateTime = ZonedDateTime.of ( localDate , localTime , dubai );
System.out.println ( "Dubai Tiime:" + zonedDateTime );
But this is still bad code. If those pair of .now methods were called over the stroke of midnight, you would have very wrong information (off by about 24 hours).
Solutions
Instead you should capture the current moment atomically. Either user Kokorin's code, or use my code shown next.
An Instant is a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = Instant.now();
ZoneId zoneId_Dubai = ZoneId.of( "Asia/Dubai" );
ZonedDateTime zdt_Dubai = ZonedDateTime.ofInstant( instant , zoneId_Dubai );
As a shortcut, call the static method ZonedDateTime.now.
ZonedDateTime zdt_Dubai = ZonedDateTime.now( zoneId_Dubai );
To see the same moment but with your own wall-clock time, adjust into India time.
ZonedDateTime zdt_Kolkata = zdt_Dubai.withZoneSameInstant( ZoneId.of( "Asia/Kolkata" ) );
BIG TIP: Always pass the optional time zone arguments. While I tremendously respect the work that went into java.time, I consider making the time zone arguments optional on various methods to be a design flaw. The silent implicit application of your JVM’s current default time zone is just too easy a trap to fall into for so many programmers. By the way, ditto for Locale, always specify.
Another Tip: Think, work, and store in UTC. As a programmer you must learn to think in UTC, get your head out of “my time in Kolkata” and “their time in Dubai”. You will drive yourself crazy and make your brain hurt. While programming, know that the only one true time is UTC. All the other Dubai/Kolkata/Montréal/Auckland times are smoke and mirrors, mere illusions. Use the Instant class in much of your code, make it your “go to” class when doing date-time work (only apply a time zone for display to the user). Use UTC in your database. Do your logging in UTC. Keep your servers on UTC (or Iceland) time zone. Use UTC when serializing date-time values to storage or in data-exchange (and use ISO 8601 formats btw). Keep a clock on your desk or screen displaying UTC. Later, when you go home from work, then you can slip back into your own local "India time" thinking.
The problem is that you instantiate ZonedDateTime with your local date and time.
This will do what you want:
ZonedDateTime dubaiDT = Instant.now().atZone(dubaiZone);