使用 Javascript 将 Excel 日期序列号转换为日期

IT技术 javascript excel date
2021-02-13 09:08:48

我有以下 javascript 代码将日期(字符串)转换为 Microsoft Excel 中使用的日期序列号:

function JSDateToExcelDate(inDate) {

    var returnDateTime = 25569.0 + ((inDate.getTime() - (inDate.getTimezoneOffset() * 60 * 1000)) / (1000 * 60 * 60 * 24));
    return returnDateTime.toString().substr(0,5);

}

那么,我该如何做相反的事情呢?(意味着将 Microsoft Excel 中使用的日期序列号转换为日期字符串的 Javascript 代码?

6个回答

试试这个:

function ExcelDateToJSDate(serial) {
   var utc_days  = Math.floor(serial - 25569);
   var utc_value = utc_days * 86400;                                        
   var date_info = new Date(utc_value * 1000);

   var fractional_day = serial - Math.floor(serial) + 0.0000001;

   var total_seconds = Math.floor(86400 * fractional_day);

   var seconds = total_seconds % 60;

   total_seconds -= seconds;

   var hours = Math.floor(total_seconds / (60 * 60));
   var minutes = Math.floor(total_seconds / 60) % 60;

   return new Date(date_info.getFullYear(), date_info.getMonth(), date_info.getDate(), hours, minutes, seconds);
}

为您量身定做 :)

为什么即使 1970 - 1900 = 25567 天也要减去 25569?并不是说这是我发现的第一个在线代码,正是因为这个原因。
2021-03-19 09:08:48
测试了几种解决方案,这是第一个/唯一一个给我预期值的解决方案
2021-03-25 09:08:48
你能通过改变时区来测试你的解决方案吗..我在 PST 时区我不得不负 25568,然后它工作但在 UTC+10:00 它不起作用,请检查 utc+ 和 utc- 时区。
2021-04-02 09:08:48
@silkfire,呵呵,下一个好奇;) 情况很简单,我的同事 - 远程服务人员,可以访问损坏的日志文件,其中 excel 日期未转换为可读格式,我只是编写了快速 JS 以便他可以检查值在线无需在目标机器上安装 Excel 或任何其他程序,只需打开站点并写入值即可。最后。
2021-04-07 09:08:48
@biesior 听起来不错!干得好,很高兴我编写的代码段对您有所帮助。
2021-04-12 09:08:48

我为你做了一个单线:

function ExcelDateToJSDate(date) {
  return new Date(Math.round((date - 25569)*86400*1000));
}
似乎没有考虑时区。例如,我在使用 UTC+8 时间的中国。使用 43556.1265740741 我得到4/1/2019, 11:02:16 AM比 excel value 晚 8 小时2019/4/1 3:02:16
2021-03-15 09:08:48
这种单线性函数的时间不准确。但日期是正确的。
2021-03-28 09:08:48
Math.round 对我不起作用。尽管如此,它仍然有效。
2021-03-29 09:08:48
我已经建立了一个测试来验证 14 年的日期数字转换为与 excel 相同的日期(忽略时区)。所以这个单线摇滚!
2021-04-04 09:08:48
@pappadog 我发现日期可能会相差 1 毫秒,并且比 Silkfire 的答案中提供的 0.0000001 偏移更准确。
2021-04-10 09:08:48

无需做任何数学运算即可将其归结为一行。

// serialDate is whole number of days since Dec 30, 1899
// offsetUTC is -(24 - your timezone offset)
function SerialDateToJSDate(serialDate, offsetUTC) {
  return new Date(Date.UTC(0, 0, serialDate, offsetUTC));
}

我在 PST,它是 UTC-0700,所以我曾经offsetUTC = -17将 00:00 作为时间(24 - 7 = 17)。

如果您以串行格式从 Google 表格中读取日期,这也很有用。文档建议连续剧可以有一个小数来表示一天的一部分:

指示日期、时间、日期时间和持续时间字段以“序列号”格式输出为双精度值,如 Lotus 1-2-3 所流行的那样。该值的整数部分(小数点左边)计算自 1899 年 12 月 30 日以来的天数。小数部分(小数点右边)将时间计算为一天的一小部分。例如,1900 年 1 月 1 日中午是 2.5,2 因为它是 1899 年 12 月 30 日之后的 2 天,0.5 因为中午是半天。1900 年 2 月 1 日下午 3 点将是 33.625。这正确地将 1900 年视为不是闰年。

因此,如果您想支持带小数的序列号,则需要将其分开。

function SerialDateToJSDate(serialDate) {
  var days = Math.floor(serialDate);
  var hours = Math.floor((serialDate % 1) * 24);
  var minutes = Math.floor((((serialDate % 1) * 24) - hours) * 60)
  return new Date(Date.UTC(0, 0, serialDate, hours-17, minutes));
}
这对我有用.. 你需要抵消 UTC 否则你会得到错误的日期。
2021-04-02 09:08:48
此解决方案适用于 UTC-5 至 UTC+5:30。我只测试了那些范围时区
2021-04-10 09:08:48
这个答案非常接近,但并不完全正确。威廉在这里的回答实际上更准确。如果您坚持使用 UTC 功能,您实际上不需要调整时区。
2021-04-11 09:08:48

眼镜:

1) https://support.office.com/en-gb/article/date-function-e36c0c8c-4104-49da-ab83-82328b832349

Excel 将日期存储为连续的序列号,以便它们可以用于计算。1900 年 1 月 1 日是序号 1,而 2008 年 1 月 1 日是序号 39448,因为它是 1900 年 1 月 1 日之后的 39,447 天。

2) 还有:https : //support.microsoft.com/en-us/help/214326/excel-incorrectly-assumes-that-the-year-1900-is-a-leap-year

当 Microsoft Multiplan 和 Microsoft Excel 发布时,他们还假设 1900 年是闰年。这种假设允许 Microsoft Multiplan 和 Microsoft Excel 使用与 Lotus 1-2-3 相同的序列日期系统,并提供与 Lotus 1-2-3 的更大兼容性。将 1900 年视为闰年也使用户更容易将工作表从一个程序移动到另一个程序。

3) https://www.ecma-international.org/ecma-262/9.0/index.html#sec-time-values-and-time-range

时间在 ECMAScript 中以 UTC 时间 1970 年 1 月 1 日以来的毫秒为单位进行测量。在时间值中,闰秒被忽略。假设每天正好有 86,400,000 毫秒。

4) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Un​​ix_timestamp

new Date(value)

一个整数值,表示自 1970 年 1 月 1 日 00:00:00 UTC(Unix 纪元)以来的毫秒数,忽略闰秒。请记住,大多数 Unix 时间戳函数只能精确到最接近的秒。

把它放在一起:

function xlSerialToJsDate(xlSerial){
  // milliseconds since 1899-31-12T00:00:00Z, corresponds to xl serial 0.
  var xlSerialOffset = -2209075200000; 

  var elapsedDays;
  // each serial up to 60 corresponds to a valid calendar date.
  // serial 60 is 1900-02-29. This date does not exist on the calendar.
  // we choose to interpret serial 60 (as well as 61) both as 1900-03-01
  // so, if the serial is 61 or over, we have to subtract 1.
  if (xlSerial < 61) {
    elapsedDays = xlSerial;
  }
  else {
    elapsedDays = xlSerial - 1;
  }

  // javascript dates ignore leap seconds
  // each day corresponds to a fixed number of milliseconds:
  // 24 hrs * 60 mins * 60 s * 1000 ms
  var millisPerDay = 86400000;

  var jsTimestamp = xlSerialOffset + elapsedDays * millisPerDay;
  return new Date(jsTimestamp);
}

作为单线:

function xlSerialToJsDate(xlSerial){
  return new Date(-2209075200000 + (xlSerial - (xlSerial < 61 ? 0 : 1)) * 86400000);
}
哦亲爱的。情节变厚了。support.office.com/en-us/article/...
2021-03-26 09:08:48

尽管我在讨论开始多年后偶然发现了这个讨论,但我可能对原始问题有一个更简单的解决方案——fwiw,这是我最终将 Excel“自 1899 年 12 月 30 日以来的天数”转换为 JS 日期的方法我需要:

var exdate = 33970; // represents Jan 1, 1993
var e0date = new Date(0); // epoch "zero" date
var offset = e0date.getTimezoneOffset(); // tz offset in min

// calculate Excel xxx days later, with local tz offset
var jsdate = new Date(0, 0, exdate-1, 0, -offset, 0);

jsdate.toJSON() => '1993-01-01T00:00:00.000Z'

从本质上讲,它只是构建一个新的 Date 对象,该对象通过添加 Excel 天数(基于 1),然后通过负本地时区偏移调整分钟数来计算。

我喜欢这个解决方案,因为它很优雅。
2021-04-02 09:08:48