I wanted to get the LocalDateTime in GMT so wrapped it with ZonedDateTime.
But gmtZoneTime is returned in the following format: 2019-10-29T00:00Z[GMT] While I need it to be: 2019-10-29T00:00:00.000+0000
How should I properly convert localDateTime into the GMT ZonedDateTime?
val currentDate:LocalDate = java.time.LocalDate.now
val localDateTime: LocalDateTime = currentDate.atStartOfDay
val gmtZoneTime: ZonedDateTime = localDateTime.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("GMT"))
You need to format the ZonedDateTime.
First approach would be to use predefined formatter like: java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME, however for GMT it shows 'Z' instead of '+0000' (default behaviour, other offsets are displayed like '+0100' etc.)
So the second one would be to create your own formatter like:
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")
and then use it to format ZonedDateTime like gmtZoneTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ"))
so you get a result like:
2019-10-28T23:00:00+0000
First your code is incorrect. When I ran it in my time zone (Europe/Copenhagen) just now, I got
2019-10-29T23:00Z[GMT]
I don’t think you intended 23:00 in GMT.
Second you may think of GMT or UTC as an offset (of zero from UTC), so it is more correct to use an OffsetDateTIme than a ZonedDateTime for the time. This also eliminates your unwanted suffix. In Java (it’s all I can write):
LocalDate currentDate = LocalDate.now(ZoneOffset.UTC);
OffsetDateTime gmtZoneTime = currentDate.atStartOfDay(ZoneOffset.UTC)
.toOffsetDateTime();
System.out.println(gmtZoneTime);
Output when running just now:
2019-10-30T00:00Z
Edit: You can safely regard UTC and GMT as synonymous since java.time does that (even though strictly speaking they may differ by up to a second).
I assumed you also wanted the date in UTC, so passed this as argument to LocalDate.now(). If you want the date in some other time zone, pass that time zone to LocalDate.now() so that it is clear from the code what you get.
If you want that specific format in your question, pezetem is correct in the other answer that you need to format into a string:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxx");
String formattedGmtTime = gmtZoneTime.format(formatter);
System.out.println(formattedGmtTime);
2019-10-30T00:00:00.000+0000
It seems wordy to me, though. I’d at least leave out the milliseconds since we know they are 0, probably the seconds too. Said without knowing your exact business case.
Link: Difference between UTC and GMT
Related
I have a Date with the actual time of my system (I live in Spain). I need to change it to UTC-1, but it doesn't matter if I write "UTC-1" or "UTC-2", it always gives me the same time less 2 hours, I mean:
My system hour (time_utc): 11:00 13/04/2021
Try UTC-1 (time): 09:00 13/04/21
Try UTC-2 (time): 09:00 13/04/21
I have this code:
Date time_utc = new Date();
DateFormat convertidor = new SimpleDateFormat("yyyy-MM-dd HH:00:00.000");
convertidor.setTimeZone(TimeZone.getTimeZone("UTC-1"));
time = convertidor.format(time_utc);
Why it doesn't work? Can anyone helps me? Thanks a lot!
¡Hola!
You can do that in a pretty short way using java.time (if you are allowed and willing to do so).
There are special classes that represent a moment in time in different time zones of offsets. One of them is an OffsetDateTime, see this example:
public class Main {
public static void main(String[] args) {
// create one of your example date times in UTC
OffsetDateTime utcOdt = OffsetDateTime.of(2021, 4, 13, 11, 0, 0, 0, ZoneOffset.UTC);
// and print it
System.out.println(utcOdt);
/*
* then create another OffsetDateTime
* representing the very same instant in a different offset
*/
OffsetDateTime utcPlusTwoOdt = utcOdt.withOffsetSameInstant(ZoneOffset.ofHours(2));
// and print it
System.out.println(utcPlusTwoOdt);
// do that again to see "the other side" of UTC (minus one hour)
OffsetDateTime utcMinusOneOdt = utcOdt.withOffsetSameInstant(ZoneOffset.ofHours(-1));
// and print that, too.
System.out.println(utcMinusOneOdt);
}
}
It outputs the following three lines:
2021-04-13T11:00Z
2021-04-13T13:00+02:00
2021-04-13T10:00-01:00
As you can see, the time of day is adjusted according to the offset.
The output could be formatted in your desired style if needed (this currently just uses the toString() method of OffsetDateTime).
UPDATE
You can achieve the output formatted as desired by defining the pattern as uuuu-MM-dd HH:mm when using a java.time.format.DateTimeFormatter.
Just add the following lines to the example above:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm");
System.out.println(utcOdt.format(dtf));
System.out.println(utcPlusTwoOdt.format(dtf));
System.out.println(utcMinusOneOdt.format(dtf));
This would then output
2021-04-13 11:00
2021-04-13 13:00
2021-04-13 10:00
And if you really want fix zeros for seconds and millis, then create your DateTimeFormatter like this:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:00.000");
which will cause output like this:
2021-04-13 11:00:00.000
2021-04-13 13:00:00.000
2021-04-13 10:00:00.000
As a supplement to the good answer by deHaar:
As Matt Johnson-Pint already asked, do you need to convert to a different time zone? This would be the most typical. If so, use that time zone, not just a UTC offset of -1. By all probability that time zone has used other offsets in the past and may well do so in the future. So -01:00 isn’t safe. A real time zone ID like Atlantic/Cape_Verde is safer.
You don’t need to go through the current time in your own time zone and convert. java.time can directly give you the current time in another time zone or at a specific UTC offset.
java.time can also truncate a time to whole hours.
So for example:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
ZoneId zone = ZoneId.of("Atlantic/Cape_Verde");
ZonedDateTime nowInCaboVerde = ZonedDateTime.now(zone);
System.out.println(nowInCaboVerde);
System.out.println(nowInCaboVerde.truncatedTo(ChronoUnit.HOURS)
.format(formatter));
Output:
2021-04-14T03:12:28.272010-01:00[Atlantic/Cape_Verde]
2021-04-14 03:00:00.000
PS Cabo Verde/Cape Verde was at offset -02:00 until 1975.
What went wrong in your code?
This is how confusingly the old TimeZone class behaves and one of the reasons why you should never use it: When given a time zone ID that it does not recognize, it returns GMT and pretends all is well. UTC-1 is not a recognized time zone ID. In case it didn’t make sense to refer to a real time zone and you needed the offset -01:00 from UTC, you might have used GMT-1 or GMT-01:00. Yes, TimeZone refers to UTC as GMT even though they are not strictly speaking the same.
I have a Method which parses a String according to Iso8601 and returns a LocalDateTime.
Now I accept possible offsets.
The Problem now is I have to convert the offset to UTC and return it as LocalDateTime.
So far I have tried working with Instant, OffsetDateTime, ZonedDateTime.
I always get the opposite. Instead of +06:00 my result will be shown as -06:00.
return LocalDateTime.ofInstant(Instant.from(OffsetDateTime.parse(date, buildIso8601Formatter())), ZoneOffset.UTC);
This is the solution which works the same as my other tried ones I mentioned above.
I know this is not the common way to do it and I did a lot of research because of that but the current architecture only allows me to do it that way.
EDIT example:
With an implementation like this:
OffsetDateTime offsetDateTime = OffsetDateTime.parse(date, buildIso8601Formatter());
Instant instant = offsetDateTime.toInstant();
return LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
Let's say I get "2020-01-12T08:30+06:00" as input for my method. I HAVE to return LocalDateTime.
As a result I want to have "2020-01-12T14:30" instead my best solution was to get it the opposite way: "2020-01-12T02:30".
The behavior of java.time is correct. The string 2020-01-12T08:30+06:00 means that the datetime part of this string is a datetime local to some region, which exists in an area with an offset of +06:00 from UTC.
Your interpretation is different from the abovementioned case. In your case, you interpret 08:30 as a time in sync with UTC, and then concatenate the timezone offset string for the desired region.
So if you really want to do this – think again.
One way to achieve this, is simply by parsing the datetime as an offset datetime and negate the offset.
I have time 12:00:00 in format HH:mm:ss.
I know that this time comes from server witch is setup with +3 offset.
If i use SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");, it parses time with regard to device, which can be in a different timezone.
Is there another way to parse it with regard to +3 offset except adding it to the original string?
First, should your server rather send the time in UTC? If clients are everywhere, this would seem more time zone neutral and standardized. However, the way to handle it in code wouldn’t be much different. In any case the server offset form UTC could be constant:
private static final ZoneOffset serverOffset = ZoneOffset.ofHours(3);
In real code you will probably want to make it configurable somehow, though. To parse:
OffsetTime serverTime = LocalTime.parse("12:00:00").atOffset(serverOffset);
System.out.println(serverTime);
This prints
12:00+03:00
Since your time format agrees with LocalTime’s default (ISO 8601), we need no explicit formatter. If a representation of the time with offset is all you need, we’re done. If you need to convert to the user’s local time, to do that reliably you need to decide both a time zone and a date:
LocalTime clientTime = serverTime.atDate(LocalDate.of(2018, Month.JANUARY, 25))
.atZoneSameInstant(ZoneId.of("Indian/Maldives"))
.toLocalTime();
System.out.println(clientTime);
With the chosen day and zone we get
14:00
Please substitute your desired time zone and date.
Just hypothetically, if you knew the user’s offset from UTC, you could use just that:
LocalTime clientTime = serverTime.withOffsetSameInstant(ZoneOffset.of("-08:45"))
.toLocalTime();
The example yields 00:15. However, no one knows when the politicians introduce summer time (DST) or other anomalies in the user’s time zone, so I discourage relying on an offset alone.
And yes, I too am using java.time. SimpleDateFormat is not only long outdated, it is also notoriously troublesome, so java.time is what I warmly recommend.
Set the timezone on your SimpleDateFormat object:
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT+03:00"));
I recommend you use the Java 8 date and time API (package java.time) instead of the old API, of which SimpleDateFormat is a part.
Using the Java 8 DateTime API:
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("HH:mm:ss");
LocalTime clientLocalTime = LocalTime
.parse("12:00:00", formatter)
// Create an OffsetTime object set to the server's +3 offset zone
.atOffset(ZoneOffset.ofHours(3))
// Convert the time from the server timezone to the client's local timezone.
// This expects the time value to be from the same day,
// otherwise the local timezone offset may be incorrect.
.withOffsetSameInstant(ZoneId.systemDefault().getRules().getOffset(Instant.now()))
// Drop the timezone info - not necessary
.toLocalTime();
I run the following code:
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
try{
Date date = sdf.parse("03-28-2003 01:00:00");
System.out.print(date.toString());
}
catch(Exception e){
//do something
}
The result of the parsing is this date: 2003-03-28T02:00:00.000+0300
One hour is added.
When I change the year/day/hour to any other valid number, I get the correct time, no extra hour is added. If I only change the minutes or the seconds I still get the added hour.
Can anyone tell me why this happens?
EDIT:
This is related to when daylight saving time is applied in the timezone my program runs on- UTC+02:00.
In this timezone the clock changed on 2003-03-28. that's why an hour was added, as it was suggested by the comments and answer below.
I used the code suggested in the answer to parse my date and the parsing worked! The date is parsed correctly, the extra hour isn't added.
Finding out exactly what your code does is complicated by the fact that not only SimpleDateFormat.parse() may depend on the default time zone of the computer (and does in this case where the pattern does not include time zone), also Date.toString() depends on the default time zone. However, I understand that you want to interpret the date string in UTC, so I will concentrate on getting the parsing right and not worry so much about what’s printed.
Feek is correct in the comment that setting the time zone of the SimpleDateFormat to UTC will get you what you want, for example:
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
With this line added before try I get this output on my computer:
Fri Mar 28 02:00:00 CET 2003
2 am. CET agrees with 1 UTC, so now the parsing is correct.
Allow me to add that if you can use the Java 8 date and time classes, I find the corresponding code somewhat clearer:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd-yyyy HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse("03-28-2003 01:00:00", formatter);
OffsetDateTime utcDateTime = dateTime.atOffset(ZoneOffset.UTC);
System.out.println(utcDateTime);
The point is not that it’s shorter, but that you don’t get easily in doubt about what it does and don’t easily get time zone or DST problems. An added benefit is that the output is also as expected:
2003-03-28T01:00Z
Now it’s evident that the time is correct (Z means Z or Zulu or UTC time zone, it’s got more than one name).
If for some reason you absolutely need an oldfashioned java.util.Date object, that is not difficult:
Date date = Date.from(utcDateTime.toInstant());
This gives the same date as we got from sdf.parse() with UTC time zone.
I have this simple code:
DateTimeFormatter formatter = DateTimeFormat.forPattern("HH:mm yyyy-MM-dd");
DateTime dateTime = formatter.withZone(DateTimeZone.forID("America/New_York")).parseDateTime("08:30 2015-06-01");
DateTime dateTime2 = formatter.withZone(DateTimeZone.forID("America/New_York")).parseDateTime("08:30 2015-12-01");
these are leap times. when I hit toString method, I got something like this:
2015-06-01T08:30:00.000-04:00
2015-12-01T08:30:00.000-05:00
which is correct, we can see UTC time - offset. But when I call getHourOfDay, I got 8 and not 4/3 as expected. What am I doing wrong? Please, share some advices here.
Well, from the Javadoc for DateTimeFormatter#withZone():
Returns a new formatter that will use the specified zone in preference to the zone of the printed object, or default zone on a parse.
So, you told the formatter to use the specific timezone on parsing AND output, and the input you gave it did NOT contain a timezone, so this is the expected result. In essence you said:
Here's a date string without timezone, parse it assuming America/New_York
Convert the date back to String, in the timezone America/New_York
This is what it did.