How to convert UTC Time to LocalDateTime by using ZonedDateTime - java

I have found many way to convert localDateTime to LocalDateTime in UTC.
But I could not find any way to convert UTC time at localDateTime by using ZonedDateTime. Do you know a way to convert it ?
This is what I used to convert it to UTC. I need a vice versa method .
ZonedDateTime zonedDate = ZonedDateTime.of(localDateTime,
ZoneId.systemDefault());
localDateTime.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC)

Don’t use LocalDateTime for a date and time for which you know the UTC offset or time zone. For a date and time in your time zone or another known time zone, use ZonedDateTime. For a date and time for which you know an offset (and here UTC counts as an offset) use OFfsetDateTime.
Why? LocalDateTime (confusing class name) is a date and time without time zone or offset. Not storing the known offset or time zone is throwing away vital data and is an error waiting to happen.
One exception: For a date and time in a known time zone in a further future, do store a LocalDateTime and make sure to store the time zone as a separate ZoneId object. This will allow the offset and/or summer time rules (DST rules) for the time zone to be changed between now and that time (which happens more often than we like to think). Only when time draws near and our Java installation may have been updated with the latest zone rules, can we correctly combine the date-time and the zone and obtain the correct moment in time.
Convert UTC date and time to your time zone
OffsetDateTime utcDateTime = OffsetDateTime.of(2019, 9, 10, 12, 0, 0, 0, ZoneOffset.UTC);
System.out.println("UTC date and time: " + utcDateTime);
ZonedDateTime myDateTime = utcDateTime.atZoneSameInstant(ZoneId.systemDefault());
System.out.println("Date and time in the default time zone: " + myDateTime);
After I set my time zone to Asia/Istanbul, this snippet output:
UTC date and time: 2019-09-10T12:00Z
Date and time in the default time zone: 2019-09-10T15:00+03:00[Asia/Istanbul]
Convert from your time zone to UTC
For the opposite conversion I prefer:
OffsetDateTime convertedBackToUtc = myDateTime.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC);
System.out.println("UTC date and time again: " + convertedBackToUtc);
UTC date and time again: 2019-09-10T12:00Z
Still not using any LocalDateTime.

Related

ZonedDateTime with timezone added to print format

I'm using https://github.com/JakeWharton/ThreeTenABP in my project.
I have org.threeten.bp
ZonedDateTime: 2019-07-25T14:30:57+05:30[Asia/Calcutta]
How can I get this printed with addition of the timezone hours? ie the result should have 2019-07-25T20:00:57
Get the offset in the form of seconds from ZonedDateTime
ZonedDateTime time = ZonedDateTime.parse("2019-07-25T14:30:57+05:30");
long seconds = time.getOffset().getTotalSeconds();
Now get the LocalDateTime part from ZonedDateTime
LocalDateTime local = time.toLocalDateTime().plusSeconds(seconds); //2019-07-25T20:00:57
toLocalDateTime
Gets the LocalDateTime part of this date-time.
If you want to get the local date time in UTC use toInstant()
This returns an Instant representing the same point on the time-line as this date-time. The calculation combines the local date-time and offset.
Instant i = time.toInstant(); //2019-07-25T09:00:57Z
You misunderstood. The offset of +05:30 in your string means that 5 hours 30 minutes have already been added to the time compared to UTC. So adding them once more will not make any sense.
If you want to compensate for the offset, simply convert your date-time to UTC. For example:
ZonedDateTime zdt = ZonedDateTime.parse("2019-07-25T14:30:57+05:30[Asia/Calcutta]");
OffsetDateTime utcDateTime = zdt.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC);
System.out.println(utcDateTime);
Output:
2019-07-25T09:00:57Z

Convert datetime string in one timezone to another using offset

I have a datetime string "2018-01-15 01:16:00" which is in EST timezone. I want to convert this into another timezone dynamically using the UTC offset. My javascript code passes this UTC offset as a parameter and the servlet has to convert/format this datetime string to the timezone identified by the provided offset.
I have tried many approaches including the one documented in the oracle tutorials but unable to arrive at a solution.
Below is my code that I am trying, any help is greatly appreciated.
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static final String DEFAULT_TIME_ZONE = ZoneId.SHORT_IDS.get("EST");
public static void main(String[] args) throws Exception {
String dateTime = "2018-01-15 02:35:00";
//parse the datetime using LocalDateTime
LocalDateTime defaultDateTime = LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(DATE_FORMAT));
//get the datetime in default timezone
ZoneId defaultZoneId = ZoneId.of(DEFAULT_TIME_ZONE);
ZonedDateTime defaultZoneDateTime = defaultDateTime.atZone(defaultZoneId);
System.out.println("EST time: "+defaultZoneDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT)));
ZonedDateTime utcZonedDateTime = defaultZoneDateTime.withZoneSameInstant(ZoneId.of("UTC"));
String utcTime = defaultZoneDateTime.withZoneSameInstant(ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern(DATE_FORMAT));
System.out.println("UTC : "+utcTime);
//IST timezone
ZoneOffset offset = ZoneOffset.of("+05:30");
OffsetDateTime offsetDate = OffsetDateTime.of(utcZonedDateTime.toLocalDateTime(), offset);
String targetTimeZone = offsetDate.format(DateTimeFormatter.ofPattern(DATE_FORMAT));
System.out.printf("target time : "+targetTimeZone);
}
OUTPUT
EST time: 2018-01-15 02:35:00
UTC : 2018-01-15 07:37:00
target time : 2018-01-15 07:37:00
Expected target time : 2018-01-15 13:05:00
The immediate problem is this line:
OffsetDateTime offsetDate = OffsetDateTime.of(utcZonedDateTime.toLocalDateTime(), offset);
That's saying you want the same local date/time, but with the specified offset. That changes which instant in time is being represented.
Instead, you really want to represent the same instant in time, but at a particular offset. So the shortest fix is:
OffsetDateTime offsetDate = utcZonedDateTime.toInstant().atOffset(offset);
However, there are a number of other aspects which could do with changing:
Prefer ZoneOffset.UTC to ZoneId.of("UTC")
Using EST as a time zone is confusing - it's not clear whether you expect it to mean "Eastern Time" (changing between EST and EDT) or pure standard time of UTC-5. Assuming you actually mean "Eastern Time" it would be better to use America/New_York as a zone ID.
It's unclear what you want to happen if the input string represents a skipped or ambiguous value in Eastern time. These happen around DST transitions.
Next, you don't need to convert the ZonedDateTime in Eastern time into a ZonedDateTime in UTC at all. Either convert it directly to an instant:
OffsetDateTime target = defaultZoneDateTime.toInstant().at(offset);
Or create a ZonedDateTime for the target instead:
ZonedDateTime target = defaultZoneDateTime.withZoneSameInstant(offset);
Given that an offset isn't really a time zone, I'd probably go with the first of these.
You're using
OffsetDateTime.of(utcZonedDateTime.toLocalDateTime(), offset)
to create your target. You're thus constructing an OffsetDateTime in the target offset, having a LocalDateTime equal to the LocalDateTime in the UTC zone.
What you want is the exact same transformation as the one you're using to go from the EST time to UTC: keep the same instant, but go to a different timezone:
defaultZoneDateTime.withZoneSameInstant(offset);
or, if you really want an OffsetDateTime and not a ZonedDateTime:
OffsetDateTime.ofInstant(defaultZoneDateTime.toInstant(), offset);

Date from ZonedDateTime instant not in utc

I am creating date like this:
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
Date.from(now.toInstant());
I need Date object have current time in utc, but when I print date it gives me my local time and not utc time.
I also tried with:
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
Date date = Date.from(now.toInstant());
But when I print Date again time is not in utc. Am I doing something wrong when creating Date object. Why above 2 approaches not give me Date that have current time in utc.
Two points:
Avoid the long outdated Date class, in particular when you are already using classes from java.time, the modern Java date and time API.
A Date object hasn’t got and cannot have a time zone in it.
To print offset or time zone
If you need your offset, you need to hold on to your OffsetDateTime (or ZonedDateTime) object:
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println(now);
On my computer this just printed
2017-11-21T11:53:11.519Z
The Z in the end indicates Zulu time zone, another name for UTC (you may also informally think of it as Zero offset from UTC).
If you would like a more human-readable format, you are right, use a formatter:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
System.out.println(now.format(formatter));
Depending on your locale and the time, this prints something like
Tuesday, November 21, 2017 11:53:11 AM Z
Again the Z means Zulu time zone, UTC.
Date is not going to help you
A Date is just a point in time. So is the Instant that you use for initializing the date. None of them has got a time zone or offset. The difference here is their toString methods: The Instant is always printed in UTC, the Date usually (always?) in the JVM’s default time zone. The latter confuses many into thinking the Date has a time zone when it hasn’t. See All about java.util.Date.
As I have demonstrated, a formatter may put a time zone or offset into a string when formatting the date-time. This does not in any way modify the date-time object, whether OffsetDateTime, ZonedDateTime, Instant or Date. The long outdated DateFormat class may do the same when formatting a Date. It cannot and will not set a time zone in the Date object since (and I repeat) a Date object cannot have a time zone in it.
Long story short, you have no need for the outdated Date class that I can see.

JSR 310 :: System.currentTimeMillis() vs Instant.toEpochMilli() :: TimeZone

Could you please shed some light on how to obtain correct epoch time in milliseconds for a default system timezone and given timezone.
Given
1. TimeZone: GMT+3
2. The following code snippet:
import java.time.*;
public class Main {
public static void main(String[] args) {
System.out.println(LocalDateTime
.now()
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli()
);
System.out.println(LocalDateTime
.now()
.atZone(ZoneOffset.of("+3"))
.toInstant()
.toEpochMilli()
);
System.out.println(System.currentTimeMillis());
}
}
3. Output:
1444158955508
1444148155508
1444148155508
4. JavaDoc for System.currentTimeMillis() that tells that returned value will be the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
So, why
the output of the LocalDateTime at GMT+3 is the same as of System.currentTimeMillis(), although the docs for the System.currentTimeMillis() mention UTC?
the output of the LocalDateTime at UTC differs from System.currentTimeMillis(), although the docs for the System.currentTimeMillis() mention UTC?
Both System.currentTimeMillis() and Instant.toEpochMilli() return the number of milliseconds since the Unix epoch. That isn't "in" any particular time zone, although the Unix epoch is normally expressed as "midnight on January 1st 1970, UTC". But an instant is just an instant in time, and is the same whichever time zone you're in - but it will reflect a different local time.
The output of LocalDateTime.atZone(UTC) differs because you're saying "Take the local date and time, and convert it to an instant as if it were in the UTC time zone" - even though when you created that LocalDateTime you did so implicitly in the UTC+3 time zone... that's why it's "wrong".
LocalDateTime.now() takes the local date and time in the system default time zone. So if your time zone is UTC+3, the current instant in time is 2015-10-06T16:57:00Z, then LocalDateTime.now() will return .2015-10-06T19:57:00. Let's call that localNow...
So localNow.atZone(ZoneOffset.of("+3")) will return a ZonedDateTime representing 2015-10-06T19:57:00+03 - in other words, the same local date/time, but "knowing" that it's 3 hours ahead of UTC... so toInstant() will return an Instant representing 2015-10-06T16:57:00Z. Great - we still have the current date/time.
But localNow.atZone(ZoneOffset.UTC) will return a ZonedDateTime representing 2015-10-06T19:57:00Z - in other words, the same local date/time, but "thinking" that it's already in UTC... so toInstant() will return an Instant representing 2015-10-06T19:57:00Z.. which isn't the current time at all (it's in three hours).
Short version:
There is no way to compute LocalDateTime -> Instant, you need to specify a timezone.
With a timezone you get a ZonedDateTime and can compute ZonedDateTime -> Instant
Instant == System.currentTimeMillis() if the timezone of the ZonedDateTime equals the system default time zone.
Long version:
LocalDateTime is the time on your clock(plus date information). Which is not enough if you don't tell us which timezone your are in. 13:00 o'clock in Tokyo is not the same Instant as 13:00 o'clock in Paris.
Once you add a timezone to your LocalDateTime you get a ZonedDateTime and we can know in which Instant of time you actually are. E.g. are you 13:00 o'clock in Tokyo or in Paris?
To get the correct Instant the timezone of the ZonedDateTime needs to be correct. If it is 13:00 o'clock in Tokyo but you claim that you are 13:00 o'clock in Paris you will get a wrong Instant.
LocalDateTime:
It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
ZonedDateTime:
This class handles conversion from the local time-line of LocalDateTime to the instant time-line of Instant. The difference between the two time-lines is the offset from UTC/Greenwich, represented by a ZoneOffset.
To get an Instant you need to convert LocalDateTime to ZonedDateTime first. If you did this correctly(by stating the correct timezone) your Instant will agree with System.currentTimeMillis().
System.currentTimeMillis():
the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
the output of the LocalDateTime at GMT+3 is the same as of System.currentTimeMillis(), although the docs for the System.currentTimeMillis() mention UTC?
If your timezone is GMT+3 then ZonedDateTime.toInstant() will give you the correct Instant and therefore agree with System.currentTimeMillis()
the output of the LocalDateTime at UTC differs from System.currentTimeMillis(), although the docs for the System.currentTimeMillis() mention UTC?
If your timezone is not UTC then ZonedDateTime.toInstant() will give you an incorrect Instant.
System.out.println("Output 1 : " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("Output 2 : " + System.currentTimeMillis());
Output 1 : 1576047664910
Output 2 : 1576047664911

How to get date in a specific timezone?

greetings all
i am using the following method to get the current time in GMT timezone
public static Timestamp getCurrentTimeGMT() {
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
long time = c.getTimeInMillis();
long offset = TimeZone.getDefault().getOffset(time);
return new Timestamp(time - offset);
}
but when i try to use the same method with minor changes to get the current time in GMT+3
it gives me the same result of GMT ? i don't know why:
public static Timestamp getCurrentTimeGMT3() {
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT+3"));
long time = c.getTimeInMillis();
long offset = TimeZone.getDefault().getOffset(time);
return new Timestamp(time - offset);
}
any ideas why the above code doesn't work properly, and how to do such a method ?
Timestamp extends Date - it doesn't have a time zone, conceptually. It just represents an instant in time.
If you want to display it in a particular calendar with a particular time zone, that's a formatting issue. Create the appropriate calendar with the relevant time zone, and set the timestamp within it accordingly.
(As per normal, I'd like to recommend that you use Joda Time instead of the built-in API where possible. It's much cleaner.)
Why do you subtract the offset from the time in the last line? That is basically resetting your time back to GMT. You retrieve GMT+3 then you subtract 3 hours from that.
What Jon said. A Timestamp does not have a time zone, it's always UTC, and really shouldn't be abused for representing local time. If you really need objects to represent local time, Joda Time has a class for that.
And you should be aware that "GMT+3" is not a real valid time zone. A time zone has not just a base offset, but also a daylight savings time offset, which can be different for time zones with the same base offset, and can even change for the same time zone due to legislation. A real time zone ID is "Europe/Berlin" or "Australia/Darwin".
java.time
In March 2014, the modern Date-Time API supplanted the legacy date-time API and since then it is strongly recommended to switch to java.time, the modern date-time API.
Solution using java.time, the modern Date-Time API: The first important thing to understand is the difference between a timezone and a timezone offset.
A timezone is identified by an ID, typically in the form of a Region/City e.g. Europe/London. Here you can check a list of tz database time zones. The java.time API provides with ZonedDateTime to represent a date-time with timezone.
A timezone offset tells us the amount of time by which the time of a place is offset from the UTC e.g. 2011-12-03T10:15:30+01:00 which tells us that this date-time is offset by 01:00 hours from UTC i.e. we need to subtract 01:00 hours to get the equivalent date-time at UTC. The java.time API provides with OffsetDateTime to represent a date-time with time zone offset.
Some time zones observe DST i.e. America/New_York observes an offset of -05:00 hours in the winter while -04:00 hours in the summer.Here you can check an illustration.
A ZonedDateTime automatically reflects the applicable offset while we create an OffsetDateTime with a fixed offset value. Thus, GMT and GMT+3 mentioned in your question are not time zones, they represent time zone offset. A better and more modern way to write it is Z and +03:00 respectively.
Demo:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
class Main {
public static void main(String[] args) {
ZoneId zone = ZoneId.of("America/New_York");
// Current date-time in America/New_York
System.out.println(ZonedDateTime.now(zone));
// A sample winter date-time in America/New_York
System.out.println(ZonedDateTime.of(LocalDate.of(2023, 01, 14), LocalTime.of(10, 20, 30), zone));
// A sample summer date-time in America/New_York
System.out.println(ZonedDateTime.of(LocalDate.of(2023, 06, 14), LocalTime.of(10, 20, 30), zone));
// Current OffsetDateTime with an offset of 00:00 hours (UTC time)
System.out.println(OffsetDateTime.now(ZoneOffset.UTC));
// Current OffsetDateTime with an offset of 05:30 hours
OffsetDateTime odt = OffsetDateTime.now(ZoneOffset.of("+05:30"));
System.out.println(odt);
// The same OffsetDateTime converted to UTC time (will be 05:30 less)
System.out.println(odt.withOffsetSameInstant(ZoneOffset.UTC));
}
}
Output from a sample run:
2023-01-14T12:40:04.348474-05:00[America/New_York]
2023-01-14T10:20:30-05:00[America/New_York]
2023-06-14T10:20:30-04:00[America/New_York]
2023-01-14T17:40:04.352982Z
2023-01-14T23:10:04.353969+05:30
2023-01-14T17:40:04.353969Z
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
Sample Code to get Time in Different Time Zone
public class GetZoneDateTime {
public static void main(String[] args) throws Exception {
String reqTzId = "Asia/Singapore";
LocalDateTime now = LocalDateTime.now();
System.out.println("Local Now: " + now + " TimeZone: " + TimeZone.getDefault());
ZoneId zoneId = ZoneId.of(reqTzId);
System.out.println("Req TimeZone : " + zoneId);
LocalDateTime localNow = LocalDateTime.now(zoneId);
System.out.println("tzLocalDateTime: " + localNow);
ZonedDateTime zoneNow = ZonedDateTime.now(zoneId);
System.out.println("tzZonedDateTime: " + zoneNow);
}
}
c.getTimeInMillis() returns the number of milliseconds since January 1st, 1970 0:00 UTC and will return the same value, no matter which time zone is used in the Calendar instance.
If you create a Calendar with a time zone and need access to the time fields, you should access these directly:
int h = c.get(Calendar.HOUR_OF_DAY);
int m = c.get(Calendar.MINUTE);
int s = c.get(Calendar.SECOND);
Use the Timezone static method.
TimeZone default = TimeZone.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone("GMT+3"));
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(System.currentTimeMillis()));
Date date = cal.getTime(); // converted date time
System.out.println(date.toString());
// Set Back to System Default
TimeZone.setDefault(default);

Categories

Resources