Google表格错误地转换了日期

时间:2019-02-15 09:55:18

标签: datetime google-apps-script google-sheets

我表示只在单元格中写数字的列。例如: 我写了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 还使其运行OnEditvar editedCell;

但是当我跑步时,它说在var rg1=sh1.getRange(D3:D31);行中有一个错误

1 个答案:

答案 0 :(得分:0)

问题
OP在未格式化的单元格中输入14022019。将单元格格式化为日期时,返回的值为40290 December 24;返回值为40290。 OP预计日期为2019年2月14日。

解决方案
-1:将单元格的格式设置为输入之前的日期。
-2:输入带分隔符的数字 ,例如14/02/2019或14-02-2019

说明
当OP在未格式化的单元格中键入“ 14022019”时,他们打算将输入内容视为日期(2019年2月14日)。但是,Google会根据内容看重内容;没有关于日期/时间的推论。因此,当单元格随后被格式化为日期时,原始值将转换为日期,并且该单元格显示40290 12月24日。

原因是Google时间纪元始于1899年12月31日00:00:00(与1970年1月1日开始的Javascript 使用的Unix时间纪元相反。 00:00:00)。其次,Google以天为单位测量日期时间(与Unix Epoch相比,以秒为单位)。

(大致是 )这就是Google如何将14,022,019转换为40290年12月24日。

  • 14,022,019个“天”,大约每年平均365.245天=大约38390.7年。
  • 在1899年添加Google Epoch。累计运行时间= 40289.7年。 (大约40290年9月中旬)
  • 允许调整leap年101.795天= 0.3(101.795 / 365.245);累计运行时间= 40290年。 (大约40290年12月24日)

注意#1:还有一个复杂之处。
  表格和Apps脚本处理“日期”的方式非常不同。

  • 数据表:“日期”单位为1天;基本日期为1899-12-30 0:00:00,可从电子表格设置中获取时区。
  • Apps脚本(基于JavaScript):“日期”单位为1毫秒。基准日期是1970-1-1 00:00:00 UTC。

参考/信用:Rubén

注释#2:我对Google Epoch的引用是(https://webapps.stackexchange.com/a/108119/196152

注释3:大致date/time conversions are based on每小时3,600秒,每天86,400秒,每年31,556,926秒和每年365.24天。


更新-2019年2月20日
OP非常正确地问,“那么我该如何转换现有的单元格呢?”

进行转换的代码非常简单:  -将数字转换为字符串  -将字符串切成天,月和年的组成部分  -使用组件创建新日期  -用日期更新单元格

要转换的范围是一个潜在问题。范围是多少,范围是否总是相同大小,等等?以下代码使用户可以选择一个范围的界面。然后可以转换范围。可以说,这个元素不是必需的,但是确实提供了一种更为灵活(甚至不是优雅的)解决方案。


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>

信用
// Prompt user for range in .gs function, pass array to html script and re-focus on the HTML dialog // Cooper的信用答案-https://stackoverflow.com/a/45427670/1330560


添加

如果知道输入伪日期的范围并且该范围没有变化,则简化了管理伪代码的代码

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
  }
}