假设您网站的用户输入了一个日期范围。
2009-1-1 to 2009-1-3
您需要将此日期发送到服务器进行某些处理,但服务器要求所有日期和时间均为UTC。
现在假设用户在阿拉斯加。由于它们所处的时区与UTC完全不同,因此需要将日期范围转换为如下所示:
2009-1-1T8:00:00 to 2009-1-4T7:59:59
使用JavaScriptDate对象,如何将第一个“本地化”日期范围转换为服务器能够理解的内容?
假设您网站的用户输入了一个日期范围。
2009-1-1 to 2009-1-3
您需要将此日期发送到服务器进行某些处理,但服务器要求所有日期和时间均为UTC。
现在假设用户在阿拉斯加。由于它们所处的时区与UTC完全不同,因此需要将日期范围转换为如下所示:
2009-1-1T8:00:00 to 2009-1-4T7:59:59
使用JavaScriptDate对象,如何将第一个“本地化”日期范围转换为服务器能够理解的内容?
当前回答
我的解决方案使日期保持不变,无论客户端上设置了什么时区。也许有人会发现它很有用。
我的用例:
我正在创建一个todo应用程序,您可以在其中设置任务日期。无论您在哪个时区,此日期都应保持不变。
实例你想在6月25日早上8点给你的朋友打电话。
您在中国时,在5天前(6月20日)创建此任务。
然后,在同一天,你飞往纽约几天。
然后在6月25日,当你还在纽约时,你在早上7:30醒来(这意味着你应该在30分钟内收到任务通知(即使在中国,你创建任务时已经是下午1:30)
因此,任务是忽略时区。这意味着“我想在早上8点在任何时区做这件事”。
我所做的是让我们说“我假设你总是在伦敦时区-UTC”。
这意味着-当用户在她/他的时区中选择某个日期时-我将此日期转换为UTC中的相同日期。也就是说,你在中国选择上午8点,但我将其转换为UTC的上午8点。
然后-下次你打开应用程序时-我读取以UTC保存的日期,并将其转换为当前时区中的相同日期-例如,我将UTC中的上午8点转换为纽约时区中的早上8点。
这个解决方案意味着,日期可能意味着其他东西,这取决于你在设置日期时的位置和阅读日期的位置,但它保持不变,“感觉”你总是在同一时区。
让我们编写一些代码:
首先,我们有两个主要函数用于从UTC转换为UTC,忽略时区:
export function convertLocalDateToUTCIgnoringTimezone(date: Date) {
const timestamp = Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds(),
);
return new Date(timestamp);
}
export function convertUTCToLocalDateIgnoringTimezone(utcDate: Date) {
return new Date(
utcDate.getUTCFullYear(),
utcDate.getUTCMonth(),
utcDate.getUTCDate(),
utcDate.getUTCHours(),
utcDate.getUTCMinutes(),
utcDate.getUTCSeconds(),
utcDate.getUTCMilliseconds(),
);
}
然后,我保存/读取此日期,如:
function saveTaskDate(localDate: Date) {
// I convert your local calendar date so it looks like you've picked it being in UTC somewhere around London
const utcDate = convertLocalDateToUTCIgnoringTimezone(localDate);
api.saveTaskDate(utcDate);
}
function readTaskDate(taskUtcDate: Date) {
// I convert this UTC date to 'look in your local timezone' as if you were now in UTC somewhere around london
const localDateWithSameDayAsUTC = convertUTCToLocalDateIgnoringTimezone(taskUtcDate);
// this date will have the same calendar day as the one you've picked previously
// no matter where you were saving it and where you are now
}
其他回答
处理日期时,我的建议是将日期解析为用户输入的各个字段。你可以把它当作一根完整的绳子,但你在玩火。
JavaScript可以以不同的格式处理两个相同的日期。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
永远不要做类似的事情:
new Date('date as text');
一旦您将日期从用户输入解析到其各个字段中,就创建一个日期对象。创建日期对象后,通过添加时区偏移将其转换为UTC。由于DST,我无法强调使用日期对象的偏移量有多重要(这是另一个讨论来说明原因)。
var year = getFullYear('date as text');
var month = getMonth('date as text');
var dayOfMonth = getDate('date as text');
var date = new Date(year, month, dayOfMonth);
var offsetInMs = ((date.getTimezoneOffset() * 60) // Seconds
* 1000); // Milliseconds
var utcDate = new Date(date.getTime + offsetInMs);
现在,您可以将日期以UTC时间传递给服务器。我再次强烈建议不要使用任何日期字符串。要么将其传递给服务器,并将其细分为所需的最低粒度,例如年、月、日、分钟,要么将其作为一个值(如unix时期的毫秒)传递给服务器。
我知道这个问题已经过时了,但我们正在研究同样的问题,一种选择是将date.valueOf()发送到服务器。javascript Date的valueOf()函数发送自1970年1月1日午夜以来的毫秒数。
值Of()
对于目标是将其作为“日期对象”而不是字符串获取的其他人,并且您只想显示不带TZ(可能是硬编码的)的日期/时间,您可以做的是:
const now = new Date();
const year = now.getUTCFullYear();
const month = now.getUTCMonth();
const day = now.getUTCDate();
const hour = now.getUTCHours();
const tomorrowUTC= new Date();
tomorrowUTC.setDate(day + 1); // +1 because my logic is to get "tomorrow"
tomorrowUTC.setYear(year);
tomorrowUTC.setMonth(month);
tomorrowUTC.Hours(hour);
// then use the tomorrowUTC for to display/format it
// tomorrowUTC is a "Date" and not a string.
然后,您可以执行以下操作:
我们将在${格式(明天UTC,'EEEE do MMMM hh:mmaa')}UTC删除您的帐户
(格式是一个日期fns函数,如果需要,可以使用其他lib);
这有点“黑客”,因为这仍然使用本地时区,但如果你只想显示日期而不是时区,那么这就可以了。
扩展功能:
if (!Date.prototype.toUTC){
Date.prototype.toUTC = function(){
var utcOffset = new Date().getTimezoneOffset();
var utcNow = new Date().addMinutes(utcOffset);
return utcNow;
};
}
用法:
new Date().toUTC();
该方法将为您提供:2017-08-04T11:15:00.000+04:30,您可以忽略区域变量,只需获得2017-08-04T1 1:15:00.000。
function getLocalIsoDateTime(dtString) {
if(dtString == "")
return "";
var offset = new Date().getTimezoneOffset();
var localISOTime = (new Date(new Date(dtString) - offset * 60000 /*offset in milliseconds*/)).toISOString().slice(0,-1);
//Next two lines can be removed if zone isn't needed.
var absO = Math.abs(offset);
var zone = (offset < 0 ? "+" : "-") + ("00" + Math.floor(absO / 60)).slice(-2) + ":" + ("00" + (absO % 60)).slice(-2);
return localISOTime + zone;
}