I'm trying to convert a Brazil local date to UTC format. I have developed my solution but I'm sure that it can be improved. I have been searching for others questions but without success.
My problem is that when I process the Date
object with:
Instant endDateTime = questionDate.toInstant();
I receive a UTC date as "2017-11-16T00:00:00Z"
but this should be Brazil local date (not correct because it has a trailing "Z"
) and when I try to convert to UTC, I receive the same output.
In another hand, if I use ZoneDateTime
class and build the date with LocalDateTime
object I lose the seconds in the output: "2017-11-16T02:00Z"
. This happens when I use:
LocalTime.of(hour, minutes, seconds);
I search into LocalTime
class and I think this is because minutes or seconds are 0
but I'm not sure of it.
OffsetDateTime
class"2017-11-16"
"2017-11-16T02:00:00Z"
private static OffsetDateTime processDate(Date questionDate) {
Instant endDateTime = questionDate.toInstant();
ZoneId zoneId = ZoneId.of(ZONEID);
String [] date = endDateTime.toString().split("T");
LocalDateTime localDateTime = convertLocalTimeToUtc(date);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
ZonedDateTime utcDate = zonedDateTime.withZoneSameInstant(ZoneOffset.UTC);
return utcDate.toOffsetDateTime();
}
private static LocalDateTime convertLocalTimeToUtc(String[] dateFromCountry) {
LocalDate date = processDate(dateFromCountry[0]);
LocalTime time = processTime(dateFromCountry[1]);
return LocalDateTime.of(date, time);
}
private static LocalDate processDate(String dateFromCountry) {
String [] partsOfDate = dateFromCountry.split("-");
int year = Integer.parseInt(partsOfDate[0]);
int month = Integer.parseInt(partsOfDate[1]);
int day = Integer.parseInt(partsOfDate[2]);
return LocalDate.of(year, month, day);
}
private static LocalTime processTime(String dateFromCountry) {
String [] partsOfTime = dateFromCountry.split(":");
int hour = Integer.parseInt(partsOfTime[0]);
int minutes = Integer.parseInt(partsOfTime[1]);
int seconds = Integer.parseInt(partsOfTime[2].substring(0,1));
return LocalTime.of(hour,minutes,seconds);
}
If your input is a java.util.Date
, you can get rid of all the string manipulation:
//simulate your input
Instant input = Instant.parse("2017-11-16T00:00:00Z");
Date d = Date.from(input);
//transformation code starts here
Instant instant = d.toInstant();
ZonedDateTime localInstant = instant.atZone(ZoneOffset.UTC);
ZonedDateTime sameLocalInBrazil = utcInstant.withZoneSameLocal(ZoneId.of("Brazil/East"));
OffsetDateTime sameInstantUtc = sameLocalInBrazil.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC);
This return an OffsetDateTime with value 2017-11-16T02:00Z
as you expect.
Note that an OffsetDateTime has no formatting - so the object does know that its seconds are set to 0 but the default toString
method doesn't print them. If you want to print it with seconds, you can use a formatter:
//Formatting
System.out.println(sameInstantUtc.format(DateTimeFormatter.ISO_INSTANT));
which prints 2017-11-16T02:00:00Z
If your input is a java.sql.Date
, you can use a slightly different strategy:
LocalDate d = sqlDate.toLocalDate();
ZonedDateTime localInstant = d.atStartOfDay(ZoneOffset.UTC);
The rest of the code would be the same.