文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

在 JavaScript中处理日期是一件非常让人头疼的事情。原生的日期方法往往是冗长且不一致的,这给开发人员带来很大的困惑。但现在,好消息来了。现在已经有不少库,能让处理日期变得不再那么痛苦。这些库之于 JavaScript 原生的日期方法,就好比 jQuery 之于原生 DOM API。

举个例子。这是一个对 Stack Overflow 上的一个问题—— how to get last day of the month的解答:

var t = new Date();
alert( new Date(t.getFullYear(), t.getMonth() + 1, 0, 23, 59, 59) );
第 1 段(可获 1.03 积分)

当然,这是有效的,但是并不是很明显,getMonth代表什么数字。现在相比之下,相当可读:

const today = new Date();
console.log( lastDayOfMonth(today) );

lastDayOfMonth方法是由 date-fns提供的,它是一种自动声明的综合工具集,用于在浏览器和Node.js中操纵JavaScript日期。

在本文中,我将向您展示如何使用date-fns来启动和运行。阅读后,您可以将其放入项目中,并利用其许多帮助方法轻松操纵日期。这将使代码像t.getMonth()1,0,23,59,59一样是过去的事情。日期FNS

第 2 段(可获 1.2 积分)

--广告--

那么,为什么不使用 Moment.js?

作者更多文章

Moment.js 是房间里的大象[译者注:大家都知道但不愿意讨论的东西]。毫无疑问,这个库已经成为 JavaScript 处理日期的标准。既然如此,为什么不使用它呢?我们为什么需要另一个 JavaScript 日期库?

根据 Sasha Koss,date-fns 的观点,Moment.js 天生就存在一些问题,正是这些问题促使它创造了 date-dns。Sasha 在 项目的 GitHub 页对此进行了解释,归结如下:

  • Moment.js 是可变的,这可能会导致缺陷。
  • 它具有复杂的面向对象的 API (这加剧了可变性问题)。
  • 其复杂的 API 带来大量性能开销。
  • 在使用 Webpack 将其打包在构建结果中时,会导致构建结果尺寸增长不少。
第 3 段(可获 1.79 积分)

我们拿 date-fns 来进行一个对比 (来自项目主页):

  • date-fns 是不可变的,总是返回新的日期,而不是修改传入的那个。
  • 它的 API 很简单。你做每件事都只需要一个函数。
  • 它很快。你的用户会有更好的用户体验。
  • 它是 Webpack 完美的伴侣。由于其每个文件一个函数的风格,你可以在打包时选择需要的部分而扔弃没用到的那些功能。

对于我来说,最为闪亮的特性是其易用性。在基于 Web 的项目中使用它,你可以从 CDN 获得 date-fns,将其添加到页面。接下来会有更多相关内容……

 

第 4 段(可获 1.54 积分)

安装

安装这个库的方法有许多种。

你可以通过 npm 安装:

npm install date-fns --save

或者通过 Yarn:

yarn add date-fns

或者通过 Bower:

bower install date-fns

或者从一个 CDN 引用:

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.28.5/date_fns.min.js"/>

如果你选择使用这种办法,请注意这个库是被命名在一个 dateFns 对象下,就好比是 jQuery 被命名在 $ 之下。

<script>
  console.log(
    dateFns.isToday(new Date())
  );
</script>

Date-fns 使用方法

下文假设你使用的是模块加载器,你可以只引入你需要的部分。以下例子教你如何 格式化日期

第 5 段(可获 0.99 积分)
const format = require('date-fns/format');
console.log(
  format(new Date(2017, 6, 6), 'MM/DD/YYYY')
);

// '06/07/2017'

想改变语言环境? 没问题:

const format = require('date-fns/format');
const deLocale = require('date-fns/locale/de') // German

console.log(
  format(new Date(2017, 6, 6), 'DD MMMM YYYY', { locale: deLocale })
);

// 06 Juli 2017

 下面是支持的语言列表.

如果您在浏览器中工作,不要忘记在dateFns对象中挂起任何调用辅助方法的调用.

下面是如何用 lastDayOfMonth方法获取一个月的最后一天的方法:

第 6 段(可获 0.65 积分)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script>
  console.log(
    dateFns.lastDayOfMonth( new Date(2017, 6, 7) )
  );
  // Mon Jul 31 2017 00:00:00 GMT+0200 (CEST)
</script>

要注意 date-fns 也有相应的获取特定一 季度的最后一天的方法。

不可变性,纯净性和简洁性

date-fns 的一个卖点是它的方法解释起来都是纯净简洁的。这使它的代码十方易于理解,使得在出问题的时候很容易消除 bug。

让我用 Moment.js 作为反例来论证这一点。前文提到,在 Moment 中日期是可变的,这可能会导致不可预料的行为。

第 7 段(可获 0.99 积分)
const moment = require('moment');
const now = new Date(); 
const mNow = moment(now);

mNow.add('day', 3);
console.log(mNow.toDate());
mNow.add(3, 'day');
console.log(mNow.toDate());

// 2017-07-08T22:00:00.000Z
// 2017-07-11T22:00:00.000Z

在这里有几件事情需要注意。Moment 的 add 函数不在乎其参数的顺序(虽然现在第1个方法会产生不赞成使用的警告)。不过更让人困惑的是如果你连续多次调用 add,你不会得到相同的结果,因为 Moment 对象是可变的:

 

第 8 段(可获 0.76 积分)
mNow.add(3, 'day'); // add 3 days
mNow.add(3, 'day'); // adds 3 **more** days

相比之下,date-fns 的参数拥有一致的顺序,而且结果总是相同,每次调用都会返回新的 Date 对象。

let addDays = required('date-fns/add_days');
addDays(now, 3); // (April 30, 2017)
addDays(now, 3); // (April 30, 2017)
addDays(now, 3); // (April 30, 2017)

同时注意,它的方法名更具语义(addDays 而不是 add),保持一致,一个方法做一件事情,而且只做一件事情。

阅读 JavaScript 介绍

第 9 段(可获 0.69 积分)

增强你的 JavaScript 代码。改进现代 Web。

现在开始阅读

比较日期

如果你看到 SitePoint 的 JavaScript 频道的文章列表,你会发现一些列出了其发表的具体日期,另外一些则显示发表于 X 天前。如果你使用纯 JavaScript 实现这个功能,可能得花些时间,但是用 date-fns 就轻而易举 —— 只需要使用 distanceInWords 方法。

来比较两个不同的日期:

const distanceInWords = require('date-fns/distanceInWords');
const startDate = new Date(2017, 3, 27); // (April 27, 2017)
const endDate = new Date(2018, 3, 27); // (April 27, 2018)
console.log(
  distanceInWords(startDate, endDate)
);
// "about 1 year"
第 10 段(可获 1.05 积分)

如果你想在 date-fns 中使用其它不同的单位,可以参考下面的列表:

  • Milliseconds (毫秒)
  • Seconds (秒)
  • Minutes (分钟)
  • Hours (小时)
  • Days (天)
  • Months (月)
  • Years (年)

方法名是 differenceIn[上面列表中的一项] 比如 differenceInDays.

使用日期集合

data-dns 有一些很方便的辅助方法,以各种方式操作日期集合。

对日期集合排序

下面的示例使用 compareAsc 来对日期进行升序排列。如果第一个日期在第二个日期之后,它会返回1,如果第一个日期在第二个日期之前它会返回 -1,两个日期相等则返回 0。

 

第 11 段(可获 1.29 积分)
const compareAsc = require('date-fns/compare_asc');
const date1 = new Date('2005-01-01');
const date2 = new Date('2010-01-01');
const date3 = new Date('2015-01-01');
const arr = [date3, date1, date2];
const sortedDates = arr.sort(compareAsc);

// [ 2005-01-01, 2010-01-01, 2015-01-01 ]

如你所见,日期现在是升序排列。

与 compareAsc 对应的方法是  compareDesc

const compareDesc = require('date-fns/compare_desc');
...
const sortedDates = arr.sort(compareDesc);
// [ 2015-01-01, 2010-01-01, 2005-01-01 ]

生成特定两天之间的日期

第 12 段(可获 0.29 积分)

为了生成两天之间的日期,您可以使用我们以前遇到的addDays method ,以及在指定范围内返回一个日期数组的 eachDay helpe

const addDays = require('date-fns/add_days');
const eachDay = require('date-fns/each_day');
const today = new Date();
const dayAWeekFromNow = addDays(today, 7);
const thisWeek = eachDay(today, dayAWeekFromNow); 
console.log(thisWeek);

// [ 2017-07-03, 2017-07-04, 2017-07-05, 2017-07-06, 2017-07-07, 2017-07-08, 2017-07-09, 2017-07-10 ]

查找最近日期

可以使用closestTo 方法在日期数组中找到最近的日期,此代码片段来自前面的示例:

第 13 段(可获 0.81 积分)
const closestTo = require('date-fns/closest_to');
...
const christmas = new Date(2017, 11, 25);
const closestToChristmasDate = closestTo(christmas, thisWeek); 
// 2017-07-10T

还有一个 closestIndexTo 方法,如果你想得到索引号就可以使用它。

时区

date-dns 的一个弱点是它目前没有像 Moment.js 一样提供处理时区的函数。Stack Overflow 上的这个回答确实提供了一些背景知识,是关于本地 Date 对象并不会实际保存“当前时区”数据。然而 date-fns 总是返回代码运行环境的本地时区。

 

第 14 段(可获 0.91 积分)

你会在那个讨论中注意到他们提到在 JavaScript 的一些设置时区的有限方法。正如答案指出的,这不是一个全面的解决方案,但是它适用于很多只需要输出转换的情况 (从 UTC 或本地时间转换到特定的时区)。

new Date().toLocaleString("en-US", {timeZone: "America/New_York"});

时区是个复杂的问题,所以 MomentJS 有一个单独的库来处理时区。也有正在进行的计划为 date-dns 添加时区支持,但在写本文的时候,它还在开发中。

第 15 段(可获 1.19 积分)

结论

Date-fns是一个很棒的小库,这里一大堆的辅助方法来处理JavaScript日期. 我希望这篇文章能让你有足够的了解和灵感去看看并且开始在自己的项目中使用它。 这个库正处于非常活跃的发展阶段希望第2版很快就会出来了。

有了这个,我会带你使用date-fns之旅途,请在下面的评论中告诉我你与date-fns相关经验。

第 16 段(可获 1.16 积分)

文章评论