I been looking for this answer but I could be mistaken as to how to implement this. I have a ZonedDateTime variable and currently if I were to print it it would print for example 2017-12-03T10:15:30+01:00. is there any way to print the time with the off set already added or subtracted? for example I would like to see with the example above 16:30. Thank you for your help!

- 71,965
- 6
- 74
- 110

- 1,385
- 1
- 22
- 43
-
2If I understand correctly, what you want to do just amounts to displaying the ZonedDateTime instance in UTC. You can set time zone on your DateTimeFormatter, so just do that. – korolar Mar 24 '17 at 22:39
-
1`2017-12-03T10:15:30+01:00` is the time `10:15:30` in the given time zone, or `09:15:30` in the UTC time zone (not `16:30`). The time is already in the given time zone. If you want to remove the offset information, call [`toLocalDateTime()`](https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html#toLocalDateTime--) to get `2017-12-03T10:15:30`. Down-voting, as this question is based on a misunderstanding of [ISO date formats](https://en.wikipedia.org/wiki/ISO_8601). – Andreas Mar 24 '17 at 22:52
-
thank you for your help! I solved my problem! – paul590 Mar 24 '17 at 22:56
3 Answers
Take a look at this:
public Date parseDateTime(String input) throws java.text.ParseException {
//NOTE: SimpleDateFormat uses GMT[-+]hh:mm for the TZ which breaks
//things a bit. Before we go on we have to repair this.
SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssz" );
//this is zero time so we need to add that TZ indicator for
if ( input.endsWith( "Z" ) ) {
input = input.substring( 0, input.length() - 1) + "GMT-00:00";
} else {
int inset = 6;
String s0 = input.substring( 0, input.length() - inset );
String s1 = input.substring( input.length() - inset, input.length() );
input = s0 + "GMT" + s1;
}
return df.parse( input );
}
There are little changes to make so it fits your need. You should be able to do it with little effort. Then after you have the Date object you add the offset you want:
int myNumHours = 4; //Any number of hours you want
myDateObject.add(Calendar.HOUR,myNumHours);
//Adds myNumHours to the Hour slot and processes all carrys if needed be.
Now to print it:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String myDateString = df.format(myDateObject);
//Now just use your myDateString wherever you want.

- 301
- 1
- 3
- 7
tl;dr
yourZonedDateTime.atZone(ZoneOffset.UTC).withZoneSameInstant(ZoneId.systemDefault())
Or in my case:
serverSeconds.toLocalDateTime(ZonedDateTime.now().offset) // extension below
fun Long.toLocalDateTime(zoneOffset: ZoneOffset = ZoneOffset.UTC): LocalDateTime {
return LocalDateTime.ofEpochSecond(this / 1000L, 0, zoneOffset)
}
History
I stumbled on this question when I was trying to properly format the date-time received from the server. I did these simple steps:
- The server gave me this:
1597752329121
, which is a date-time in seconds. - Converting it to LocalDateTime gave me this:
2020-08-18T12:05:29
. - Converting it to ZonedDateTime gave me this:
2020-08-18T12:05:29+03:00[Europe/Kiev]
this was perfect, as I needed to display it like 15:05, 18 August 2020
, simple right? But formatting it in any way was mockingly giving me 12:05, 18 August 2020
. So stupid. I started searching for what I'm doing wrong and was finding only "smart" comments like "The time is already in the given time zone." and you should only get it.
But how can it be if the ZonedDateTime any way gives you 12:05 instead of 15:05?!
Anyway, I finally found this answer (https://stackoverflow.com/a/35689566/3569545) which, actually, wasn't solving my problem as it is, but gave some thoughts on how to fix it. So finally I've tried this:
val localDate = serverSeconds.toLocalDateTime() //an extension, see below
val zonedUTC = localDate.atZone(ZoneOffset.UTC)
val zoned = zonedUTC.withZoneSameInstant(ZoneId.systemDefault())
fun Long.toLocalDateTime(): LocalDateTime {
return LocalDateTime.ofEpochSecond(this / 1000L, 0, ZoneOffset.UTC)
}
And finally formatting zoned
gave me required 15:05, 18 August 2020
.
I improved it into code you can see above in tl;dr.

- 5,073
- 3
- 31
- 49
ZonedDateTime#withZoneSameInstant
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String dateTimeStr = "2017-12-03T10:15:30+01:00";
ZonedDateTime zdtGiven = ZonedDateTime.parse(dateTimeStr);
System.out.println(zdtGiven);
// Date-time adjusted with Zone-Offset (i.e. date-time at UTC)
ZonedDateTime zdtAtUTC = zdtGiven.withZoneSameInstant(ZoneId.of("Etc/UTC"));
System.out.println(zdtAtUTC);
// Alternatively,
OffsetDateTime odtAtUTC = zdtGiven.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC);
System.out.println(odtAtUTC);
// Custom format
String formattedDateTimeStr = zdtAtUTC.format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss"));
System.out.println(formattedDateTimeStr);
}
}
Output:
2017-12-03T10:15:30+01:00
2017-12-03T09:15:30Z[Etc/UTC]
2017-12-03T09:15:30Z
2017-12-03T09:15:30
The gap in your understanding:
The +01:00
in the date-time string, 2017-12-03T10:15:30+01:00
means that the date & time in the string has been already adjusted by adding +01:00
hour to the date & time at UTC
. It means if you want to remove the +01:00
from it, +01:00
hour needs to be subtracted from 2017-12-03T10:15:30
i.e. it will become 2017-12-03T09:15:30
representing the date & time at UTC
.

- 71,965
- 6
- 74
- 110