now.js是什么
now.js是一個javascript的時間操作小工具,類似date-fns和moment。
長啥樣
簡單的把示例放這,更多用法請到github去發(fā)現(xiàn)。
import Now from 'now.js'; // for node(browser do not need this)
now = new Now() // "2017-11-20 22:23:00.285"
now.beginningOfMinute() // "2017-11-20 22:23:00"
now.beginningOfHour() // "2017-11-20 22:00:00"
now.beginningOfDay() // "2017-11-20 00:00:00"
now.beginningOfWeek() // "2017-11-19 00:00:00"
now.firstDayMonday = true // Set Monday as first day, default is Sunday
now.beginningOfWeek() // "2017-11-20 00:00:00"
now.beginningOfMonth() // "2017-11-01 00:00:00"
now.beginningOfQuarter() // "2017-10-01 00:00:00"
now.beginningOfYear() // "2017-01-01 00:00:00"
now.endOfMinute() // "2017-11-20 22:23:59.999"
now.endOfHour() // "2017-11-20 22:59:59.999"
now.endOfDay() // "2017-11-20 23:59:59.999"
now.endOfWeek() // "2017-11-25 23:59:59.999"
now.firstDayMonday = true // Set Monday as first day, default is Sunday
now.endOfWeek() // "2017-11-26 23:59:59.999"
now.endOfMonth() // "2017-11-30 23:59:59.999"
now.endOfQuarter() // "2017-12-31 23:59:59.999"
now.endOfYear() // "2017-12-31 23:59:59.999"
All the above functions return String type. You can pass 'self' to return Now instance:
var beginningOfMinute = now.beginningOfMinute('self') // return Now instance
beginningOfMinute.format('ddd, Ah') // "Mon, PM10"
beginningOfMinute.format('LLLL') // "Monday, November 20, 2017 10:23 PM"
beginningOfMinute.isMonday() // true
為什么要寫這個庫
因為學(xué)習(xí)underscore源碼的過程中,感覺無聊。想寫個庫調(diào)劑一下,當(dāng)做學(xué)習(xí)的機會。
我是照著underscore源碼一個個commit敲的.代碼放在這里,剛看了一眼,有668次commit,兩個月,敲到了1.4.3版本,可能還沒到一半。
敲久了有點無聊。想動手寫一個庫作為調(diào)劑。碰巧之前做防健忘短信提醒的時候是用go寫的后臺,用了gorm,在作者jinzhu的github主頁上發(fā)現(xiàn)了now,是一個go的時間幫助庫,覺得很有意思。clone之,學(xué)之。
偷了now的思想。造一個javascript版的就顯得很容易。很快我就寫完了除了Parse和MustParse之外的所有方法。跟原庫對比一下。覺得now.js就是個玩具。這不怪我,javascript對時間處理的支持遠不如go。比如go原生支持format、字符串解析成時間以及Duration等等。
想著加上format。該怎么去寫?立馬就想到的方法是平時經(jīng)常寫的根據(jù)不同條件做字符串拼接。確實是個方法。但得多少switch case才能涵蓋所有情況,想想都可怕。顯然這是最蠢也是工作量最大的方法。
不會,那就借鑒別人的。github上發(fā)現(xiàn)了date-fns和moment,支持i18n國際化。
date-fns:
import { formatRelative } from 'date-fns'
import { es, ru } from 'date-fns/esm/locale'
formatRelative(subDays(new Date(), 3), new Date(), { locale: es })
//=> "el viernes pasado a las 19:26"
formatRelative(subDays(new Date(), 3), new Date(), { locale: ru })
//=> "в прошлую пятницу в 19:26"
moment:
moment.locale('fr');
moment(1316116057189).fromNow(); // il y a une heure
moment.locale('en');
moment(1316116057189).fromNow(); // an hour ago
我的審美告訴我應(yīng)該選擇moment,調(diào)用一次locale(),這之后的format都是基于該locale的。當(dāng)然它也還支持每次單獨指定locale的:
moment.duration(1, "minutes").locale("en").humanize(); // a minute
moment.duration(1, "minutes").locale("fr").humanize(); // une minute
moment.duration(1, "minutes").locale("es").humanize(); // un minuto
進一步學(xué)習(xí)發(fā)現(xiàn)moment的format和i18n國際化高度耦合。要用它的i18n意味著基本上也得用它的format。當(dāng)然i18n也不是核心的moment庫作者寫的,他們也精通不了那么多國家的語言,那都是github上許許多多人貢獻的。開源就有這好處??聪翷ICENCE是MIT的,代碼可用,抄。
now.js也是MIT協(xié)議的,負(fù)罪感少了點(其實MIT協(xié)議是相當(dāng)寬松的,就算你拿它代碼去商業(yè)化也是沒有問題的)。況且我寫庫的主要目的是為了學(xué)習(xí)。
開干!雖說是抄,畢竟代碼要整合到我的庫,直接復(fù)制粘貼是不行的。所有的代碼細節(jié)未必都需要全知道,但看懂整體運行的邏輯是必須的,下點功夫,整合成功,開源。
思維腦圖
moment:

當(dāng)然,moment的東西不止上圖這些,我只取了一部分來畫。
now.js:

now.js的Duration和moment的不一樣,現(xiàn)在還不支持單獨使用,只是給內(nèi)部方法
elapse使用,以后可能會支持單獨使用。
對比
- moment是大而全,now.js是剛夠用。
- moment的parse相當(dāng)強大,now.js就暫時不支持了,只支持和
new Date(args)相同的args參數(shù)類型。不過format應(yīng)該都基本上和moment的一樣,不過測試用例現(xiàn)在還沒有寫太全,如果誰用了并且發(fā)現(xiàn)bug,可以到github去提issues。不勝感激。
- moment是頁面一加載的時候會把所有的i18n都初始化了,這點我個人認(rèn)為不好,加載時間長,網(wǎng)絡(luò)情況不好的時候,差不多需要10秒我才能在devtool上調(diào)試(當(dāng)然這也包括官網(wǎng)加載的其他很多東西)。now.js只加載默認(rèn)的,需要的時候按需加載。
- moment做什么操作前都要檢測一下date是否合法的(isvalid)。now.js在parse的時候如果不合法就直接拋出錯誤,以免后續(xù)沒玩沒了的檢測。當(dāng)然這可能損失了用戶友好性,但是對減少代碼量是很有幫助的。
結(jié)語
這個庫不是我一個人寫的,是許多開源工作者共同完成的。感謝moment的所有開源貢獻者,我從中學(xué)習(xí)了很多東西。后續(xù)還會繼續(xù)研究moment的代碼細節(jié),偷偷它的思想。
寫代碼什么最重要?思想最重要!