Как объединить две даты и времени в одну дату и время?

У меня есть две даты со значениями времени. Мне нужно объединить дату из одного и время из другого и сделать из них третью дату и время.

Вот JSON:

  "block_times": [
    {
      "id": 63672,
      "name": "One hour blocked time",
      "all_day": false,
      "start_date": "07/07/2020",
      "end_date": "07/07/2020",
      "start_time": "2000-01-01T16:00:00.000-06:00",
      "end_time": "2000-01-01T17:00:00.000-06:00",
      "note": "One hour block time",
      "account_id": 1,
      "service_routes_id": 4502,
      "created_at": "2020-07-07T10:50:30.599-05:00",
      "updated_at": "2020-07-07T10:50:30.599-05:00"
    }
  ]

Мне нужно получить дату из start_date и мне нужно получить время из start_time и объединить их вместе со значением даты и времени.

У меня есть следующий код:

 public static Date convertBlockedTimeToUserTime(String startTimeStr, String startDateStr) {
      SimpleDateFormat dateFormat = new SimpleDateFormat(getDateTimeFormat(), Locale.US);
      SimpleDateFormat startDateFormatInitial = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
      SimpleDateFormat startDateFormatFinal = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
      SimpleDateFormat startTimeFormat = new SimpleDateFormat(getTimeFormat(), Locale.US);
    try {
      String resultStartDate = startDateFormatFinal.format(startDateFormatInitial.parse(startDateStr));
      String resultStartTime = startTimeFormat.format(dateFormat.parse(startTimeStr));
      String result =  resultStartDate+"T"+resultStartTime;
      return dateFormat.parse(result);
    } catch (ParseException e) {
      e.printStackTrace();
      return null;
    }

Я получаю этот результат: 2020-07-07T11:00:00.000+01:00 и это неправильно, так как мой текущий часовой пояс GMT +2, поэтому он должен быть таким: 2020-07-07T10:00:00.000+02:00.

Может ли кто-нибудь помочь мне найти проблему?


person Zookey    schedule 08.07.2020    source источник
comment
Первая проблема заключается в использовании java.util вместо java.time, а вторая - в наличии полных дат и времени, включая смещение, где вам, очевидно, нужна только часть времени... и, возможно, смещение, но это неясно.   -  person deHaar    schedule 08.07.2020
comment
В качестве отступления подумайте о том, чтобы выбросить давно устаревшие и заведомо неприятные SimpleDateFormat и их друзей. Посмотрите, можете ли вы использовать дешугаринг или добавить ThreeTenABP в свой проект Android, чтобы использовать java.time, современный API даты и времени Java. С ним намного приятнее работать.   -  person Ole V.V.    schedule 08.07.2020


Ответы (2)


Ваш API очень неуклюжий. Как правило, пакет java.time (который, если вы используете древнюю версию Java, в которой его нет, все еще можно получить через бэкпорт) очень хорошо дает вам всевозможные типы, которые могут представлять все виды сумасшедших дат и времени, и при использовании правильных типов для представления вещей такими, какие они есть, код работает. как следствие. Время — это очень сложная концепция, поэтому используйте лучший доступный инструмент.

import java.time.*;
import java.time.format.*;

class Example {
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd/MM/yyyy");

    public static void main(String[] args) {
        String inDate = "07/07/2020";
        String inTime = "2000-01-01T16:00:00.000-06:00";
        LocalDate ld = LocalDate.parse(inDate, DATE_FORMAT);
        OffsetTime time = OffsetDateTime.parse(inTime, DateTimeFormatter.ISO_OFFSET_DATE_TIME).toOffsetTime();
        ZonedDateTime target = time.atDate(ld).atZoneSameInstant(ZoneId.systemDefault());
        System.out.println(target);
    }
}

Здесь мы сначала преобразуем ваш сумасшедший ввод времени в OffsetDateTime (потому что это то, что есть; это полная дата и время со смещением, а не часовой пояс; часовой пояс - это что-то вроде «амстердама»; реальные часовые пояса имеют разные смещения в зависимости от времени года и может быть совершенно разным в зависимости от века и т. д. Смещения - это то, что они говорят). Затем мы отбрасываем часть даты. Затем мы превращаем его обратно в смещение даты и времени, смешивая дату из вашего ввода даты, и, наконец, мы «переназначаем» эту вещь в вашу предпочтительную зону. В этом фрагменте я выбрал «системное значение по умолчанию», которое может не подходить для серверного приложения, но, вероятно, это то, что вам нужно для Android.

Обратите внимание, что этот API по своей сути сбивает с толку. Что произойдет, если, скажем, входные данные будут следующими:

        String inDate = "07/07/2020";
        String inTime = "2000-01-01T23:00:00.000-06:00";

Вам нужен этот вывод, если вы были в Европе летом:

2020-07-08T07:00:00.000+02:00

обратите внимание, что на самом деле это не тот день, который указан на входе, потому что так работают зоны.

Это то, что делает этот фрагмент. Это странно, если вы этого не хотите (в конце концов, это означает, что вы настраиваетесь на целый день в зависимости от того, где находится ваш телефон, когда запускается код, это звучит странно, нет?) - но если результат зонированной даты и времени должен упасть на дату ввода, тогда вам, вероятно, будет лучше в конце проверить, является ли день «неправильным», а затем использовать .plusDays или .minusDays для настройки.

person rzwitserloot    schedule 08.07.2020
comment
Спасибо за разъяснение и ответ. К сожалению, я использую Android SDK, который является очень ограниченной и более старой версией Android API, которая не может использовать функции Java Time, которые были представлены в Java 8. Эта исходная дата и время с GMT-6 из США и в этом формате сохраняются в базе данных API, которую я не контролирую. Я из Европы, и мне нужно отображать часовой пояс GMT + 2. 2020-07-07T07:22:00.000+02:00 должен быть ответом, насколько я понимаю. - person Zookey; 08.07.2020
comment
@Zookey Из того, что мне сообщили, у вас есть два варианта: (1) Использование java.time через дешугаринг. (2) Использование резервной копии java.time; добавьте ThreeTenABP в свой проект Android - person Ole V.V.; 08.07.2020
comment
@Zookey Я связался с бэкпортом. Он отлично работает на андроиде. - person rzwitserloot; 09.07.2020

  "start_date": "07/07/2020",
 "end_date": "07/07/2020",
 "start_time": "2000-01-01T16:00:00.000-06:00",
 "end_time": "2000-01-01T17:00:00.000-06:00",

Какой неуклюжий API ????

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

  SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
  SimpleDateFormat timeFormat = new SimpleDateFormat(getDateTimeFormat(), Locale.US); // TODO: parse 2000-01-01T16:00:00.000-06:00

  Date date = dateFormat.parse(startDateString);
  Date time = timeFormat.parse(startTimeString);

  Calendar dateCalendar = Calendar.getInstance();
  dateCalendar.setTimeInMillis(date.getTime());
  
  Calendar timeCalendar = Calendar.getInstance();
  timeCalendar.setTimeInMillis(time.getTime());

  int year = dateCalendar.get(Calendar.YEAR);
  int month = dateCalendar.get(Calendar.MONTH);
  int day = dateCalendar.get(Calendar.DAY_OF_MONTH);

  timeCalendar.set(Calendar.DAY_OF_MONTH, 1);
  timeCalendar.set(Calendar.YEAR, year);
  timeCalendar.set(Calendar.MONTH, month);
  timeCalendar.set(Calendar.DAY_OF_MONTH, day);

  return timeCalendar.getTime();
  

ПРИМЕЧАНИЕ. есть вероятность, что синтаксический анализ информации о часовом поясе в java.util.Date не является хорошей идеей, и в этом случае вы можете захотеть использовать java.time.* API, который должен быть доступен в AS 4.0 с AGP 4.0.

person EpicPandaForce    schedule 08.07.2020
comment
Я думаю, что у Женевы есть что сказать о рекомендации (или даже намеке на рекомендацию) использовать API календаря. - person rzwitserloot; 08.07.2020
comment
Это Android, и я не уверен, работает ли дешугаринг для java.time, поэтому ¯\_(ツ)_/¯, если вы хотите дать ответ, используя ThreeTenBP или что-то в этом роде, то вы определенно можете это сделать. - person EpicPandaForce; 08.07.2020
comment
Как обычно, отказ от использования 310 приводит к пагубным проблемам. Этот код будет совершенно причудливым образом давать сбои в определенные даты. Например, если время ввода «23:00:00.000-06:00», а желаемая дата — 7 июля, а телефон находится в Амстердаме, какой результат требуется? ваш фрагмент сказал бы: 7 утра 7-го. Что неправильно; 8-го было бы 7 утра. Вот почему так плохо рекомендовать Календарь: время тяжелое, а Календарь заставляет вас писать неправильный код. - person rzwitserloot; 08.07.2020
comment
(Или, альтернативно, ОП действительно действительно этого хочет, но эта странность присуща вопросу, но не очевидна. Использование правильных типов из 310 приводит к менее «шаткому» результату (который будет: ответ 07:00 8 июля) или не будет компилироваться, что хорошо соответствует тому, что заданный вопрос не сформулирован должным образом. В этом случае вы получаете «меньший» результат (наименее шаткий ответ), но поток преобразования к OffsetDT, а затем повторное зонирование, которое выделяет гораздо лучше, чем вы сначала находите правильный момент, а затем зонируете его в нужной зоне. - person rzwitserloot; 08.07.2020
comment
Я слышал, что этот подход фактически нарушает информацию о часовом поясе, но я думаю, что это произошло во время анализа Date. - person EpicPandaForce; 08.07.2020