Сравнение дат с formatDate в скрипте Google Apps отстает на 1 день

Написание скрипта Google Apps, который просматривает задачи через Google Tasks API (как расширенный сервис) и проверяет срок их выполнения, чтобы определить, не просрочены ли они. Если это так, их следует переместить на текущий день.

Завершенный проект

Я использовал этот код для создания этого проекта для обновления задач Google:

Обновите Задачи Google

Проблема

При сравнении текущего дня с датой выполнения задачи, срок выполнения задачи всегда отстает на один день.

Исследовать

Изучив его, я обнаружил, что это может быть связано с переходом на летнее время, и всего один час перерыва может означать разницу в два дня. Я нашел этот вопрос, в котором была аналогичная проблема, их решение заключалось в использовании Session.getScriptTimeZone() для правильной установки часового пояса.

Однако даже когда я устанавливаю часовой пояс с помощью Session.getScriptTimeZone(), срок выполнения задачи по-прежнему остается на один день позже.

Код

function checkOverdue(t) {
  var today = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy");
  //var today = new Date();
  var tasks = t;
  if (tasks.items) {
    for (var i = 0; i < tasks.items.length; i++) {
      var task = tasks.items[i];
      if (task.due) {
        var taskDue = Utilities.formatDate(new Date(task.due), "EST", "MM/dd/yyyy");
        Logger.log('"%s", Comparing "%s" to "%s"',
                 task.title, taskDue, today);
        if (taskDue.valueOf() < today.valueOf()) {
          Logger.log('Task with title "%s" is past due', task.title);
        }
      }
    }
  } else {
    Logger.log('No tasks found.');
  }
}

Журналы

[18-04-10 13:12:33:927 EDT] "Create Bio presentation", Comparing "04/09/2018" to "04/10/2018"
[18-04-10 13:12:33:928 EDT] Task with title "Create Bio presentation" is past due
[18-04-10 13:12:33:929 EDT] "Bio Presentation", Comparing "04/10/2018" to "04/10/2018"
[18-04-10 13:12:33:930 EDT] "Matrix HW", Comparing "04/09/2018" to "04/10/2018"
[18-04-10 13:12:33:930 EDT] Task with title "Matrix HW" is past due

=== [ОБНОВЛЕНИЕ] ===

Я заметил, что если я зарегистрирую исходный task.due, он будет иметь правильную дату. Итак, что-то в форматировании меняет дату.

Новый Код

function checkOverdue(t) {
  var today = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy");
  //var today = new Date();
  var tasks = t;
  if (tasks.items) {
    for (var i = 0; i < tasks.items.length; i++) {
      var task = tasks.items[i];
      if (task.due) {
        var taskDue = Utilities.formatDate(new Date(task.due), "EST", "MM/dd/yyyy");
        Logger.log('"%s", Comparing TaskDue: "%s" to today: "%s", task.due "%s"', task.title, taskDue, today, task.due);
        if (taskDue.valueOf() < today.valueOf()) {
          Logger.log('Task with title "%s" is past due', task.title);
        }
      }
    }
  } else {
    Logger.log('No tasks found.');
  }
}

Новые журналы

[18-04-10 14:15:17:628 EDT] "Create Bio presentation", Comparing TaskDue: "04/09/2018" to today: "04/10/2018", task.due "2018-04-10T00:00:00.000Z"
[18-04-10 14:15:17:629 EDT] Task with title "Create Bio presentation" is past due
[18-04-10 14:15:17:630 EDT] "Bio Presentation", Comparing TaskDue: "04/10/2018" to today: "04/10/2018", task.due "2018-04-11T00:00:00.000Z"
[18-04-10 14:15:17:631 EDT] "Matrix HW", Comparing TaskDue: "04/09/2018" to today: "04/10/2018", task.due "2018-04-10T00:00:00.000Z"
[18-04-10 14:15:17:631 EDT] Task with title "Matrix HW" is past due

=== [Обновление 2] ===

Поменял оба "EST" в формате Дата на Session.getScriptTimeZone()

Удалено .valueOf() для сравнения.

По-прежнему вызывает ту же проблему

Новый Код

function checkOverdue(t) {
  var today = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy");
  //var today = new Date();
  var tasks = t;
  if (tasks.items) {
    for (var i = 0; i < tasks.items.length; i++) {
      var task = tasks.items[i];
      if (task.due) {
        var taskDue = Utilities.formatDate(new Date(task.due), Session.getScriptTimeZone(), "MM/dd/yyyy");
        Logger.log('"%s", Comparing TaskDue: "%s" to today: "%s", task.due "%s"', task.title, taskDue, today, task.due);
        if (taskDue < today) {
          Logger.log('Task with title "%s" is past due', task.title);
        }
      }
    }
  } else {
    Logger.log('No tasks found.');
  }
}

Новые журналы

[18-04-10 15:21:01:988 EDT] "Create Bio presentation", Comparing TaskDue: "04/09/2018" to today: "04/10/2018", task.due "2018-04-10T00:00:00.000Z"
[18-04-10 15:21:01:988 EDT] Task with title "Create Bio presentation" is past due
[18-04-10 15:21:01:990 EDT] "Bio Presentation", Comparing TaskDue: "04/10/2018" to today: "04/10/2018", task.due "2018-04-11T00:00:00.000Z"
[18-04-10 15:21:01:991 EDT] "Matrix HW", Comparing TaskDue: "04/09/2018" to today: "04/10/2018", task.due "2018-04-10T00:00:00.000Z"
[18-04-10 15:21:01:991 EDT] Task with title "Matrix HW" is past due

person CTOverton    schedule 10.04.2018    source источник
comment
Почему вы все еще используете жестко запрограммированный часовой пояс EST в некоторых частях кода? Вы должны заменить это везде, чтобы получить стабильные результаты.   -  person Serge insas    schedule 10.04.2018
comment
Кроме того, вам не следует преобразовывать даты в строки, методы даты явно не работают со строками, поэтому, когда вы используете valueOf () в сравнении, это не имеет смысла. Оставьте даты, поскольку даты и вещи должны работать.   -  person Serge insas    schedule 10.04.2018
comment
Большое спасибо @Sergeinsas, я изменил код, но все равно получаю те же результаты. Я показал, что я сделал в вопросе выше в обновлении 2   -  person CTOverton    schedule 10.04.2018
comment
@Sergeinsas с большим беспорядком Я заметил, что task.due - это строка, а не дата. Таким образом, сравнение не работает, если это не строка. И это проблема, потому что при преобразовании в строку он получает неправильный день   -  person CTOverton    schedule 10.04.2018
comment
Преобразование task.due в объект даты, это лучший способ. Если вам нужна помощь в том, как этого добиться, не стесняйтесь, дайте нам знать прямо сейчас   -  person Serge insas    schedule 11.04.2018
comment
@Sergeinsas, ладно! Я бы предположил, что это будет примерно так: var newTaskDate = new Date (task.due) Однако, если это так, когда я это делаю, я все равно получаю один выходной. Я легко могу это исправить, добавив один день. Итак, после этого все, что мне действительно нужно, это как установить новую дату задачи stackoverflow.com/questions/49763474/   -  person CTOverton    schedule 11.04.2018
comment
Это, вероятно, станет источником проблем через несколько месяцев, когда снова переключится летнее время ... Вы уверены, что календарь и сценарий имеют одинаковые настройки часового пояса?   -  person Serge insas    schedule 11.04.2018
comment
Позвольте нам продолжить это обсуждение в чате.   -  person CTOverton    schedule 11.04.2018


Ответы (2)


Согласно документации API задач Google, свойство task#due является значение даты и времени RFC 3339, например "2018-04-11T0:45:26.000Z". Из этой строки вы можете создать Javascript Date изначально, т.е.

var taskDueDate = new Date(task.due);

Обратите внимание, что это эквивалентно вызову _5 _ и, следовательно, может быть причиной неудачного сравнения дат, учитывая, что Google Apps Script - это Javascript 1.6 (т.е. не ES5 +). Возможно, лучшим методом было бы использование настраиваемого парсера, учитывая, что вы знаете строгий конкретный формат, который вы получите от task.due. Один такой парсер подробно описан в этом ответе.

Как упоминает @Serge, вы должны выполнять это сравнение, используя собственные объекты Date, а не Strings:

function isOverdue(task) {
  if(!task.due)
    return false;

  var now = new Date();
  var endOfToday = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1)); // Also known as start of tomorrow ;)
  var taskDueDate = myFunctionToConvertRFC3339StringToJSDate(task.due);
  return taskDueDate < endOfToday;
}
person tehhowch    schedule 11.04.2018
comment
Действительно ценю это! - person CTOverton; 11.04.2018

для информации, это небольшой код, который я использую для преобразования объекта времени в дату в RFC339. Мне легче читать и понимать.

function parseDate_RFC3339(string) {
  var refStr = new Date().toString();
  Logger.log('refStr = '+refStr);
  var tzOffset = Number(refStr.substr(refStr.indexOf('GMT')+4,2));
  Logger.log('TZ offset = '+tzOffset);
  var parts = string.split('T');
  parts[0] = parts[0].replace(/-/g, '/');
  var t = parts[1].split(':');
  return new Date(new Date(parts[0]).setHours(+t[0]+tzOffset,+t[1],0));
}
person Serge insas    schedule 11.04.2018
comment
Большое спасибо! Действительно помогает - person CTOverton; 11.04.2018
comment
Спасибо, что приняли, но я думаю, что принятый ответ должен быть техничным, мой код предоставляет только простой способ получить то, что он предложил. - person Serge insas; 12.04.2018
comment
Честно говоря, я закончил свой код и дал вам обоим кредит. Вы можете проверить это, если хотите. Я связал это в вопросе - person CTOverton; 12.04.2018