點燈坊

失くすものさえない今が強くなるチャンスよ

使用 add() 對日期相加

Sam Xiao's Avatar 2019-11-09

實務上常需要對 API 所回傳的 Date 字串加工,如先增加 hours,再增加 title,這牽涉到增加 Date 與 String 兩種 Type,該如何優雅實現呢 ?

Version

macOS Catelina 10.15.1
VS Code 1.40.0
Quokka 1.0.259
Ramda 0.26.1
Date-fp 5.0.3

Imperative

let data = '2019-06-13 07:43:44'

let fn = str => {
  let date = new Date(str)
  date.setHours(date.getHours() + 8)

  return 'Release : ' + date.getFullYear() + '-' + date.getMonth() + '-' + date.getDate() + ' ' +
  date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds()
};

fn(data) // ?

Imperative 會直接使用 Date 自帶的 getHours() 取得 hour 部分,+8 之後再使用 setHours() 寫回,其中 setHours() 使用了 side effect 改變 date

最後加上 發生日期,並還原日期原本格式。

add000

Function Pipeline

import { pipe, concat } from 'ramda'
import { add, format, parse } from 'date-fp'

let data = '2019-06-13 07:43:44'

let fn = pipe(
  parse('YYYY-MM-DD HH:mm:ss'),
  add('hours', 8),
  format('YYYY-MM-DD HH:mm:ss'),
  concat('Release : ')
)

fn(data) // ?

以 functional 角度思考:

  • 使用 date-fp 的 parse() 將 string 轉成 date
  • 使用 date-fp 的 add() 增加 8 小時
  • 使用 date-fp 的 format() 還原日期原本格式
  • 使用 Ramda 的 concat() 加上 發生時間

最後以 pipe() 整合所有流程,非常清楚。

add001

Function Composition

import { compose, concat } from 'ramda'
import { add, format, parse } from 'date-fp'

let data = '2019-06-13 07:43:44'

let fn = compose(
  concat('Release : '),
  format('YYYY-MM-DD HH:mm:ss'),
  add('hours', 8),
  parse('YYYY-MM-DD HH:mm:ss')
)

fn(data) // ?

既然能使用 pipe() 達成 pipeline,反向使用 compose() 就是 function composition 了。

add002

Conclusion

  • Ramda 缺乏處理 Date 的 function,可靠 Date-fp 補齊
  • 相同的功能, imperative 與 functional 何者較優雅呢 ?

Reference

date-fp, add()
date-fp, format()
Ramda, pipe()
Ramda, compose()
Ramda, concat()