Not getting correct timezone in Java 8? - java

I have set my system data time to Asia/Kolkata and it is:
Date: 2015-06-12
Time: 12:07:43.548
Now i have written following program in Java 8
ZoneId paris = ZoneId.of("Europe/Paris");
LocalDateTime localtDateAndTime = LocalDateTime.now();
ZonedDateTime dateAndTimeInParis = ZonedDateTime.of(localtDateAndTime, paris );
System.out.println("Current date and time in a particular timezone : " + dateAndTimeInParis );
When i run the code it shows following time for Paris:
Current date and time in a particular timezone :
2015-06-12T12:07:43.548+02:00[Europe/Paris]
The above Europe/Paris is same as of Asia/Kolkata. Could anyone please explain where i am doing wrong?
Update: I prefer not using class from another Java package; as i have heard that this package java.time have enough functionalities to handle maximum date time jobs and i hope this one is included :)

A LocalDateTime is a date and time without a timezone. When you create a ZonedDateTime object out of it, you're explicitly attaching a timezone to the LocalDateTime.
It's not going to convert from your timezone to the Europe/Paris timezone; note that the LocalDateTime does not have a timezone at all; it doesn't know that you mean it to be Asia/Kolkata.
If you want to convert from Kolkata time to Paris time, start with a ZonedDateTime that uses the Asia/Kolkata timezone:
// Current time in Asia/Kolkata
ZonedDateTime kolkata = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
// Convert to the same time in Europe/Paris
ZonedDateTime paris = kolkata.withZoneSameInstant(ZoneId.of("Europe/Paris"));
(edit, thanks JBNizet): If you just want "now" in Europe/Paris time, you can do:
ZonedDateTime paris = ZonedDateTime.now(ZoneId.of("Europe/Paris"));

Related

Convert UTC time to Europe/London timezone in java

I've current datetime in UTC but I need date time of timezone (Europe/London). I tried but everytime time is not adding instead of this offset is appending in current date time.
My code -
LocalDateTime utcTime = LocalDate.now().atTime(0,1);
System.out.println("utc time " + utcTime);
ZoneId europeLondonTimeZone = ZoneId.of("Europe/London");
ZoneOffset offset = europeLondonTimeZone.getRules().getOffset(utcTime);
OffsetDateTime offsetDateTime = utcTime.atOffset(offset);
System.out.println(offsetDateTime);
It will print:
"2021-06-18T00:01+01:00"
but I want
"2021-06-17T23:01"
as +01:00 is ahead in daylight saving time.
Thanks
If you just want the current time in Great Britain, there is no need to convert from UTC. You can have that time directly.
ZoneId europeLondonTimeZone = ZoneId.of("Europe/London");
OffsetDateTime offsetDateTime = OffsetDateTime.now(europeLondonTimeZone);
System.out.println(offsetDateTime);
Output when I ran the code just now:
2021-06-18T19:18:39.599+01:00
If you do need to have the UTC time first, avoid using LocalDate or LocalDateTime for that. The local in some java.time class names means without time zone or UTC offset. Prefer OffsetDateTime, which itself keeps track of its offset, as the name says. So when it’s in UTC, it “knows” this fact itself.
// Sample UTC time
OffsetDateTime utcTime = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println("UTC time: " + utcTime);
ZoneId europeLondonTimeZone = ZoneId.of("Europe/London");
OffsetDateTime offsetDateTime = utcTime.atZoneSameInstant(europeLondonTimeZone)
.toOffsetDateTime();
System.out.println("UK time: " + offsetDateTime);
UTC time: 2021-06-18T18:18:39.669Z
UK time: 2021-06-18T19:18:39.669+01:00
The atZoneSameInstant method converts from whatever offset the OffsetDateTime was in (in this case UTC) to the time zone passed as argument, thus typically altering the clock time (sometimes even the date).
What went wrong in your code?
A LocalDate contains a date without time of day only, so LocalDate.now() only gives you which day it is in the default time zone of your JVM (so not even which day it is in UTC), not the time of day. .atTime(0,1) converts that day to a LocalDateTime representing the time of 0 hours 1 minute, that is, 00:01, on that day, still without any time zone.
Also a ZonedDateTime not only knows its time zone but can also handle its time zone rules. So there is no reason for you to deal with the offset at a particular time yourself.
Finally LocalDateTime.atOffset() converts to an OffsetDateTime but neither changes the date nor the time of day. Since the LocalDateTime did not have any time zone, the method cannot be used for converting between time zones.

Why time not converted according to time zone?

I have LocalDateTime that keeps value in UTC.
I want to convert it to local date and time according to a time zone,
here how I do it:
public LocalDateTime convertUTC2LocalDateTimeZone(LocalDateTime dateTime){
System.out.println("dateTime:" + dateTime);
ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.of("Canada/Mountain"));
System.out.println("zonedDateTime:" + zonedDateTime);
LocalDateTime ldt = zonedDateTime.toLocalDateTime()
System.out.println("ldt:" + ldt);
return ldt;
}
Output:
dateTime:2018-07-15T10:00:46
zonedDateTime:2018-07-15T10:00:46-06:00[Canada/Mountain]
ldt:2018-07-15T10:00:46
As you can see the ldt value is the same as input, no time conversion occurred.
Any idea why time conversion not occurred?
A LocalDateTime represents a "local time and date". In other words: it's something abstract like "January 1st 2020, 10:00 AM" without any time zone information.
It does not represent anything in UTC. There simply is no time zone information contained in it.
So it doesn't represent a "physical" or exact point in time. To do this you need to convert it to a ZonedDateTime by adding some time zone. The way you do in your code basically says: "Give me a ZonedDateTime object that represents the local time provided by this LocalDateTime in the given time zone".
That means this ZonedDateTime does represent a fixed point in time (i.e. you can calculate the milliseconds since the epoch, basically).
Then you ask "given that ZonedDateTime, what would the local date/time be?", which will just return the value that you initially put in without any modification.
To actually convert from UTC to some other timezone, you need to explicitly create a ZonedDateTime in the UTC timezone first:
create ZonedDateTime representing UTC
calculate ZonedDateTime in the target timezone
get a LocalDateTime from the ZonedDateTime created in #2.
So in code:
ZonedDateTime utcDateTime = dateTime.atZone(ZoneOffset.UTC); // #1
ZonedDateTime mountainDateTime = utcDateTime.withZoneSameInstant(ZoneId.of("Canada/Mountain")); // #2
LocalDateTime localDateTimeAtMountain = mountainDateTime.toLocalDateTime(); // #3

UTC time in java? [duplicate]

This question already has answers here:
How can I get the current date and time in UTC or GMT in Java?
(33 answers)
Closed 4 years ago.
How can I get UTC value in Java of any given time and date with the respective time-zone?
Say for example my current time zone is Asia/Kolkata, now how can I get UTC value of say 1.00 am on 21/07/2018?
For getting currect time in UTC.
Instant.now() // Current time in UTC.
For getting current time in any desired TimeZone.
ZonedDateTime.now( ZoneId.systemDefault() ) // Current time in your ZoneId.
Kolkata Example :
ZoneId zoneKolkata = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zoneDTKolkata = instant.atZone( zoneKolkata ) ;
To adjust back to UTC, extract an Instant from the ZonedDateTime.
Instant instant = zoneDTKolkata.toInstant() ;
You can adjust from UTC to a time zone.
ZonedDateTime zoneDTKolkata = instant.atZone( zoneKolkata ) ;
Use the Java 8 time API instead of the older API (ie Date & SimpleDateFormat solution proposed by rajadilipkolli)
// System time (ie, your operating system time zone)
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
// Time in Asia/Kolkata
ZonedDateTime kolkata = ldt.atZone(ZoneId.of("Asia/Kolkata"));
// Time in UTC
OffsetDateTime utc = ldt.atOffset(ZoneOffset.UTC);
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("h.mm a 'on' dd/MM/uuuu")
.toFormatter(Locale.ENGLISH);
ZoneId zone = ZoneId.of("Asia/Kolkata");
String localDateTimeString = "1.00 am on 21/07/2018";
Instant i = LocalDateTime.parse(localDateTimeString, formatter)
.atZone(zone)
.toInstant();
System.out.println("UTC value is: " + i);
This prints:
UTC value is: 2018-07-20T19:30:00Z
I wasn’t sure whether you needed to parse the exact string you gave, 1.00 am on 21/07/2018, into a date-time object, but in case I have shown how. The challenge is that am is in lowercase. In order to specify case insensitive parsing I needed to go through a DateTimeFormatterBuilder.
As you can see, the code converts to an Instant, which is the modern way to represent a point in time in Java. Instant.toString always prints the time in UTC. The Z at the end means UTC. If you want a date-time that is more explicitly in UTC you may use
OffsetDateTime odt = LocalDateTime.parse(localDateTimeString, formatter)
.atZone(zone)
.toInstant()
.atOffset(ZoneOffset.UTC);
System.out.println("UTC value is: " + odt);
The output is similar, only OffsetDateTime leaves out the seconds if they are 0 (zero):
UTC value is: 2018-07-20T19:30Z
Link: Oracle tutorial: Date Time explaining how to use java.time, the modern Java date and time API.

Converting time to UTC using java 8

I have some APIs in Java which accept times as strings.
The UI sends plain string like "10:00:00". I am creating a LocalTime out of that and saving in the db (MySQL).
Later in another API I use a LocalDate object and the above time with Zone UTC to create a ZonedDateTime object that is saved to the db. My problem is that the time is not getting converted to UTC.
ZonedDateTime.of(LocalDate.now(ZoneId.of("UTC")),LocalTime.now(ZoneId.of("UTC")), ZoneId.of("UTC"));
ZonedDateTime.of(LocalDate.now(ZoneId.of("UTC")),dto.getStart(), ZoneId.of("UTC"));
Both of these are different though I am sending for eg 07:00:00 which is my time in India. Please guide me as to how I should convert the time alone to UTC.
EDIT:: I have set jvm Duser.Timezone to UTC.When I do this:
ZonedDateTime.of(LocalDate.now(ZoneId.of("UTC")),dto.getStart(), ZoneId.of("UTC")).getOffset().getTotalSeconds();
It gives 0 as seconds
EDIT::
ZoneId z = ZoneId.of("Asia/Calcutta");
ZoneId z1 = ZoneId.of("UTC");
TimeZone.getTimeZone(z).getRawOffset();
Tried this and it gives the diff in ms. I will try using this provided the UI sends the actual local zone. Will update..
If the input corresponds to your local time, you can create a ZonedDateTime to get the current date in India timezone, set the time and then convert it to UTC:
LocalTime time = LocalTime.parse("10:00:00"); // 10 AM
ZonedDateTime utc = ZonedDateTime
.now(ZoneId.of("Asia/Calcutta")) // current date/time in India
.with(time) // set time to 10 AM
.withZoneSameInstant(ZoneOffset.UTC); // convert to UTC
The value of variable utc will be 2018-01-29T04:30Z (running the code today, January 29th). The time in UTC is 4:30 AM, which is equivalent to 10 AM in India.
I believe that MySQL can't save a ZonedDateTime, so you can first convert it to an Instant by calling utc.toInstant(). Or if the driver you use is an older version and it works only with java.util.Date, you can convert it using Date.from(utc.toInstant()).
Also note that I used the constant ZoneOffset.UTC, which is equivalent to (but better than, IMO) calling ZoneId.of("UTC").
For now We have decided to allow the UI to change the time to whatever is its timezone. JVM timezone for the server is set to UTC...
I would advise against storing a ZonedDateTime in a MySQL database. MySQL timestamps don't store the timezone information so you can't guarantee you'll get back the same time that you save.
Instead I would store a LocalDateTime and standardise on UTC for internal times and then format with a timezone when you need to display etc. To get the current time in UTC you can do something like this.
LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
To build a UTC timestamp for today and a provided time you could do something like this.
LocalTime time = getTime();
LocalDateTime = LocalDateTime.of(LocalDate.now(Clock.systemUTC()), time);
To build a timestamp using the date for the current timezone, a provided time and then convert to UTC for saving to the database.
ZoneId timezone = ZoneId.of("Asia/Calcutta");
LocalTime time = getTime();
ZonedDateTime zdt = ZonedDateTime.of(LocalDate.now(timezone), time, timezone);
LocalDateTime utcDateTime = LocalDateTime.ofInstant(zdt.toInstant(), ZoneOffset.UTC);

Convert Time from one time zone to another using Java 8 Time

I am trying to convert Date with GMT +5:30 to EST with java 8 ZonedDateTime.
String inputDate = "2015/04/30 13:00";
DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US);
LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);
// local : 2015-04-30T13:00
//Combining this local date-time with a time-zone to create a ZonedDateTime.
ZonedDateTime zoned = local.atZone(TimeZone.getTimeZone("GMT+5:30").toZoneId());
// zoned : 2015-04-30T13:00+05:30[GMT+05:30]
ZonedDateTime zonedUS = zoned.withZoneSameInstant(TimeZone.getTimeZone("GMT-5:00").toZoneId());
// zonedUS : 2015-04-30T02:30-05:00[GMT-05:00]
I am expecting 3:30 AM EST but what I am getting is 2:30 AM EST as 1 PM IST= 3:30AM EST. What am I missing?
It seems that whatever service you found was being over-helpful in interpreting what you meant and assumed North American Eastern Daylight Time (EDT) when you specified EST (Eastern Standard Time). Most, not all of the places using EST as standard time are using daylight saving time and hence were on EDT or offset UTC-04:00 on the date you use, April 30, 2015.
If it makes sense in your situation, you should always prefer to give time zone in the region/city format, as Asia/Kolkata and America/New_York. If you intended Eastern Time as in New York or Montréal, one may say that your “time zone” of GMT-5:00 was wrong and the cause of your unexpected result.
So your code becomes for example:
String inputDate = "2015/04/30 13:00";
DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US);
LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);
// local : 2015-04-30T13:00
//Combining this local date-time with a time-zone to create a ZonedDateTime.
ZonedDateTime zoned = local.atZone(ZoneId.of("Asia/Kolkata"));
// zoned : 2015-04-30T13:00+05:30[Asia/Kolkata]
ZonedDateTime zonedUS = zoned.withZoneSameInstant(ZoneId.of("America/Montreal"));
// zonedUS : 2015-04-30T03:30-04:00[America/Montreal]
I have made one other change: When using the modern classes from java.time, there is no point in also using the outdated TimeZone class, so I have taken that out. The code is slightly simpler, and more importantly, ZoneId.of(String) includes validation of your time zone string so you will discover any spelling error in the time zone name (like when I just happened to type a ( instead of the / in Asia/Kolkata — such happens all the time).
Most of the above has already been said in comments by Jon Skeet and others. I thought it deserved to go into an answer so it’s plain to see that the question has been answered.
Though the question is old, felt like I could add more to the accepted answer.
A ZonedDateTime is different from an OffsetDateTime.
I would prefer to use ZonedDateTime when I'm getting a time for a specific location like "Asia/Kolkata", "Asia/Shanghai", "US/Pacific" (this time zone will change depending on the day of the year because of Daylight savings).
To illustrate with an example,
var pacific = ZonedDateTime.of(2020,11,01,1,59,0,0,ZoneId.of("US/Pacific"))
var afterAnHour = pacific.plusHours(1)
This will give me a time of
2020-November-01 01:59:00.000 AM -07:00[US/Pacific]
And if i add an hour to it, it will give me a time of
2020-November-01 01:59:00.000 AM -08:00[US/Pacific]
You can see that the hour component is same even after adding an hour to the time. This is because the daylight savings time has kicked in and the time zone is shifted from -07:00 to -08:00.
Now if i use an OffsetDateTime look what happens.
var offsetNow = OffsetDateTime.of(2020,11,01,1,59,0,0,ZoneOffset.of("-07:00"))
var offsetAfterAnHour = offsetNow.plusHours(1)
The offsetNow will be,
2020-November-01 01:59:00.000 -07:00
And adding an hour to it will be,
2020-November-01 02:59:00.000 -07:00
you can see that the hour component has become 2 after adding an hour.
The key point is a ZonedDateTime uses ZoneRules to calculate important properties like Daylight savings time so that it can adjust the time zone accordingly.
While the OffsetDateTime will not change the zone offset for anything.

Categories