Jac*_*ack 12 javascript excel date
我有以下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);
}
Run Code Online (Sandbox Code Playgroud)
那么,我该怎么做呢?(这意味着将Microsoft Excel中使用的日期序列号转换为日期字符串的Javascript代码?
sil*_*ire 32
试试这个:
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);
}
Run Code Online (Sandbox Code Playgroud)
定制为你:)
Wil*_*man 27
new Date(Date.UTC(0, 0, excelSerialDate - 1));
Run Code Online (Sandbox Code Playgroud)
new Date(Date.UTC(0, 0, excelSerialDate));
Run Code Online (Sandbox Code Playgroud)
我真的很喜欢@leggett 和@SteveR 的答案,虽然它们大多有效,但我想更深入地了解如何Date.UTC()工作。
注意:时区偏移可能存在问题,特别是对于较旧的日期(1970 年之前)。请参阅浏览器、时区、Chrome 67 错误(历史时区更改),因此我希望保留 UTC,并且尽可能不依赖于任何时间变化。
Excel 日期是基于 1900 年 1 月 1 日的整数(在 PC 上。在 MAC 上则基于 1904 年 1 月 1 日)。假设我们使用的是 PC。
1900-01-01 is 1.0
1901-01-01 is 367.0, +366 days (Excel incorrectly treats 1900 as a leap year)
1902-01-01 is 732.0, +365 days (as expected)
Run Code Online (Sandbox Code Playgroud)
JS 中的日期基于Jan 1st 1970 UTC. 如果我们使用Date.UTC(year, month, ?day, ?hour, ?minutes, ?seconds)它将返回自该基准时间(UTC)以来的毫秒数。它有一些有趣的功能,我们可以利用它们来获益。
除了 之外,所有参数的正常范围Date.UTC()都是从 0 开始的day。它确实接受这些范围之外的数字,并将输入转换为超出或下溢其他参数。
Date.UTC(1970, 0, 1, 0, 0, 0, 0) is 0ms
Date.UTC(1970, 0, 1, 0, 0, 0, 1) is 1ms
Date.UTC(1970, 0, 1, 0, 0, 1, 0) is 1000ms
Run Code Online (Sandbox Code Playgroud)
它也可以处理早于 1970-01-01 的日期。在这里,我们将日期从 0 减到 1,并增加小时、分钟、秒和毫秒。
Date.UTC(1970, 0, 0, 23, 59, 59, 999) is -1ms
Run Code Online (Sandbox Code Playgroud)
它甚至足够智能,可以将 0-99 范围内的年份转换为 1900-1999
Date.UTC(70, 0, 0, 23, 59, 59, 999) is -1ms
Run Code Online (Sandbox Code Playgroud)
现在,我们如何表示 1900-01-01?为了更轻松地查看我喜欢的日期的输出
new Date(Date.UTC(1970, 0, 1, 0, 0, 0, 0)).toISOString() gives "1970-01-01T00:00:00.000Z"
new Date(Date.UTC(0, 0, 1, 0, 0, 0, 0)).toISOString() gives "1900-01-01T00:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)
现在我们必须处理时区。Excel 在其日期表示中没有时区的概念,但 JS 有。恕我直言,解决这个问题的最简单方法是将所有 Excel 日期输入为 UTC(如果可以的话)。
从 Excel 日期 732.0 开始
new Date(Date.UTC(0, 0, 732, 0, 0, 0, 0)).toISOString() gives "1902-01-02T00:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)
我们知道,由于上述闰年问题,该时间会延迟 1 天。我们必须将 day 参数减 1。
new Date(Date.UTC(0, 0, 732 - 1, 0, 0, 0, 0)) gives "1902-01-01T00:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)
需要注意的是,如果我们使用 new Date(year,month,day) 构造函数构造日期,则参数将使用您当地的时区。我在 PT (UTC-7/UTC-8) 时区,我得到
new Date(1902, 0, 1).toISOString() gives me "1902-01-01T08:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)
对于我的单元测试,我使用
new Date(Date.UTC(1902, 0, 1)).toISOString() gives "1902-01-01T00:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)
将 Excel 序列日期转换为 js 日期的 Typescript 函数是
public static SerialDateToJSDate(excelSerialDate: number): Date {
return new Date(Date.UTC(0, 0, excelSerialDate - 1));
}
Run Code Online (Sandbox Code Playgroud)
并提取 UTC 日期以供使用
public static SerialDateToISODateString(excelSerialDate: number): string {
return this.SerialDateToJSDate(excelSerialDate).toISOString().split('T')[0];
}
Run Code Online (Sandbox Code Playgroud)
Gil*_*Gil 16
我为你做了一个单行班:
function ExcelDateToJSDate(date) {
return new Date(Math.round((date - 25569)*86400*1000));
}
Run Code Online (Sandbox Code Playgroud)
leg*_*ett 10
无需做任何数学运算即可将其归结为一行。
// 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));
}
Run Code Online (Sandbox Code Playgroud)
我在 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));
}
Run Code Online (Sandbox Code Playgroud)
眼镜:
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 毫秒。
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);
}
Run Code Online (Sandbox Code Playgroud)
作为单线:
function xlSerialToJsDate(xlSerial){
return new Date(-2209075200000 + (xlSerial - (xlSerial < 61 ? 0 : 1)) * 86400000);
}
Run Code Online (Sandbox Code Playgroud)
小智 5
尽管我在讨论开始多年后偶然发现了这个讨论,但我可能对原始问题有一个更简单的解决方案——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'
Run Code Online (Sandbox Code Playgroud)
本质上,它只是构建一个新的 Date 对象,该对象通过添加 Excel 天数(基于 1),然后通过负本地时区偏移量调整分钟数来计算。
小智 5
我真的很喜欢吉尔的答案,因为它很简单,但它缺少时区偏移。所以,这里是:
function date2ms(d) {
let date = new Date(Math.round((d - 25569) * 864e5));
date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
return date;
}
Run Code Online (Sandbox Code Playgroud)