かめ。ブログ

luxonを使って「1日前」表記の公開日を表すReactコンポーネントを作る

2022年4月15日
2022年4月15日

目次

日付ライブラリとして、昔はよくmomentを使用していました。
最近は他のライブラリが推奨されているようなので、luxonを使っています。

他のライブラリの推奨理由はmomentのドキュメントに書いてあります。
その中の一つにluxonも推奨されています。
https://momentjs.com/docs/

公開日コンポーネントについて

ブログを作る際に、公開日を表示するコンポーネントをよく使うのでメモとして残していきます!
それを作るために今回luxonを使用しました。

よくある形として記事を公開してから経過している時間によって、
「数時間前」「1日前」「2021年4月15日」など表記を変更するようにしています。

使用しているライブラリ

  • React 17
  • luxon
  • styled-components


実際のコード

import React from 'react'
import { DateTime, Settings } from 'luxon'
import styled from 'styled-components'
import DateIcon from '~/assets/DateIcon'
import UpdateIcon from '~/assets/UpdateIcon'

Settings.defaultLocale = 'ja';

const DateContainer = styled.p`
  display: flex;
  align-items: center;
  font-size: 12px;
  color: #666;
  & svg {
    margin-right: 8px;
  }
`

export interface Date {
  value?: string
  isUpdate?: boolean
}

const DateArea: React.FC<Date> = props => {
  if(!props.value) return <></>
  const date = DateTime.fromISO(props.value)
  const diffHour = date.diff(DateTime.now(), 'hours').hours

  const Icon = props.isUpdate ? UpdateIcon : DateIcon
  
  const HOUR = -10
  const Day = -7 * 24
  return (  
    <DateContainer>
      {diffHour > -1 && <><Icon />{date.toRelative({ unit: 'minutes' })}</>}
      {diffHour <= -1 && diffHour > HOUR && <><Icon />{date.toRelative({ unit: 'hours' })}</>}
      {diffHour > Day && diffHour < HOUR && <><Icon />{date.toRelativeCalendar()}</>}
      {diffHour <= Day && <><Icon />{date.toLocaleString(DateTime.DATE_MED)}</>}
    </DateContainer>
  )
}

export default DateArea

アイコンについて

figmaのiconifyを使用しています。
https://github.com/iconify/iconify-figma

DateIcon

const DateIcon = () => (
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.4444 1.55556H11.6667V0.777778C11.6667 0.35 11.3167 0 10.8889 0C10.4611 0 10.1111 0.35 10.1111 0.777778V1.55556H3.88889V0.777778C3.88889 0.35 3.53889 0 3.11111 0C2.68333 0 2.33333 0.35 2.33333 0.777778V1.55556H1.55556C0.692222 1.55556 0.00777777 2.25556 0.00777777 3.11111L0 14C0 14.4126 0.163888 14.8082 0.455612 15.0999C0.747335 15.3917 1.143 15.5556 1.55556 15.5556H12.4444C13.3 15.5556 14 14.8556 14 14V3.11111C14 2.25556 13.3 1.55556 12.4444 1.55556ZM12.4444 13.2222C12.4444 13.65 12.0944 14 11.6667 14H2.33333C1.90556 14 1.55556 13.65 1.55556 13.2222V5.44444H12.4444V13.2222ZM3.11111 7H4.66667V8.55556H3.11111V7ZM6.22222 7H7.77778V8.55556H6.22222V7ZM9.33333 7H10.8889V8.55556H9.33333V7Z" fill="#999999"/>
</svg>
)
export default DateIcon

Update

const UpdateIcon = () => (
<svg width="16" height="13" viewBox="0 0 18 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.7 6C5.1 4 6.9 2.5 9 2.5C10.5 2.5 11.7 3.2 12.5 4.3L14.2 2.3C13 0.9 11.1 0 9 0C5.5 0 2.6 2.6 2.1 6H0L3.5 10L7 6H4.7ZM14.5 4L11 8H13.3C12.8 10 11.1 11.5 9 11.5C7.5 11.5 6.3 10.8 5.5 9.7L3.8 11.6C5 13.1 6.9 14 9 14C12.5 14 15.4 11.4 15.9 8H18L14.5 4Z" fill="#999999"/>
</svg>
)
export default UpdateIcon

コード解説

propsの型定義

export interface Date {
  value?: string // 日付の値を入れる。「2022-01-14T00:00:02.817Z」
  isUpdate?: boolean // 更新日アイコンにしたい場合はtrueにする
}

デフォルトのtimezone指定する

import { DateTime, Settings } from 'luxon'
Settings.defaultLocale = 'ja'

記事の投稿時間と現在時刻と比較してどのぐらいの時間が経過したかを取得する

const diffHour = date.diff(DateTime.now(), 'hours').hours

どのぐらいの時間が経過したらどういう表記にするかの目安をきめておく

const HOUR = -10
const Day = -7 * 24

記事投稿からの経過時間によって表記をだし分ける

<DateContainer>
  {diffHour > -1 && <><Icon />{date.toRelative({ unit: 'minutes' })}</>} // 記事公開から1時間以内の場合は「10分前」のように分単位で表記
  {diffHour <= -1 && diffHour > HOUR && <><Icon />{date.toRelative({ unit: 'hours' })}</>} // 記事公開から1時間以上、10時間未満だった場合は「1時間前」のように時間単位で表記
  {diffHour > Day && diffHour < HOUR && <><Icon />{date.toRelativeCalendar()}</>} // 記事公開から10時間以上、7日未満の場合に「今日、昨日、2日前」のように表記
  {diffHour <= Day && <><Icon />{date.toLocaleString(DateTime.DATE_MED)}</>} // それ以降は「2021年4月15日」のように表記
</DateContainer>

まとめ

今回はluxonを使って、公開日や更新日のコンポーネントを作りました。
momentは昔からよく使われていましたが、その時は新しくてもjavascvriptの仕様のアップデートともに、ライブラリ自体も古くなっていってしまう場合もあるので気をつけていきたいですね。
時間系ライブラリは他にも「Day.js」、「date-fns」などもあるので、その時々で試してみて決めれるとよいですね!