网站做微信链接,常州建站价格,html实例,网站怎么做分类聚合文章目录 日期和时间创建访问日期组件设置日期组件自动校准#xff08;Autocorrection#xff09;日期转化为数字#xff0c;日期差值Date.now()基准测试#xff08;Benchmarking#xff09;对字符串调用 Date.parse总结✅任务创建日期显示星期数欧洲的星期表示方法许多天… 文章目录 日期和时间创建访问日期组件设置日期组件自动校准Autocorrection日期转化为数字日期差值Date.now()基准测试Benchmarking对字符串调用 Date.parse总结✅任务创建日期显示星期数欧洲的星期表示方法许多天之前是哪个月几号某月的最后一天今天过去了多少秒距离明天还有多少秒格式化相对日期 日期和时间
让我们来学习一个新的内建对象日期Date。该对象存储日期和时间并提供了日期/时间的管理方法。
我们可以使用它来存储创建/修改时间测量时间或者仅用来打印当前时间。
创建
调用 new Date() 来创建一个新的 Date 对象。在调用时可以带有一些参数如下所示 new Date() 不带参数 —— 创建一个表示当前日期和时间的 Date 对象let now new Date(); alert( now ); // 显示当前的日期/时间 new Date(milliseconds) 创建一个 Date 对象其时间等于 1970 年 1 月 1 日 UTC0 之后经过的毫秒数1/1000 秒。// 0 表示 01.01.1970 UTC0 let Jan01_1970 new Date(0); alert( Jan01_1970 ); // 现在增加 24 小时得到 02.01.1970 UTC0 let Jan02_1970 new Date(24 * 3600 * 1000); alert( Jan02_1970 );传入的整数参数代表的是自 1970-01-01 00:00:00 以来经过的毫秒数该整数被称为 时间戳。这是一种日期的轻量级数字表示形式。我们通常使用 new Date(timestamp) 通过时间戳来创建日期并可以使用 date.getTime() 将现有的 Date 对象转化为时间戳下文会讲到。在 01.01.1970 之前的日期带有负的时间戳例如// 31 Dec 1969 let Dec31_1969 new Date(-24 * 3600 * 1000); alert( Dec31_1969 ); new Date(datestring) 如果只有一个参数并且是字符串那么它会被自动解析。该算法与 Date.parse 所使用的算法相同将在下文中进行介绍。let date new Date(2017-01-26); alert(date); // 未指定具体时间所以假定时间为格林尼治标准时间GMT的午夜零点 // 并根据运行代码时的用户的时区进行调整 // 因此结果可能是 // Thu Jan 26 2017 11:00:00 GMT1100 (Australian Eastern Daylight Time) // 或 // Wed Jan 25 2017 16:00:00 GMT-0800 (Pacific Standard Time) new Date(year, month, date, hours, minutes, seconds, ms) 使用当前时区中的给定组件创建日期。只有前两个参数是必须的。year 必须是四位数2013 是合法的98 是不合法的。month 计数从 0一月开始到 11十二月结束。date 是当月的具体某一天如果缺失则为默认值 1。如果 hours/minutes/seconds/ms 缺失则均为默认值 0。例如new Date(2011, 0, 1, 0, 0, 0, 0); // 1 Jan 2011, 00:00:00 new Date(2011, 0, 1); // 同样时分秒等均为默认值 0时间度量最大精确到 1 毫秒1/1000 秒let date new Date(2011, 0, 1, 2, 3, 4, 567); alert( date ); // 1.01.2011, 02:03:04.567
访问日期组件
从 Date 对象中访问年、月等信息有多种方式 getFullYear() 获取年份4 位数 getMonth() 获取月份从 0 到 11。 getDate() 获取当月的具体日期从 1 到 31这个方法名称可能看起来有些令人疑惑。 getHours()getMinutes()getSeconds()getMilliseconds() 获取相应的时间组件。 ⚠️不是 getYear()而是 getFullYear() 很多 JavaScript 引擎都实现了一个非标准化的方法 getYear()。不推荐使用这个方法。它有时候可能会返回 2 位的年份信息。永远不要使用它。要获取年份就使用 getFullYear()。 另外我们还可以获取一周中的第几天 getDay() 获取一周中的第几天从 0星期日到 6星期六。第一天始终是星期日在某些国家可能不是这样的习惯但是这不能被改变。
以上的所有方法返回的组件都是基于当地时区的。
当然也有与当地时区的 UTC 对应项它们会返回基于 UTC0 时区的日、月、年等getUTCFullYear()getUTCMonth()getUTCDay()。只需要在 get 之后插入 UTC 即可。
如果你当地时区相对于 UTC 有偏移那么下面代码会显示不同的小时数
// 当前日期
let date new Date();// 当地时区的小时数
alert( date.getHours() );// 在 UTC0 时区的小时数非夏令时的伦敦时间
alert( date.getUTCHours() );除了上述给定的方法还有两个没有 UTC 变体的特殊方法 getTime() 返回日期的时间戳 —— 从 1970-1-1 00:00:00 UTC0 开始到现在所经过的毫秒数。 getTimezoneOffset() 返回 UTC 与本地时区之间的时差以分钟为单位// 如果你在时区 UTC-1输出 60 // 如果你在时区 UTC3输出 -180 alert( new Date().getTimezoneOffset() );
设置日期组件
下列方法可以设置日期/时间组件
setFullYear(year, [month\], [date])setMonth(month, [date\])setDate(date)setHours(hour, [min\], [sec], [ms])setMinutes(min, [sec\], [ms])setSeconds(sec, [ms\])setMilliseconds(ms)setTime(milliseconds)使用自 1970-01-01 00:00:00 UTC0 以来的毫秒数来设置整个日期
以上方法除了 setTime() 都有 UTC 变体例如setUTCHours()。
我们可以看到有些方法可以一次性设置多个组件比如 setHours。未提及的组件不会被修改。
举个例子
let today new Date();today.setHours(0);
alert(today); // 日期依然是今天但是小时数被改为了 0today.setHours(0, 0, 0, 0);
alert(today); // 日期依然是今天时间为 00:00:00。自动校准Autocorrection
自动校准 是 Date 对象的一个非常方便的特性。我们可以设置超范围的数值它会自动校准。
举个例子
let date new Date(2013, 0, 32); // 32 Jan 2013 ?!?
alert(date); // ……是 1st Feb 2013!超出范围的日期组件将会被自动分配。
假设我们要在日期 “28 Feb 2016” 上加 2 天。结果可能是 “2 Mar” 或 “1 Mar”因为存在闰年。但是我们不需要考虑这些只需要直接加 2 天剩下的 Date 对象会帮我们处理
let date new Date(2016, 1, 28);
date.setDate(date.getDate() 2);alert( date ); // 1 Mar 2016这个特性经常被用来获取给定时间段后的日期。例如我们想获取“现在 70 秒后”的日期
let date new Date();
date.setSeconds(date.getSeconds() 70);alert( date ); // 显示正确的日期信息我们还可以设置 0 甚至可以设置负值。例如
let date new Date(2016, 0, 2); // 2016 年 1 月 2 日date.setDate(1); // 设置为当月的第一天
alert( date );date.setDate(0); // 天数最小可以设置为 1所以这里设置的是上一月的最后一天
alert( date ); // 31 Dec 2015日期转化为数字日期差值
当 Date 对象被转化为数字时得到的是对应的时间戳与使用 date.getTime() 的结果相同
let date new Date();
alert(date); // 以毫秒为单位的数值与使用 date.getTime() 的结果相同有一个重要的副作用日期可以相减相减的结果是以毫秒为单位时间差。
这个作用可以用于时间测量
let start new Date(); // 开始测量时间// do the job
for (let i 0; i 100000; i) {let doSomething i * i * i;
}let end new Date(); // 结束测量时间alert( The loop took ${end - start} ms );Date.now()
如果我们仅仅想要测量时间间隔我们不需要 Date 对象。
有一个特殊的方法 Date.now()它会返回当前的时间戳。
它相当于 new Date().getTime()但它不会创建中间的 Date 对象。因此它更快而且不会对垃圾回收造成额外的压力。
这种方法很多时候因为方便又或是因性能方面的考虑而被采用例如使用 JavaScript 编写游戏或其他的特殊应用场景。
因此这样做可能会更好
let start Date.now(); // 从 1 Jan 1970 至今的时间戳// do the job
for (let i 0; i 100000; i) {let doSomething i * i * i;
}let end Date.now(); // 完成alert( The loop took ${end - start} ms ); // 相减的是时间戳而不是日期基准测试Benchmarking
在对一个很耗 CPU 性能的函数进行可靠的基准测试Benchmarking时我们需要谨慎一点。
例如我们想判断以下两个计算日期差值的函数哪个更快
这种性能测量通常称为“基准测试benchmark”。
// 我们有 date1 和 date2哪个函数会更快地返回两者的时间差
function diffSubtract(date1, date2) {return date2 - date1;
}// or
function diffGetTime(date1, date2) {return date2.getTime() - date1.getTime();
}这两个函数做的事情完全相同但是其中一个函数使用显式的 date.getTime() 来获取毫秒形式的日期另一个则依赖于“日期 — 数字”的转换。它们的结果是一样的。
那么哪个更快呢
首先想到的方法可能是连续运行两者很多次并计算所消耗的时间之差。就这个例子而言函数过于简单所以我们必须执行至少 100000 次。
让我们开始测量
function diffSubtract(date1, date2) {return date2 - date1;
}function diffGetTime(date1, date2) {return date2.getTime() - date1.getTime();
}function bench(f) {let date1 new Date(0);let date2 new Date();let start Date.now();for (let i 0; i 100000; i) f(date1, date2);return Date.now() - start;
}alert( Time of diffSubtract: bench(diffSubtract) ms );
alert( Time of diffGetTime: bench(diffGetTime) ms );看起来使用 getTime() 这种方式快得多这是因为它没有进行类型转换对引擎优化来说更加简单。
我们得到了结论但是这并不是一个很好的度量的例子。
想象一下当运行 bench(diffSubtract) 的同时CPU 还在并行处理其他事务并且这也会占用资源。然而运行 bench(diffGetTime) 的时候并行处理的事务完成了。
对于现代多进程操作系统来说这是一个非常常见的场景。
比起第二个函数第一个函数所能使用的 CPU 资源更少。这可能导致错误的结论。
为了得到更加可靠的度量整个度量测试包应该重新运行多次。
例如像下面的代码这样
function diffSubtract(date1, date2) {return date2 - date1;
}function diffGetTime(date1, date2) {return date2.getTime() - date1.getTime();
}function bench(f) {let date1 new Date(0);let date2 new Date();let start Date.now();for (let i 0; i 100000; i) f(date1, date2);return Date.now() - start;
}let time1 0;
let time2 0;// 交替运行 bench(diffSubtract) 和 bench(diffGetTime) 各 10 次
for (let i 0; i 10; i) {time1 bench(diffSubtract);time2 bench(diffGetTime);
}alert( Total time for diffSubtract: time1 );
alert( Total time for diffGetTime: time2 );现代的 JavaScript 引擎的先进优化策略只对执行很多次的 “hot code” 有效对于执行很少次数的代码没有必要优化。因此在上面的例子中第一次执行的优化程度不高。我们可能需要增加一个预热步骤
// 在主循环中增加预热环节
bench(diffSubtract);
bench(diffGetTime);// 开始度量
for (let i 0; i 10; i) {time1 bench(diffSubtract);time2 bench(diffGetTime);
}⚠️进行微型基准测试时要小心 现代的 JavaScript 引擎执行了很多优化。与正常编写的代码相比它们可能会改变“人为编写的专用于测试的代码”的执行流程特别是在我们对很小的代码片段进行基准测试时例如某个运算符或内建函数的工作方式。因此为了深入理解性能问题请学习 JavaScript 引擎的工作原理。在那之后你或许再也不需要进行微型基准测试了。 http://mrale.ph 提供了很多 V8 引擎相关的文章。 对字符串调用 Date.parse
Date.parse(str) 方法可以从一个字符串中读取日期。
字符串的格式应该为YYYY-MM-DDTHH:mm:ss.sssZ其中
YYYY-MM-DD —— 日期年-月-日。字符 T 是一个分隔符。HH:mm:ss.sss —— 时间小时分钟秒毫秒。可选字符 Z 为 -hh:mm 格式的时区。单个字符 Z 代表 UTC0 时区。
简短形式也是可以的比如 YYYY-MM-DD 或 YYYY-MM甚至可以是 YYYY。
Date.parse(str) 调用会解析给定格式的字符串并返回时间戳自 1970-01-01 00:00:00 起所经过的毫秒数。如果给定字符串的格式不正确则返回 NaN。
举个例子
let ms Date.parse(2012-01-26T13:51:50.417-07:00);alert(ms); // 1327611110417 (时间戳)我们可以通过时间戳来立即创建一个 new Date 对象
let date new Date( Date.parse(2012-01-26T13:51:50.417-07:00) );alert(date);总结
在 JavaScript 中日期和时间使用 Date 对象来表示。我们不能单独创建日期或时间Date 对象总是同时创建两者。月份从 0 开始计数对一月是 0。一周中的某一天 getDay() 同样从 0 开始计算0 代表星期日。当设置了超出范围的组件时Date 会进行自动校准。这一点对于日/月/小时的加减很有用。日期可以相减得到的是以毫秒表示的两者的差值。因为当 Date 被转换为数字时Date 对象会被转换为时间戳。使用 Date.now() 可以更快地获取当前时间的时间戳。
和其他系统不同JavaScript 中时间戳以毫秒为单位而不是秒。
有时我们需要更加精准的时间度量。JavaScript 自身并没有测量微秒的方法百万分之一秒但大多数运行环境会提供。例如浏览器有 performance.now() 方法来给出从页面加载开始的以毫秒为单位的微秒数精确到毫秒的小数点后三位
alert(Loading started ${performance.now()}ms ago);
// 类似于 Loading started 34731.26000000001ms ago
// .26 表示的是微秒260 微秒
// 小数点后超过 3 位的数字是精度错误只有前三位数字是正确的Node.js 可以通过 microtime 模块或使用其他方法。从技术上讲几乎所有的设备和环境都允许获取更高精度的时间数值只不过不是使用 Date 对象。
✅任务
创建日期
重要程度5️⃣
创建一个 Date 对象日期是Feb 20, 2012, 3:12am。时区是当地时区。
使用 alert 显示结果。
解决方案
new Date 构造函数默认使用本地时区。所以唯一需要牢记的就是月份从 0 开始计数。
所以二月对应的数值是 1。
这是一个以数字作为日期参数的示例
// new Date(year, month, date, hour, minute, second, millisecond)
let d1 new Date(2012, 1, 20, 3, 12);
alert( d1 );我们还可以从字符串创建日期像这样
// new Date(datestring)
let d2 new Date(February 20, 2012 03:12:00);
alert( d2 );显示星期数
重要程度5️⃣
编写一个函数 getWeekDay(date) 以短格式来显示一个日期的星期数‘MO’‘TU’‘WE’‘TH’‘FR’‘SA’‘SU’。
例如
let date new Date(2012, 0, 3); // 3 Jan 2012
alert( getWeekDay(date) ); // 应该输出 TU打开带有测试的沙箱。 解决方案 date.getDay() 方法返回从星期日开始的星期数。 我们创建一个关于星期的数组这样我们就可以通过编号获取正确的日期名称 function getWeekDay(date) {
let days [SU, MO, TU, WE, TH, FR, SA];return days[date.getDay()];
}let date new Date(2014, 0, 3); // 3 Jan 2014
alert( getWeekDay(date) ); // FR使用沙箱的测试功能打开解决方案。 欧洲的星期表示方法
重要程度5️⃣
欧洲国家的星期计算是从星期一数字 1开始的然后是星期二数字 2直到星期日数字 7。编写一个函数 getLocalDay(date)并返回日期的欧洲式星期数。
let date new Date(2012, 0, 3); // 3 Jan 2012
alert( getLocalDay(date) ); // 星期二应该显示 2打开带有测试的沙箱。 解决方案 function getLocalDay(date) {let day date.getDay();if (day 0) { // weekday 0 (sunday) is 7 in europeanday 7;
}return day;
}使用沙箱的测试功能打开解决方案。 许多天之前是哪个月几号
重要程度4️⃣
写一个函数 getDateAgo(date, days)返回特定日期 date 往前 days 天是哪个月的哪一天。
例如假设今天是 20 号那么 getDateAgo(new Date(), 1) 的结果应该是 19 号getDateAgo(new Date(), 2) 的结果应该是 18 号。
跨月、年也应该是正确输出
let date new Date(2015, 0, 2);alert( getDateAgo(date, 1) ); // 1, (1 Jan 2015)
alert( getDateAgo(date, 2) ); // 31, (31 Dec 2014)
alert( getDateAgo(date, 365) ); // 2, (2 Jan 2014)P.S. 函数不应该修改给定的 date 值。
打开带有测试的沙箱。 解决方案 思路很简单从 date 中减去给定的天数 function getDateAgo(date, days) {
date.setDate(date.getDate() - days);
return date.getDate();
}……但是函数不能修改 date。这一点很重要因为我们提供日期的外部代码不希望它被修改。 要实现这一点我们可以复制这个日期就像这样 function getDateAgo(date, days) {
let dateCopy new Date(date);dateCopy.setDate(date.getDate() - days);
return dateCopy.getDate();
}let date new Date(2015, 0, 2);alert( getDateAgo(date, 1) ); // 1, (1 Jan 2015)
alert( getDateAgo(date, 2) ); // 31, (31 Dec 2014)
alert( getDateAgo(date, 365) ); // 2, (2 Jan 2014)使用沙箱的测试功能打开解决方案。 某月的最后一天
重要程度5️⃣
写一个函数 getLastDayOfMonth(year, month) 返回 month 月的最后一天。有时候是 30有时是 31甚至在二月的时候会是 28/29。
参数
year —— 四位数的年份比如 2012。month —— 月份从 0 到 11。
举个例子getLastDayOfMonth(2012, 1) 29闰年二月
打开带有测试的沙箱。 解决方案 让我们使用下个月创建日期但将零作为天数day传递 function getLastDayOfMonth(year, month) {
let date new Date(year, month 1, 0);
return date.getDate();
}alert( getLastDayOfMonth(2012, 0) ); // 31
alert( getLastDayOfMonth(2012, 1) ); // 29
alert( getLastDayOfMonth(2013, 1) ); // 28通常日期从 1 开始但从技术上讲我们可以传递任何数字日期会自动进行调整。因此当我们传递 0 时它的意思是“一个月的第一天的前一天”换句话说“上个月的最后一天”。 使用沙箱的测试功能打开解决方案。 今天过去了多少秒
重要程度5️⃣
写一个函数 getSecondsToday()返回今天已经过去了多少秒
例如如果现在是 10:00 am并且没有夏令时转换那么
getSecondsToday() 36000 // (3600 * 10)该函数应该在任意一天都能正确运行。那意味着它不应具有“今天”的硬编码值。 解决方案 为获取秒数我们可以使用今天的日期和 00:00:00 这个时间创建一个日期然后使用当前时间减去该时间。 不同之处在于从今天之初开始算起的时间是以毫秒计算的我们应该将其除以 1000进而得到秒数 function getSecondsToday() {
let now new Date();// 使用当前的 day/month/year 创建一个对象
let today new Date(now.getFullYear(), now.getMonth(), now.getDate());let diff now - today; // ms difference
return Math.round(diff / 1000); // make seconds
}alert( getSecondsToday() );另一种解决方法是获取 hours/minutes/seconds然后把它们转换为秒数 function getSecondsToday() {
let d new Date();
return d.getHours() * 3600 d.getMinutes() * 60 d.getSeconds();
};alert( getSecondsToday() );距离明天还有多少秒
重要程度5️⃣
写一个函数 getSecondsToTomorrow()返回距离明天的秒数。
例如现在是 23:00那么
getSecondsToTomorrow() 3600P.S. 该函数应该在任意一天都能正确运行。那意味着它不应具有“今天”的硬编码值。 解决方案 为获取距离明天的毫秒数我们可以用“明天 00:00:00”这个日期减去当前的日期。 首先我们生成“明天”然后对其进行减法操作 function getSecondsToTomorrow() {
let now new Date();// tomorrow date
let tomorrow new Date(now.getFullYear(), now.getMonth(), now.getDate()1);let diff tomorrow - now; // difference in ms
return Math.round(diff / 1000); // convert to seconds
}另一种解法 function getSecondsToTomorrow() {
let now new Date();
let hour now.getHours();
let minutes now.getMinutes();
let seconds now.getSeconds();
let totalSecondsToday (hour * 60 minutes) * 60 seconds;
let totalSecondsInADay 86400;return totalSecondsInADay - totalSecondsToday;
}请注意很多国家有夏令时DST因此他们的一天可能有 23 小时或者 25 小时。我们对这些天数要区别对待。 格式化相对日期
重要程度4️⃣
写一个函数 formatDate(date)能够对 date 进行如下格式化
如果 date 距离现在不到 1 秒输出 right now。否则如果 date 距离现在不到 1 分钟输出 n sec. ago。否则如果不到 1 小时输出 m min. ago。否则以 DD.MM.YY HH:mm 格式输出完整日期。即day.month.year hours:minutes全部以两位数格式表示例如31.12.16 10:00。
举个例子
alert( formatDate(new Date(new Date - 1)) ); // right nowalert( formatDate(new Date(new Date - 30 * 1000)) ); // 30 sec. agoalert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // 5 min. ago// 昨天的日期例如 31.12.16 20:00
alert( formatDate(new Date(new Date - 86400 * 1000)) );打开带有测试的沙箱。 解决方案 为了获取 date 距离当前时间的间隔 —— 我们将两个日期相减。 function formatDate(date) {
let diff new Date() - date; // 以毫秒表示的差值if (diff 1000) { // 少于 1 秒return right now;
}let sec Math.floor(diff / 1000); // 将 diff 转换为秒if (sec 60) {return sec sec. ago;
}let min Math.floor(diff / 60000); // 将 diff 转换为分钟
if (min 60) {return min min. ago;
}// 格式化 date
// 将前置 0 加到一位数 day/month/hours/minutes 前
let d date;
d [0 d.getDate(),0 (d.getMonth() 1), d.getFullYear(),0 d.getHours(),0 d.getMinutes()
].map(component component.slice(-2)); // 得到每个组件的后两位// 将时间信息和日期组合在一起
return d.slice(0, 3).join(.) d.slice(3).join(:);
}alert( formatDate(new Date(new Date - 1)) ); // right nowalert( formatDate(new Date(new Date - 30 * 1000)) ); // 30 sec. agoalert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // 5 min. ago// 昨天的日期如31.12.2016 20:00
alert( formatDate(new Date(new Date - 86400 * 1000)) );另一种解法 function formatDate(date) {
let dayOfMonth date.getDate();
let month date.getMonth() 1;
let year date.getFullYear();
let hour date.getHours();
let minutes date.getMinutes();
let diffMs new Date() - date;
let diffSec Math.round(diffMs / 1000);
let diffMin diffSec / 60;
let diffHour diffMin / 60;// 格式化
year year.toString().slice(-2);
month month 10 ? 0 month : month;
dayOfMonth dayOfMonth 10 ? 0 dayOfMonth : dayOfMonth;
hour hour 10 ? 0 hour : hour;
minutes minutes 10 ? 0 minutes : minutes;if (diffSec 1) {return right now;
} else if (diffMin 1) {return ${diffSec} sec. ago
} else if (diffHour 1) {return ${diffMin} min. ago
} else {return ${dayOfMonth}.${month}.${year} ${hour}:${minutes}
}
}使用沙箱的测试功能打开解决方案。