Google Sheet конвертирует неверную дату - PullRequest
0 голосов
/ 15 февраля 2019

Я добавляю столбец, в котором я пишу только цифры в ячейках.Как например: я пишу 15022019, затем я иду в числовые форматы и выбираю date.Таким образом, число преобразуется в 15/02/2019.Но мне не нужно каждый раз, когда я пишу число, меняю формат даты.Мне это нужно автоматически.Итак, я нашел этот скрипт:

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; 
var column = sheet.getRange("D3:D31"); 
column.setNumberFormat("dd/mm/yyy");

Это работает.Но меняет числа на формат даты неправильно.Если я напишу 14022019, его конвертируют в 24/12/40290, а не в 14/02/2019 (как я и ожидал).Почему так?Просто в ручную способ он конвертируется правильно.Мое местоположение - Бразилия.

Может кто-нибудь сказать мне, что я делаю неправильно?


Редактировать 1:

Мне это нужно, чтобыконвертировать в дату автоматически каждый раз, когда я заполняю ячейку с датой.Дата моего диапазона всегда будет D3:D31.Я попытался изменить строки ниже:

function convertnumbertodate(crange){

  // establish spreadsheet credentials
  var ss1=SpreadsheetApp.getActive();
  var sh1=ss1.getActiveSheet();

  // get the range so that rows and columns can be calculated
  var rg1=sh1.getRange(crange);

И вместо (crange) я поставил D3:D31, чтобы попытаться сделать преобразование в дату автоматически.Посмотрите ниже:

function convertnumbertodate(crange){

  // establish spreadsheet credentials
  var ss1=SpreadsheetApp.getActive();
  var sh1=ss1.getActiveSheet();

  // get the range so that rows and columns can be calculated
  var rg1=sh1.getRange(D3:D31);

Но когда я запускаю функцию convertnumbertodate, она сообщает об ошибке.Можете ли вы помочь мне, как заставить его автоматически конвертировать в дату?

Спасибо


Редактировать 2:

Только что сделал то, что вы сделали:

    function convertnumbertodate() {

      // establish spreadsheet credentials
      var editedCell;
      var sh1=ss1.getActiveSheet();

      // get the range so that rows and columns can be calculated
      var rg1=sh1.getRange(D3:D31);

      // get number of columns
      var numColumns = rg1.getNumColumns();

      // if more than one column chosen, stop the process. 
      if (numColumns !=1){
        //Logger.log("DEBUG: Number of columns in range = "+numColumns); // DEBUG
        var message = "Too Many Columns; one column only";
        return message;
      }
etc.

Я удалил crange и поставил свой диапазон D3:D31 Также заставил его работать OnEdit: var editedCell;

Но когда я бегу, он говорит, что это ошибкав строке var rg1=sh1.getRange(D3:D31);

1 Ответ

0 голосов
/ 17 февраля 2019

Проблема
ОП вводит 14022019 в неформатированную ячейку.Когда ячейка отформатирована как дата, возвращается значение 24 декабря 40290;ФП ожидала, что дата будет 14 февраля 2019 года.

Решение
- 1: отформатируйте ячейку как дату до ввода данных.
-2: введите число с разделителями , например 14/02/2019 или 14-02-2019

Пояснение
Когда OP вводит "14022019" вв неформатированной ячейке они предполагают, что ввод должен рассматриваться как дата (14 февраля 2019 г.).Однако Google рассматривает содержимое по номинальной стоимости;нет никаких выводов о дате / времени.Так, когда ячейка впоследствии форматируется как дата, необработанное значение преобразуется в дату, и ячейка отображает 24 декабря 40290.

Причина в том, что эпоха времени Google началась 31 декабря 1899 г. 00:00:00 (в отличие от Unix Time Epoch, , который используется Javascript , который начался 1 января 1970 года 00:00:00).Во-вторых, Google измеряет дату и время в днях (в отличие от эпохи Unix, которая измеряет прошедшие секунды).

Это ( примерно ), как Google конвертирует 14 022 019 в 24 декабря 40290.

  • 14 022 019 "дней", в среднем примерно 365 245 дней в году = примерно 38 390,7 года.
  • Добавьте 1899 для эпохи Google.Промежуточный итог = 40289,7 года.(примерно середина сентября 40290)
  • с учетом корректировок для високосных годов 101,795 дней = 0,3 (101,795 / 365,245);Промежуточный итог = 40290 лет.(примерно 24 декабря 40290)

Примечание # 1: есть еще одно осложнение.
Способ, которым Sheets и Apps Script обрабатывают "даты", очень различаются.

  • Листы: единица «дата» составляет 1 день;Базовая дата - 1899-12-30 0:00:00, получая часовой пояс из настроек электронной таблицы.
  • Сценарий приложений (основанный на JavaScript): единица «дата» равна 1 миллисекунде.Базовая дата 1970-1-1 00:00:00 UTC.

Ссылка / Кредит: Рубен

Примечание № 2: Моя ссылка для эпохи Google: (https://webapps.stackexchange.com/a/108119/196152)

Примечание № 3: В целом преобразования даты / времени основаны на 3600 секунд в час, 86 400 секунд в день, 31 556 926 секунд в год и 365,24 дней в году.


ОБНОВЛЕНИЕ - 20Фев 2019
ОП совершенно справедливо спрашивает: «Как мне преобразовать существующие ячейки?»

Код для преобразования прост: - преобразовать число в строку - срезстрока в компоненты для дня, месяца и года - используйте компоненты для создания новой даты - обновите ячейку с датой

Потенциальный вопрос для диапазона, который необходимо преобразовать. Что такое диапазон, это диапазонвсегда один и тот же размер и т. д. Следующий код позволяет пользователю выбрать диапазон для интерфейса. Затем этот диапазон можно преобразовать. Возможно, этот элемент не был необходим, но он обеспечивает более гибкое, если не элегантное, решение.


Code.gs

function onOpen(){
  SpreadsheetApp.getUi()
  .createMenu("Date Convert")
  .addItem("Convert", "selRange")
  .addToUi();
}


function selRange()//run this to get everything started.  A dialog will be displayed that instructs you to select a range.
{
  var output=HtmlService.createHtmlOutputFromFile('pickRange').setWidth(300).setHeight(200).setTitle('Convert to dates');
  SpreadsheetApp.getUi().showModelessDialog(output, 'Convert Numbers to Dates');
}

function selCurRng() 
{
  var sso=SpreadsheetApp.getActive();
  var sh0=sso.getActiveSheet();
  var rg0=sh0.getActiveRange();
  var rng0A1=rg0.getA1Notation();
  rg0.setBackground('#FFC300');
  return rng0A1;

}

function clrRange(range)
{
  var sso=SpreadsheetApp.getActive();
  var sh0=sso.getActiveSheet();
  var rg0=sh0.getRange(range);
  rg0.setBackground('#ffffff');
}

function convertnumbertodate(crange){

  // establish spreadsheet credentials
  var ss1=SpreadsheetApp.getActive();
  var sh1=ss1.getActiveSheet();

  // get the range so that rows and columns can be calculated
  var rg1=sh1.getRange(crange);

  // get number of columns
  var numColumns = rg1.getNumColumns();

  // if more than one column chosen, stop the process. 
  if (numColumns !=1){
    //Logger.log("DEBUG: Number of columns in range = "+numColumns); // DEBUG
    var message = "Too Many Columns; one column only";
    return message;
  }

  // get the first row and the number of rows
  var rowqty = 1;
  var rownum = rg1.getRow();
  // Logger.log("DEBUG: first row = "+rownum);//DEBUG
  var rowqty = rg1.getNumRows();
  // Logger.log("DEBUG: Number of rows  = "+rowqty); //DEBUG

  // get the values - different syntax for a single cell vs range
  if (rowqty !=1){
    // Multiple cells - uset GetValues
    var rangevalues = rg1.getValues();
  }
  else {
    // single cell, use getValue
    var rangevalues = rg1.getValue();
  }
  //Logger.log("DEBUG: Values = "+rangevalues); //DEBUG

  // create array for temporary storage
  var newvalues = [];

  // loop through the values
  for (var i=0; i< rowqty; i++){

    // different treatment for single cell value
    if (i!=0 && rowqty !=1){
      // multiple cells
      var nstring = rangevalues[i].toString();
    }
    else {
      // single value cell
      var nstring = rangevalues.toString();
    }   
    Logger.log("DEBUG: Value of the string is = "+nstring); //DEBUG

    // slice the string in day, month and year
    var daystring = nstring.slice(0, 2);
    var monthstring = nstring.slice(2, 4);  
    var yearstring = nstring.slice(4, 8);

    //calculate the date
    var pubdate = new Date(yearstring, monthstring - 1, daystring);
    //Logger.log("DEBUG: the date is "+pubdate); //DEBUG

    // push the value onto the aray
    newvalues.push([pubdate]);

  }

  // set the value(s)
  if (rowqty !=1){
    // Multiple cells - uset GetValues
    rg1.setValues(newvalues)
  }
  else {
    // single cell, use getValue
    rg1.setValue(newvalues);
  }
  //rg1.setValues(newvalues);
  var message = "Update complete";
  rg1.setBackground('#ffffff');
  return message; 
}

pickRange.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script>
     var grange='';
     function selectRange()
     {
       $('#btn1').prop('disabled',true);
       $('#btn2').prop('disabled',false);
       google.script.run
         .withSuccessHandler(setResponse)
         .selCurRng();
     }
     function setResponse(r)
     {
       grange=r;
       var msg='Selected range: '  + r+". Ready to convert"; 
       $('#instr').css('display','none');
       $('#rsp').text(msg); 
     }
     function convert2date()
     {
       $('#btn1').prop('disabled',false);
       $('#btn2').prop('disabled',false);
       google.script.run
         .withSuccessHandler(setResponse02)
         .convertnumbertodate(grange);
     }
     function setResponse02(q)
     {
       qnumber=q;
       var msg= q; 
       $('#instr').css('display','none');
       $('#rsp').text(msg); 
     }
     function clearAndClose()
     {
       google.script.run.clrRange(grange);
       google.script.host.close();

     }
     console.log('My Code');
    </script>
  </head>
  <body>
    <div id="rsp"></div>
    <div id="instr">Select range - <b>One column limit</b></div>
    <br/>
    <input type="button" id="btn1" value="1 - Select a range" onClick="selectRange();" />
    <br />
    <input type="button" id="btn3" value="2 - Convert numbers to dates" onClick="convert2date();" />
    <br />
    <input type="button" id="btn2" value="close" onClick="clearAndClose();"; disabled="true" />
  </body>
</html>

Credit
// Запрашивать у пользователя диапазон.Функция gs, передача массива в html-скрипт и переориентация на HTML-диалог // кредитный ответ Купера - https://stackoverflow.com/a/45427670/1330560


ADDENDUM

Если диапазон, в котором вводятся псевдо-даты, известен и не изменяется, то код для его управления упрощается

function onEdit(e) {

  // establish spreadsheet credentials
  var ss1 = SpreadsheetApp.getActive();
  var sh1 = ss1.getActiveSheet();

  // get the onEdit parameters
  var debug_e = {
    authMode: e.authMode,
    range: e.range.getA1Notation(),
    source: e.source.getId(),
    user: e.user,
    value: e.value,
    oldValue: e.oldValue
  };
  //Logger.log("AuthMode: "+debug_e.authMode+"\n, Range: "+debug_e.range+"\n, source: "+debug_e.source+"\n, user: "+debug_e.user+"\n, value: "+debug_e.value+"\n, old value: "+debug_e.oldValue);

  // Note the range for data entry is known and fixed.
  // it is "D3:D31"

  // Target range for converting numbers to dates
  // set the column
  var column = 4; // column D
  // get the first row and the number of rows
  var rowqty = 29;
  var rowfirst = 3;
  var rowlast = 31;
  //Logger.log("DEBUG: first row = "+rowfirst+", last row = "+rowlast+", number of rows = "+rowqty);//DEBUG

  // get detail of the  edited cell
  var editColumn = e.range.getColumn();
  var editRow = e.range.getRow();
  //Logger.log("DEBUG: edited column = "+editColumn+", edited row "+editRow);//DEBUG

  //test if the edited cell falls into the target range
  if (editColumn == 4 && editRow >= rowfirst && editRow <= rowlast) {
    // the edit was in the target range
    var nstring = e.value.toString();
    //Logger.log("DEBUG: Value of the string is = "+nstring); //DEBUG

    // slice the string in day, month and year
    var daystring = nstring.slice(0, 2);
    var monthstring = nstring.slice(2, 4);
    var yearstring = nstring.slice(4, 8);

    //calculate the date
    var pubdate = new Date(yearstring, monthstring - 1, daystring);
    //Logger.log("DEBUG: the date is "+pubdate); //DEBUG
    e.range.setValue(pubdate)

  } else {
    //Logger.log("DEBUG: Nothing to see here; this cell not in the target range");//DEBUG
  }
}
...