本文概述
作为软件开发人员, 你不能逃避日期操纵。开发人员构建的几乎每个应用程序都将具有一些组件, 需要从用户那里获取日期/时间, 并将其存储在数据库中, 并显示回给用户。
向任何程序员询问有关他们处理日期和时区的经验, 他们可能会分享一些战争故事。处理日期和时间字段当然不是火箭科学, 但通常很乏味且容易出错。
有数百篇关于该主题的文章, 但是, 大多数要么过于学术化, 专注于细节的细节, 要么过于零散, 仅提供简短的代码片段, 而没有太多解释。这份有关DateTime操作的深入指南应该可以帮助你了解与时间和日期相关的编程概念和最佳实践, 而不必浏览有关该主题的大量信息。
在本文中, 我将帮助你清楚地考虑日期和时间字段, 并提出一些最佳实践, 以帮助你避免日期时间的麻烦。在这里, 我们将探讨正确处理日期和时间值所必需的一些关键概念, 便于存储DateTime值并通过API传输它们的格式, 等等。
如果正确理解DateTime库, 它们将提供帮助
日期库以多种方式帮助你简化生活。它们极大地简化了日期解析, 日期算术和逻辑运算以及日期格式。你可以为前端和后端找到可靠的日期库, 从而为你完成大部分繁重的工作。
但是, 我们经常使用日期库而没有考虑日期/时间的实际工作方式。日期/时间是一个复杂的概念。即使对日期库的帮助, 由于对其理解不正确而出现的错误也很难理解和修复。作为程序员, 你需要了解基础知识, 并能够体会到日期库为充分利用它们而解决的问题。
此外, 日期/时间库只能带你走这么远。通过允许你访问方便的数据结构来表示DateTime, 所有日期库都可以工作。如果你要通过REST API发送和接收数据, 则最终将需要将日期转换为字符串, 反之亦然, 因为JSON没有用于表示DateTime的本机数据结构。我在这里概述的概念将帮助你避免执行这些从日期到字符串和从字符串到日期的转换时可能出现的一些常见问题。
注意:尽管我已经使用JavaScript作为本文讨论的编程语言, 但是这些都是通用的概念, 几乎适用于所有编程语言及其日期库。因此, 即使你以前从未编写过JavaScript代码, 也可以继续阅读, 因为我几乎不假定本文具有JavaScript的任何先验知识。
标准化时间
DateTime是一个非常特定的时间点。让我们考虑一下。在我撰写本文时, 笔记本电脑上的时钟显示7月21日下午1点29分。这就是我们所说的”当地时间”, 即我在周围的挂钟和手表上看到的时间。
给我或几分钟, 如果我问我的朋友在下午3:00在附近的咖啡馆见我, 我可以期望大约在那个时候见到她。同样, 如果我说例如”让我们在一个半小时内见面”, 也不会造成任何混乱。我们通常以这种方式与居住在同一城市或时区的人们谈论时间。
让我们考虑另一种情况-我想告诉一个居住在瑞典的朋友, 我想在下午5点与他交谈。我给他发了一条消息”嗨, 安东, 我们下午5点谈谈”。我立即收到”你的时间还是我的时间?”的回复。
安东告诉我, 他住在中欧时区UTC + 01:00。我住在UTC + 5:45。这意味着当我居住的时间是下午5点时, 正是11:15UTC转换为乌普萨拉的12:15, 对我们俩来说都是完美的。
另外, 请注意时区(欧洲中部时间)和时区偏移量(UTC + 05:45)之间的时差。各国出于政治原因也可以决定更改夏令时的时区偏移量。
相对于用户和相对于普遍接受的标准, 管理两个不同时间版本的问题很难解决, 在精度至关重要的编程世界中, 甚至一秒钟的时间也可以产生巨大的变化, 这一点尤其困难。解决这些问题的第一步是在UTC中存储DateTime。
格式标准化
标准化时间很棒, 因为我只需要存储UTC时间, 而且只要我知道用户的时区, 就可以随时将其转换为他们的时间。相反, 如果我知道用户的本地时间并知道他们的时区, 则可以将其转换为UTC。
但是日期和时间可以用许多不同的格式指定。对于日期, 你可以输入” 7月30日”或” 7月30日”或” 7/30″(或30/7, 具体取决于你的住所)。现在, 你可以输入” 9:30 pm”或” 2130″。
全世界的科学家齐心协力解决这个问题, 并决定采用一种格式来描述我们程序员真正喜欢的时间, 因为它简短, 精确且有效。我们喜欢将其称为ISO日期格式, 它是ISO-8601扩展格式的简化版本, 看起来像这样:
对于00:00或UTC, 我们改用” Z”, 这表示Zulu时间, UTC的另一个名称。
JavaScript中的日期处理和算术
在开始最佳实践之前, 我们将学习使用JavaScript进行日期操作以掌握语法和一般概念。尽管我们使用JavaScript, 但是你可以轻松地使这些信息适应你喜欢的编程语言。
我们将使用日期算法来解决大多数开发人员遇到的与日期相关的常见问题。
我的目标是让你轻松地从字符串创建日期对象并从其中提取组件。这是日期库可以为你提供帮助的东西, 但是总要更好地了解它是如何在后台进行的。
一旦弄清了日期/时间, 我们就可以更轻松地思考我们面临的问题, 提取最佳实践并继续前进。如果你想跳到最佳做法, 请随时这样做, 但是我强烈建议你至少略过下面的日期算术部分。
JavaScript日期对象
编程语言包含有用的构造, 以使我们的生活更轻松。 JavaScript Date对象就是这样的一件事。它提供了方便的方法来获取当前日期和时间, 将日期存储在变量中, 执行日期算术并根据用户的区域设置格式化日期。
由于浏览器实现之间的差异以及对DayLight Savings Time(DST)的不正确处理, 不建议为任务关键型应用程序依赖Date对象, 你可能应该使用类似于moment的DateTime库。
但是出于教育目的, 我们将使用Date()对象提供的方法来学习JavaScript如何处理DateTime。
获取当前日期
var currentDate = new Date();
如果你没有将任何内容传递给Date构造函数, 则返回的date对象将包含当前日期和时间。
然后, 可以将其格式化为仅提取日期部分, 如下所示:
var currentDate = new Date();
var date = currentDate.getDate();
var month = currentDate.getMonth(); //Be careful! January is 0 not 1
var year = currentDate.getFullYear();
var dateString = date + "-" +(month + 1) + "-" + year;
获取当前时间戳
如果要获取当前时间戳, 则可以创建一个新的Date对象并使用getTime()方法。
var date = new Date();
var timestamp = date.getTime();
在JavaScript中, 时间戳是自1970年1月1日以来经过的毫秒数。
如果你不打算支持<IE8, 则可以使用Date.now()直接获取时间戳, 而不必创建新的Date对象。
解析日期
将字符串转换为JavaScript日期对象的方式不同。
Date对象的构造函数接受多种日期格式:
var date = new Date("Wed, 27 July 2016 13:30:00");
var date = new Date("Wed, 27 July 2016 07:45:00 GMT");
var date = new Date("27 July 2016 13:30:00 GMT+05:45");
请注意, 你不需要包括星期几, 因为JS可以确定任何日期的星期几。
你还可以将年, 月, 日, 小时, 分钟和秒作为单独的参数传递:
var date = new Date(2016, 6, 27, 13, 30, 0);
当然, 你始终可以使用ISO日期格式:
var date = new Date("2016-07-27T07:45:00Z");
但是, 如果你未明确提供时区, 则可能会遇到麻烦!
var date = new Date("25 July 2016") // or
var date = new Date("July 25, 2016")
给你当地时间2016年7月25日00:00:00。
如果使用ISO格式, 即使你仅提供日期而不提供时间和时区, 它也会自动将时区作为UTC。
这意味着:
new Date("25 July 2016").getTime() !== new Date("2016-07-25").getTime()
new Date("2016-07-25").getTime() === new Date("2016-07-25T00:00:00Z").getTime()
格式化日期
日期格式在Javascript中更难, 因为它没有标准的日期格式功能, 例如Python或PHP中的strftime。
在PHP中, 函数strftime(” Today is%b%d%Y%X”, mktime(5, 10, 0, 12, 30, 99))为你提供今天是1999年12月30日05:10:00。
你可以使用不同的字母组合(以”%”开头)来获取不同格式的日期。
如果你确定要使用的格式, 最好使用上面学习的JavaScript函数提取单个位并自己创建一个字符串。
var currentDate = new Date();
var date = currentDate.getDate();
var month = currentDate.getMonth();
var year = currentDate.getFullYear();
我们可以使用月/日/年格式获取日期
var monthDateYear = (month+1) + "/" + date + "/" + year;
该解决方案的问题在于, 由于某些月份和日期是个位数, 而另一些则是两位数, 因此日期长度可能不一致。例如, 如果你在表格列中显示日期, 因为日期未对齐, 则可能会出现问题。
我们可以使用添加前导0的”填充”功能来解决此问题。
function pad(n) {
return n<10 ? '0'+n : n;
}
现在, 使用以下命令以MM / DD / YYYY格式获取正确的日期:
var mmddyyyy = pad(month + 1) + "/" + pad(date) + "/" + year;
如果要改为DD-MM-YYYY, 则过程类似:
var ddmmyyyy = pad(date) + "-" + pad(month + 1) + "-" + year;
让我们先付诸表决, 然后尝试以”月份日期, 年份”格式打印日期。我们将需要一个月索引到名称的映射:
var monthNames = [
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
];
var dateWithFullMonthName = monthNames[month] + " " + pad(date) + ", " + year;
有些人喜欢将日期显示为2013年1月1日。没问题, 我们需要的是一个辅助函数序数, 该序数返回1代表1、12代表12、103代表103等, 其余的很简单:
var ordinalDate = ordinal(date) + " " + monthNames[month] + ", " + year;
很容易从date对象确定星期几, 因此我们将其添加到:
var daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
ordinalDateWithDayOfWeek = daysOfWeek[currentDate.getDay()] + ", " + ordinalDate;
这里最重要的是, 一旦你从日期中提取了数字, 那么格式主要与字符串有关。
更改日期格式
一旦你知道如何解析日期并设置日期格式, 将日期从一种格式更改为另一种格式, 只需将两者结合即可。
例如, 如果你的日期格式为2013年7月21日, 并且想要将格式更改为2013年7月21日, 则可以这样实现:
var myDate = new Date("Jul 21, 2013");
var date = myDate.getDate();
var month = myDate.getMonth();
var year = myDate.getFullYear();
function pad(n) {
return n<10 ? '0'+n : n
}
var ddmmyyyy = pad(date) + "-" + pad(month + 1) + "-" + year;
使用JavaScript Date对象的本地化功能
我们上面讨论的日期格式设置方法应可在大多数应用程序中使用, 但是, 如果你确实想对日期格式进行本地化, 建议你使用Date对象的toLocaleDateString()方法。
var today = new Date().toLocaleDateString('en-GB', {
day : 'numeric', month : 'short', year : 'numeric'
})
给我们类似” 2016年7月26日”的信息。
将语言环境更改为” en-US”会显示” 2016年7月26日”。请注意格式如何更改, 但是显示选项仍然保持不变。太棒了吧?
始终通过格式设置选项是一个好习惯, 即使你的计算机上的输出看起来不错。这可以保护UI避免使用长月份名称过长的意外区域设置, 或由于名称短而显得笨拙。
如果我想要整个月为” July”, 我要做的就是将选项中的month参数更改为” long”。 Javascript为我处理了一切。对于美国英语, 我现在是2016年7月26日。
如果你希望浏览器自动使用用户的语言环境, 则可以将” undefined”作为第一个参数。
如果你想显示日期的数字版本, 并且不想大惊小怪, 请针对不同的语言环境使用MM / DD / YYYY与DD / MM / YYYY进行比较, 建议采取以下简单解决方案:
var today = new Date().toLocaleDateString(undefined, {
day:'numeric', month: 'numeric', year: 'numeric'
})
在我的计算机上, 这将输出” 7/26/2016″。如果要确保月份和日期有两位数字, 只需更改选项。
var today = new Date().toLocaleDateString(undefined, {
day: '2-digit', month: '2-digit', year: 'numeric'
})
输出为” 07/26/2016″。甜!
你还可以使用其他一些相关功能来本地化时间和日期的显示方式:
now.toLocaleTimeString() | ” 4:21:38 AM” | 显示唯一时间的本地化版本 |
now.toLocaleTimeString(未定义, {小时:” 2位数字”, 分钟:” 2位数字”, 秒:” 2位数字”}) | ” 04:21:38 AM” | 根据提供的选项显示本地化时间 |
now.toLocaleString() | ” 2016年7月22日, 上午4:21:38″ | 显示用户所在地区的日期和时间 |
now.toLocaleString(未定义, {日期:”数字”, 月份:”数字”, 年份:”数字”, 小时:” 2位数”, 分钟:” 2位数”, }) | ” 2016/7 / 22, 04:21 AM” | 根据提供的选项显示本地化的日期和时间 |
计算相对日期
下面是向JavaScript日期添加20天的示例(例如, 计算出已知日期之后20天的日期):
var date = new Date("July 20, 2016 15:00:00");
var nextDate = date.getDate() + 20;
date.setDate(nextDate);
var newDate = date.toLocaleString();
现在, 原始日期对象表示7月20日之后20天的日期, 而newDate包含表示该日期的本地化字符串。在我的浏览器中, newDate包含” 2016年8月9日, 下午3:00:00″。
比较日期
与日期相关的所有其他内容一样, 比较日期也有其自身的陷阱。
首先, 我们需要创建日期对象。幸运的是, <, >, <=和> =都能正常工作。因此, 比较2014年7月19日和2014年7月18日很容易:
var date1 = new Date("July 19, 2014");
var date2 = new Date("July 28, 2014");
if(date1 > date2) {
console.log("First date is more recent");
} else {
console.log("Second date is more recent");
}
检查相等性比较棘手, 因为代表相同日期的两个日期对象仍然是两个不同的日期对象, 并且将不相等。比较日期字符串不是一个好主意, 因为例如” 2014年7月20日”和” 2014年7月20日”代表相同的日期, 但是具有不同的字符串表示形式。下面的代码段说明了第一点:
var date1 = new Date("June 10, 2003");
var date2 = new Date(date1);
var result = date1 == date2 ? "equal" : "not equal";
console.log(result);
可变结果的值将为”不相等”。
可以通过如下比较日期的整数等效项(它们的时间戳)来解决此特殊情况:
date1.getTime() == date2.getTime()
我在很多地方都看到过此示例, 但我不喜欢它, 因为通常你不会从另一个日期对象创建日期对象。因此, 我认为该示例仅从学术角度而言很重要。另外, 这要求两个Date对象都引用完全相同的秒, 而你可能只想知道它们是否引用同一天, 小时或分钟。
让我们看一个更实际的例子。你正在尝试比较用户输入的生日是否与从API获得的幸运日期相同。
var userEnteredDateString = "12/20/1989"; // MM/DD/YY format
var dateStringFromAPI = "1989-12-20T00:00:00Z";
var userEnteredDate = new Date(userEnteredDateString)
var dateFromAPI = new Date(dateStringFromAPI);
var result = (userEnteredDate.getTime() == dateFromAPI.getTime());
if(result === true) {
transferOneMillionDollarsToUserAccount();
} else {
doNothing();
}
两者都表示同一个日期, 但是很遗憾, 你的用户将无法获得数百万美元。
这就是问题所在:JavaScript始终将时区假定为浏览器提供的时区, 除非另有明确指定。
对我来说, 这意味着新的日期(” 12/20/1989″)将创建一个日期1989-12-20T00:00:00 + 5:45或1989-12-19T18:15:00Z, 该日期与1989-12-20T00:00:00Z在时间戳方面。
无法仅更改现有日期对象的时区, 因此我们的目标是现在创建一个新的日期对象, 但要使用UTC而不是本地时区。
创建日期对象时, 我们将忽略用户的时区并使用UTC。有两种方法可以做到这一点:
- 从用户输入日期创建ISO格式的日期字符串, 并使用它来创建日期对象。使用有效的ISO日期格式创建日期对象, 同时使UTC vs local的意图非常明确。
var userEnteredDate = "12/20/1989";
var parts = userEnteredDate.split("/");
var userEnteredDateISO = parts[2] + "-" + parts[0] + "-" + parts[1];
var userEnteredDateObj = new Date(userEnteredDateISO + "T00:00:00Z");
var dateFromAPI = new Date("1989-12-20T00:00:00Z");
var result = userEnteredDateObj.getTime() == dateFromAPI.getTime();
如果你不指定时间, 则该方法也适用, 因为该时间默认为午夜(即00:00:00Z):
var userEnteredDate = new Date("1989-12-20");
var dateFromAPI = new Date("1989-12-20T00:00:00Z");
var result = userEnteredDate.getTime() == dateFromAPI.getTime();
切记:如果为日期构造函数传递了正确的ISO日期格式为YYYY-MM-DD的字符串, 它将自动采用UTC。
- JavaScript提供了一个简洁的Date.UTC()函数, 你可以使用该函数获取日期的UTC时间戳。我们从日期中提取组件并将它们传递给函数。
var userEnteredDate = new Date("12/20/1989");
var userEnteredDateTimeStamp = Date.UTC(userEnteredDate.getFullYear(), userEnteredDate.getMonth(), userEnteredDate.getDate(), 0, 0, 0);
var dateFromAPI = new Date("1989-12-20T00:00:00Z");
var result = userEnteredDateTimeStamp == dateFromAPI.getTime();
...
找出两个日期之间的差异
你会遇到的常见情况是找到两个日期之间的差异。
我们讨论两个用例:
查找两个日期之间的天数
将两个日期都转换为UTC时间戳, 找到以微秒为单位的差并找到等效的天数。
var dateFromAPI = "2016-02-10T00:00:00Z";
var now = new Date();
var datefromAPITimeStamp = (new Date(dateFromAPI)).getTime();
var nowTimeStamp = now.getTime();
var microSecondsDiff = Math.abs(datefromAPITimeStamp - nowTimeStamp );
// Number of milliseconds per day =
// 24 hrs/day * 60 minutes/hour * 60 seconds/minute * 1000 msecs/second
var daysDiff = Math.floor(microSecondsDiff/(1000 * 60 * 60 * 24));
console.log(daysDiff);
从用户的出生日期开始查找其年龄
var birthDateFromAPI = "12/10/1989";
注意:我们有非标准格式。阅读API文档以确定这是10月12日还是12月10日。相应地更改为ISO格式。
var parts = birthDateFromAPI.split("/");
var birthDateISO = parts[2] + "-" + parts[0] + "-" + parts[1];
var birthDate = new Date(birthDateISO);
var today = new Date();
var age = today.getFullYear() - birthDate.getFullYear();
if(today.getMonth() < birthDate.getMonth()) {
age--;
}
if(today.getMonth() == birthDate.getMonth() && today.getDate() < birthDate.getDate()) {
age--;
}
我知道有更多简洁的方法可以编写此代码, 但是由于逻辑的明确性, 我喜欢以此方式编写。
避免约会地狱的建议
现在我们对日期算术已经很熟悉了, 我们可以理解要遵循的最佳实践以及遵循这些实践的原因。
从用户获取DateTime
如果要从用户那里获取日期和时间, 则很可能是在寻找他们的本地DateTime。我们在日期算术部分中看到, Date构造函数可以通过许多不同的方式接受日期。
为了消除任何混乱, 我始终建议你使用新的Date(年, 月, 日, 小时, 分钟, 秒, 毫秒)格式创建日期, 即使你已经具有有效的可解析格式的日期也是如此。如果你团队中的所有程序员都遵循此简单规则, 则从长远来看, 维护代码将非常容易, 因为它与Date构造函数一样明确。
最酷的部分是, 你可以使用允许你省略后四个参数(如果为零)中的任何一个的变体。即new Date(2012, 10, 12)与new Date(2012, 10, 12, 0, 0, 0, 0)相同, 因为未指定的参数默认为零。
例如, 如果使用的日期和时间选择器为你提供日期2012-10-12和时间12:30, 则可以提取零件并创建一个新的Date对象, 如下所示:
var dateFromPicker = "2012-10-12";
var timeFromPicker = "12:30";
var dateParts = dateFromPicker.split("-");
var timeParts = timeFromPicker.split(":");
var localDate = new Date(dateParts[0], dateParts[1]-1, dateParts[2], timeParts[0], timeParts[1]);
除非它采用ISO日期格式, 否则请尝试避免从字符串创建日期。请改用Date(年, 月, 日, 时, 分, 秒, 微秒)方法。
仅获取日期
如果仅获取日期(例如, 用户的生日), 则最好将格式转换为有效的ISO日期格式, 以消除会导致日期转换为UTC时向前或向后移动的任何时区信息。例如:
var dateFromPicker = "12/20/2012";
var dateParts = dateFromPicker.split("/");
var ISODate = dateParts[2] + "-" + dateParts[0] + "-" + dateParts[1];
var birthDate = new Date(ISODate).toISOString();
万一你忘记了, 如果你使用输入的无效ISO日期格式(YYYY-MM-DD)创建了Date对象, 它将默认为UTC而不是浏览器的时区。
保存日期
始终将日期时间存储在UTC中。始终将ISO日期字符串或时间戳发送到后端。
在试图向用户显示正确的本地时间的痛苦经历之后, 几代计算机程序员已经意识到了这个简单的事实。将本地时间存储在后端是个坏主意, 最好让浏览器在前端处理到本地时间的转换。
同样, 很明显, 你绝不应向后端发送诸如” 1989年7月20日12:10 pm”之类的DateTime字符串。即使你也发送了时区, 你也会加大其他程序员理解你的意图并正确解析和存储日期的工作量。
使用Date对象的toISOString()或toJSON()方法将本地DateTime转换为UTC。
var dateFromUI = "12-13-2012";
var timeFromUI = "10:20";
var dateParts = dateFromUI.split("-");
var timeParts = timefromUI.split(":");
var date = new Date(dateParts[2], dateParts[0]-1, dateParts[1], timeParts[0], timeParts[1]);
var dateISO = date.toISOString();
$.post("http://example.com/", {date: dateISO}, ...)
显示日期和时间
- 从REST API获取时间戳或ISO格式的日期。
- 创建一个日期对象。
- 使用toLocaleString()或toLocaleDateString()和toLocaleTimeString()方法或日期数据库(例如moment.js)显示本地时间。
var dateFromAPI = "2016-01-02T12:30:00Z";
var localDate = new Date(dateFromAPI);
var localDateString = localDate.toLocaleDateString(undefined, {
day : 'numeric', month : 'short', year : 'numeric'
})
var localTimeString = localDate.toLocaleTimeString(undefined, {
hour: '2-digit', minute: '2-digit', second: '2-digit'
})
你什么时候也应该存储本地时间?
“有时, 重要的是要知道事件发生的时区, 并将其转换为单个时区将无法避免地消除该信息。
如果你要进行市场推广, 并且想知道哪些客户在午餐时间下了订单, 那么看起来似乎已经在格林尼治标准时间中午下达的订单实际上并没有在纽约的早餐中提供任何帮助。”
如果遇到这种情况, 那么节省本地时间也是比较明智的。像往常一样, 我们想以ISO格式创建日期, 但是我们必须首先找到时区偏移量。
Date对象的getTimeZoneOffset()函数告诉我们, 当添加到给定的本地时间后, 该分钟数等于等效的UTC时间。我建议将其转换为(+-)hh:mm格式, 因为这样可以更明显地看出它是时区偏移量。
var now = new Date();
var tz = now.getTimezoneOffset();
对于我的时区+05:45, 我得到-345, 这不仅是相反的符号, 而且-345之类的数字可能完全困扰着后端开发人员。因此, 我们将其转换为+05:45。
var sign = tz > 0 ? "-" : "+";
var hours = pad(Math.floor(Math.abs(tz)/60));
var minutes = pad(Math.abs(tz)%60);
var tzOffset = sign + hours + ":" + minutes;
现在, 我们获取其余的值, 并创建一个表示本地DateTime的有效ISO字符串。
var localDateTime = now.getFullYear() +
"-" +
pad(now.getMonth()+1) +
"-" +
pad(now.getDate()) +
"T" +
pad(now.getHours()) +
":" +
pad(now.getMinutes()) +
":" +
pad(now.getSeconds());
如果需要, 可以将utc和本地日期包装在一个对象中。
var eventDate = {
utc: now.toISOString(), local: localDateTime, tzOffset: tzOffset
}
现在, 在后端, 如果你想确定事件是否在当地时间中午之前发生, 则可以解析日期并只需使用getHours()函数。
var localDateString = eventDate.local;
var localDate = new Date(localDateString);
if(localDate.getHours() < 12) {
console.log("Event happened before noon local time");
}
我们此处未使用tzOffset, 但仍将其存储, 因为将来出于调试目的可能会需要它。你实际上可以只发送时区偏移量和UTC时间。但是我也喜欢存储本地时间, 因为你最终将不得不将日期存储在数据库中, 并且将本地时间单独存储可以使你直接基于字段进行查询, 而不必执行计算来获取本地日期。
服务器和数据库配置
始终将服务器和数据库配置为使用GMT / UTC时区。
我们已经看到时区转换可以带来多大的痛苦, 尤其是在意外的情况下。始终发送UTC DateTime并将服务器配置为UTC时区可以使你的生活更轻松。你的后端代码将变得更加简单和整洁, 因为它不需要进行任何时区转换。来自世界各地服务器的DateTime数据可以轻松进行比较和排序。
后端中的大多数代码都应该能够假定服务器的时区为UTC(但仍然应进行检查以确保正确)。
总结
日期操纵是一个难题, 特别是对于那些不太了解基本概念的初学者。网络上现有的大多数资料要么过于学术化(过多地介绍了时区和DST的怪异细节, 而这些细节对于大多数程序员而言都没有用), 或者过于零散(使用此代码, 它将起作用)。
在本文中, 我尝试提供有关DateTime如何工作以及如何在代码中操作DateTime的全面指南-使用实际示例说明概念, 而无需假设你先前对DateTime或JavaScript有任何了解。我希望你觉得这有帮助。
如果你有任何疑问或反馈, 请在评论中告诉我, 我们很乐意答复。
相关:Buggy JavaScript代码:JavaScript开发人员最常犯的10个错误
评论前必须登录!
注册