Формат ZonedDateTime для отображения текущего времени с уже включенным смещением
Я искал этот ответ, но я мог ошибиться относительно того, как реализовать это. У меня есть переменная ZonedDateTime, и в настоящее время, если бы я должен был ее напечатать, она напечатала бы, например, 2017-12-03T10:15:30+01:00. есть ли способ напечатать время с уже добавленным или вычтенным смещением? например, я хотел бы видеть с примером выше 16:30. Спасибо за помощь!
1 ответ
tl;dr
yourZonedDateTime.atZone(ZoneOffset.UTC).withZoneSameInstant(ZoneId.systemDefault())
Или в моем случае:
serverSeconds.toLocalDateTime(ZonedDateTime.now().offset) // extension below
fun Long.toLocalDateTime(zoneOffset: ZoneOffset = ZoneOffset.UTC): LocalDateTime {
return LocalDateTime.ofEpochSecond(this / 1000L, 0, zoneOffset)
}
История
Я наткнулся на этот вопрос, когда пытался правильно отформатировать дату и время, полученные с сервера. Я проделал эти простые шаги:
- Сервер дал мне это:
1597752329121
, который представляет собой дату и время в секундах. - Преобразование его в LocalDateTime дало мне следующее:
2020-08-18T12:05:29
. - Преобразование его в ZonedDateTime дало мне следующее:
2020-08-18T12:05:29+03:00[Europe/Kiev]
это было идеально, так как мне нужно было отобразить это как 15:05, 18 August 2020
, просто правда? Но форматирование в любом виде насмешливо давало мне12:05, 18 August 2020
. Так глуп. Я начал искать, что делаю неправильно, и находил только "умные" комментарии вроде "Время уже в заданном часовом поясе". и вы должны только это получить.
Но как это может быть, если ZonedDateTime каким-то образом дает 12:05 вместо 15:05?!
В любом случае, я наконец нашел этот ответ ( /questions/38732397/zoneddatetime-v-utc-so-smescheniem/38732414#38732414), который на самом деле не решал мою проблему как есть, но дал некоторые мысли о том, как ее исправить. Итак, наконец, я попробовал это:
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)
}
И наконец форматирование zoned
дал мне необходимое 15:05, 18 August 2020
. Я улучшил его до кода, который вы можете видеть выше в tl;dr.
Взгляните на это:
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 );
}
Есть небольшие изменения, чтобы сделать это в соответствии с вашими потребностями. Вы должны быть в состоянии сделать это без особых усилий. Затем, получив объект Date, вы добавляете желаемое смещение:
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.
Теперь, чтобы напечатать это:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String myDateString = df.format(myDateObject);
//Now just use your myDateString wherever you want.
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);
}
}
Выход:
2017-12-03T10:15:30+01:00
2017-12-03T09:15:30Z[Etc/UTC]
2017-12-03T09:15:30Z
2017-12-03T09:15:30
Пробел в вашем понимании:
В +01:00
в строке даты и времени, 2017-12-03T10:15:30+01:00
означает, что дата и время в строке уже были настроены путем добавления +01:00
час до даты и времени в UTC
. Это означает, что если вы хотите удалить+01:00
от него, +01:00
час нужно вычесть из 2017-12-03T10:15:30
т.е. он станет 2017-12-03T09:15:30
представляющий дату и время в UTC
.