Местное время в GMT и наоборот. Преобразование даты и времени не работает. - PullRequest
0 голосов
/ 13 июля 2020

Я пытался преобразовать время даты ввода в GMT + 0, а позже преобразовать обратно в местное время. Хотя локальное преобразование в GMT + 0 работает, более позднее преобразование-gmt в локальное не удается!

Calendar cal=Calendar.getInstance();
cal.setTime(new Date());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
System.out.println("my inputTime:"+ sdf.format(cal.getTime()));
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("gmt+0 converted time:"+ sdf.format(cal.getTime()));

//now i want to get my local time from this converted gmt+0 standard time
String standdardTimeStr=sdf.format(cal.getTime());
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
Date date=sdf2.parse(standdardTimeStr);
Calendar cal2= Calendar.getInstance();
cal2.setTime(date);
System.out.println("standard input time:"+ sdf2.format(cal2.getTime()));
sdf2.setTimeZone(TimeZone.getTimeZone("GMT+6")); //or Asia/Dhaka

System.out.println("gmt+6 convertedtime:"+ sdf2.format(cal2.getTime()));

И это мой результат:

my inputTime:2020-07-13T15:02:16.849
gmt+0 converted time:2020-07-13T09:02:16.849
standard input time:2020-07-13T09:02:16.849 //taking upper line as input-gmt+0
gmt+6 convertedtime:2020-07-13T09:02:16.849 //this date was supposed to be same as the first date

Пожалуйста, укажите, что я делаю не так в кодировке или концептуально?

Ответы [ 3 ]

1 голос
/ 13 июля 2020

На тот случай, если вам нужно решение с современным API, см. Этот прокомментированный пример:

public static void main(String[] args) {
    // provide some fix example datetime String
    String dateTime = "2020-05-08T13:57:06.345";
    
    // create the two time zones needed before
    ZoneId utc = ZoneId.of("UTC");  // UTC = GMT (+0)
    ZoneId local = ZoneId.systemDefault();  // the zone of your JVM / system
    
    /*
     * then parse the String which doesn't contain information about a zone
     * to an object that just knows date and time
     */
    LocalDateTime ldt = LocalDateTime.parse(dateTime);
    // and use that to create a zone-aware object with the same date and time
    ZonedDateTime utcZdt = ZonedDateTime.of(ldt, utc);
    // finally adjust its date and time by changing the zone
    ZonedDateTime localZdt = utcZdt.withZoneSameInstant(local);
    
    // then print both results
    System.out.println(utcZdt + "\t==\t" + localZdt);
    
    // and maybe try to use a different output format by defining a custom formatter
    DateTimeFormatter gmtStyleDtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSO");
    System.out.println(utcZdt.format(gmtStyleDtf)
                        + "\t==\t" + localZdt.format(gmtStyleDtf));
}

, который выводит следующие строки в моей системе (может отличаться от вашей из-за разных часовых поясов):

2020-05-08T13:57:06.345Z[UTC]   ==  2020-05-08T15:57:06.345+02:00[Europe/Berlin]
2020-05-08T13:57:06.345GMT      ==  2020-05-08T15:57:06.345GMT+2

EDIT:

Вот возможность сделать то же самое, но просто работать со смещениями вместо часовых поясов:

public static void main(String[] args) {
    // provide some fix example datetime String
    String dateTime = "2020-05-08T13:57:06.345";
    
    // create the two offsets needed
    ZoneOffset gmt = ZoneOffset.ofHours(0);  // UTC = GMT (+0)
    ZoneOffset gmtPlusSix = ZoneOffset.ofHours(6);  // Asia/Dhaka ;-)
    
    /*
     * then parse the String which doesn't contain information about a zone
     * to an object that just knows date and time
     * NOTE: this just parses the String and does nothing else
     */
    LocalDateTime justDateAndTime = LocalDateTime.parse(dateTime);
    // and use that to create an offset-aware object with the same date and time
    OffsetDateTime dateAndTimeAndGmtPlusSix = OffsetDateTime.of(justDateAndTime, gmtPlusSix);
    // finally adjust its date and time by changing the offset keeping the instant
    OffsetDateTime dateAndTimeInGmt = dateAndTimeAndGmtPlusSix.withOffsetSameInstant(gmt);
    
    // then print both results
    System.out.println(dateAndTimeAndGmtPlusSix + "\t==\t" + dateAndTimeInGmt);
    
    // and maybe try to use a different output format by defining a custom formatter
    DateTimeFormatter gmtStyleDtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSO");
    System.out.println(dateAndTimeAndGmtPlusSix.format(gmtStyleDtf) 
                        + "\t==\t" + dateAndTimeInGmt.format(gmtStyleDtf));
}

Вывод:

2020-05-08T13:57:06.345+06:00   ==  2020-05-08T07:57:06.345Z
2020-05-08T13:57:06.345GMT+6    ==  2020-05-08T07:57:06.345GMT

Обратите внимание, что Z эквивалентно смещению GMT / UT C + 0.

Таким образом, вы можете создать такой метод, как

public static String convert(String datetime, int fromOffset, int toOffset) {
    ZoneOffset fromZoneOffset = ZoneOffset.ofHours(fromOffset);
    ZoneOffset toZoneOffset = ZoneOffset.ofHours(toOffset);
    OffsetDateTime odt = LocalDateTime.parse(datetime).atOffset(fromZoneOffset);
    return odt.withOffsetSameInstant(toZoneOffset)
                .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}

возможно обрабатывать недопустимые значения аргументов, использовать его вот так

public static void main(String[] args) {
    String dateTime = "2020-05-08T13:57:06.345";
    System.out.println(convert(dateTime, 6, 0)));
}

и получать результат

2020-05-08T07:57:06.345
1 голос
/ 13 июля 2020

Вам не хватает строкового представления времени, чтобы преобразовать его обратно в локальное. Приведенный ниже модифицированный код даст представление о том же:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class TimeZoneExample {
    public static void main(String[] args) throws ParseException {
        Calendar cal = Calendar.getInstance();
        final Date currentTime = cal.getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
        String timeInCurrentTimeZone = sdf.format(currentTime);
        System.out.println("Time in current time zone: " + timeInCurrentTimeZone);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String timeInGMT = sdf.format(currentTime);
        System.out.println("Time in GMT: " + timeInGMT);
        // Now, take this time in GMT and parse the string -- this is the key, we want to work with the time which got
        // displayed not the internal representation and that's why we will get the time from string!
        Date parsedTime = sdf.parse(timeInGMT);
        String parsedString = sdf.format(parsedTime);
        System.out.println("(GMT) Time in Parsed String: " + parsedString); // here it will show up it in GMT as sdf is still set to GMT
        // Change the zone for sdf
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+6")); // or Asia/Dhaka
        System.out.println("(Local) Time in Parsed String: " + sdf.format(parsedTime)); // here it you will see the zone difference
    }
}

Примечание : вы получите лучшее изображение, если возьмете фиксированное время вместо текущего.

1 голос
/ 13 июля 2020

Я не знаю, почему вы используете объект Calendar. Javado c of Calendar.getInstance() говорит:

Возвращаемый календарь основан на текущем времени в часовом поясе по умолчанию

Это означает, что вызов cal.setTime(new Date()); полностью избыточен.

Но, что еще хуже, следующие три все одинаковы:

// The very long way
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
Date date = cal.getTime();

// The long way
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();

// The simple way
Date date = new Date();

Объект Date всегда хранит дату / время в UT C (GMT + 0). Часовые пояса применяются при синтаксическом анализе строки и при форматировании строки.

Анализ строки, в которой не указано смещение часового пояса, будет анализироваться в часовом поясе SimpleDateFormat, т.е. часовой пояс по умолчанию (также известный как «местный» часовой пояс), если не указано иное, и проанализированное значение преобразуется в UT C для хранения в объекте Date.

Форматирование значения Date в строка всегда будет использовать часовой пояс SimpleDateFormat.

Очистите код в вопросе, чтобы не использовать Calendar, поскольку это просто запутывает проблему, и комментируя это, чтобы показать, что происходит, ответит на ваш вопрос «укажите, что я делаю неправильно в кодировке или концептуально ":

Date now = new Date();

// Format the date in the local time zone
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
System.out.println("my inputTime:"+ sdf.format(now));

// Format the date in GMT time zone
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("gmt+0 converted time:"+ sdf.format(now));

// Format the date in GMT time zone (again), since the time     ** ERROR MIGHT **
// zone of the formatter is still set to GMT                    **   BE HERE   **
String standdardTimeStr = sdf.format(now);

// Parse the GMT date string as-if it is in local time zone   ** OR MAYBE HERE **
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
Date date = sdf2.parse(standdardTimeStr); // Date value here is wrong

// Format the bad date value back to string in the same time
// zone, which means you get GMT time back, even though that
// is not the value of the `date` variable
System.out.println("standard input time:"+ sdf2.format(date));

// Do it again, same result, because the time zone is changed    ** ERROR HERE **
// on the wrong formatter object
sdf.setTimeZone(TimeZone.getTimeZone("GMT+6")); //or Asia/Dhaka
System.out.println("gmt+6 convertedtime:"+ sdf2.format(date));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...