Datetime 谷歌表转换错误的日期
我有一列只在单元格中写数字。例如: 我写15022019,然后选择数字格式并选择日期。因此,该数字被转换为2019年2月15日。 但我不需要每次写一个数字时都更改日期格式。我自动需要它。所以我找到了这个脚本:Datetime 谷歌表转换错误的日期,datetime,google-apps-script,google-sheets,Datetime,Google Apps Script,Google Sheets,我有一列只在单元格中写数字。例如: 我写15022019,然后选择数字格式并选择日期。因此,该数字被转换为2019年2月15日。 但我不需要每次写一个数字时都更改日期格式。我自动需要它。所以我找到了这个脚本: var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheets()[0]; var column = sheet.getRange("D3:D31"); column.setNumberFormat("d
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var column = sheet.getRange("D3:D31");
column.setNumberFormat("dd/mm/yyy");
它起作用了。但将数字更改为最新格式不正确。如果我写14022019,它将转换为24/12/40290,而不是我预期的2019年2月14日。
为什么?
以手动方式正确转换。我的位置是巴西
有人能告诉我我做错了什么吗
编辑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.
我删除了起重机,把我的范围放在D3:D31
还让它运行OnEdit:var editedCell
但是当我运行时,它说在var rg1=sh1行中有一个错误 问题
OP在未配对的单元格中输入14022019。将单元格格式化为日期时,返回的值为12月24日40290;OP预计日期为2019年2月14日
解决方案
-1:将单元格格式化为数据输入前的日期。
-2:使用分隔符输入编号,如14/02/2019或14-02-2019
解释
当OP将14022019输入到未格式化的单元格中时,他们希望输入应被视为2019年2月14日的日期。然而,谷歌将内容视为表面价值;没有关于日期/时间的推断。因此,当随后将单元格格式化为日期时,原始值将转换为日期,单元格将显示12月24日40290
原因是Google时间纪元开始于1899年12月31日00:00:00,而Unix时间纪元由Javascript使用,它开始于1970年1月1日00:00:00。其次,Google以天为单位度量日期时间,而Unix纪元则以秒为单位度量时间
这大概就是谷歌将14022019转换为12月24日40290的方式
14022019天,粗略平均每年365.245天=约38390.7年。
加上1899年的谷歌时代。运行总时间=40289.7年。大约9月中旬40290
考虑闰年101.795天的调整=0.3 101.795/365.245;运行总时间=40290年。大约12月24日40290
注1:还有一个更复杂的问题。
工作表和应用程序脚本处理日期的方式非常不同
表:日期单位为1天;基准日期为1899-12-30 0:00:00,从电子表格设置中获取时区。
应用程序脚本基于JavaScript:日期单位为1毫秒。基准日期为UTC 1970-1-1 00:00:00。
参考/信贷:
注2:我对谷歌时代的参考是
注3:大致为每小时3600秒、每天86400秒、每年31556926秒和每年365.24天
更新日期:2019年2月20日
OP问得很对,那么如何转换现有的单元格呢
进行转换的代码非常简单:
-将数字转换为字符串
-将字符串切分为日、月和年的组件
-使用组件创建新日期
-用日期更新单元格
要转换的范围是一个潜在问题。什么是范围,范围是否总是相同的大小,等等?下面的代码启用了一个供用户选择范围的界面。然后可以转换范围。可以说,这个元素不是必需的,但确实提供了一个更灵活、更优雅的解决方案
代码.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>
功劳
//
//库珀的信用回答-
附录
如果输入伪日期的范围是已知的,并且是不变的,那么管理它的代码就会简化
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
}
}
那么,难道没有一种方法可以正确地转换为只在单元格中键入数字的日期吗?我不想要除数,比如/或-。我如何编辑我的脚本以转换为日期?你的脚本太棒了!我非常感谢你的帮助。请查看我的编辑。如果不是太晚,我只想检查一点:如果我在单元格中写入例如2019年2月26日,然后删除此单元格的日期,同一单元格将自动创建此日期:1969年12月31日。我不能删除日期,因为它会再次生成日期。你能解决它吗?作为一个有趣的问题,你认为它为什么会发生?您是否进行过任何研究、测试或故障排除以了解原因?我记得你说过我不想要除数,比如…,所以我认为你应该为解决这个问题做出贡献是合理的。我想是因为它记住了错误的值,然后转换成日期
总体安排如果我删除它,它返回到错误的值,我猜是e.oldValue。我试图删除它,也做了一些更改,但没有任何效果,所以我没有在这里发布,只是让函数convertnumbertodate-删除“crange”参数。然后,考虑将它作为一个OnEdEnter函数,以便在您输入数据时执行它。要确保它不会影响每次编辑,请包括一个测试,以检查编辑的单元格是否在指定范围内。关于StackOverflow有很多以前的话题。你能检查一下我的编辑2吗?对不起。我的心思不在工作上。参考附录。这是完全独立的,onEdite。一次工作一个细胞。顺便说一下,如果这些答案中的任何一个被证明是有用的,你可以考虑接受这个答案。