Формат ZonedDateTime для отображения текущего времени с уже включенным смещением

Я искал этот ответ, но я мог ошибиться в том, как это реализовать. У меня есть переменная ZonedDateTime, и в настоящее время, если бы я ее распечатал, она напечатала бы, например, 2017-12-03T10:15:30+01:00. есть ли способ распечатать время с уже добавленным или вычтенным смещением? например я хотел бы видеть с примером выше 16:30. Спасибо за помощь!


person paul590    schedule 24.03.2017    source источник
comment
Если я правильно понимаю, то, что вы хотите сделать, сводится к отображению экземпляра ZonedDateTime в формате UTC. Вы можете установить часовой пояс в своем DateTimeFormatter, так что просто сделайте это.   -  person korolar    schedule 25.03.2017
comment
2017-12-03T10:15:30+01:00 — это время 10:15:30 в заданном часовом поясе или 09:15:30 в часовом поясе UTC (не 16:30). Время уже находится в заданном часовом поясе. Если вы хотите удалить информацию о смещении, вызовите toLocalDateTime() чтобы получить 2017-12-03T10:15:30. Голосование против, поскольку этот вопрос основан на неправильном понимании форматов даты ISO.   -  person Andreas    schedule 25.03.2017
comment
спасибо за помощь! Я решил свою проблему!   -  person paul590    schedule 25.03.2017


Ответы (3)


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.

person Arvind Kumar Avinash    schedule 19.08.2020

Взгляните на это:

    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.
person Andre Alexandre    schedule 24.03.2017

тл;др

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?!

Во всяком случае, я наконец нашел этот ответ (https://stackoverflow.com/a/35689566/3569545), который, на самом деле, не решал мою проблему как есть, но дал некоторые мысли о том, как ее исправить. Итак, наконец, я попробовал это:

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.

person Demigod    schedule 18.08.2020
comment
Благодарю за ваш ответ! - person paul590; 20.08.2020