0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

gatsby-transformer-remarkのdateの形式

Last updated at Posted at 2023-02-11

2023-04-08追記: なんかもっとややこしい話が出てきたので、後で追記する。
Gatsby(gatsby-transformer-remark)は日付形式を全部UTCだと思っているらしい。
さらに、YAML自体がDate型を持ってたりするので余計ややこしい...。


date の形式は実は結構ややこしいのでメモ。

gatsby-transformer-remark の readme には残念ながら記載なし。

おそらく、JavaScript の Date() に食わせてると思ったので、これの引数の形式を調べることに。

こっちは
MDN
に正式な解答があった。

A string value representing a date, in a format recognized by the Date.parse() method. (The ECMA262 spec specifies a simplified version of ISO 8601, but other formats can be implementation-defined, which commonly include IETF-compliant RFC 2822 timestamps.)

simplified version of ISO 8601
というのが正式な規格らしい。
よく見る YYYY-MM-DDTHH:mm:ss.SSSZ ってやつ。

これ以外に、実装依存で別の形式も受け付けるとのこと。

YYYY-MM-DDTHH:mm:ss.SSSZ は直感的じゃないのと、入力が手間なのであまり使いたくない。
YYYY-MM-DD HH:mm でも Gatsby は受け付けてくれるっぽいので、これを採用。

YYYY-MM-DD は GoogleIME で『きょう』で変換すれば出るし、
HH:mm も同様に『いま』で変換すれば出るので、入力しやすい。

秒は無視して OK。1 秒を争う記事は書かんよ 😎

ハマりポイントその 1

YYYY/MM/DD は受け付けてくれない
Node.js(v19.2.0)で new Date("2023/02/11") とすると受け付けてくれるが、
Gatsby ではだめなようだ...。

厳密には、Gatsby でも一見受け付けてくれるように見える。が、これがクセモノ。
formatString を指定して query したり、
filterdate を指定して query したりすると ↓、

query MyQuery {
  allMarkdownRemark(
    filter: { frontmatter: { date: { lt: "2023-02-12 22:26:59" } } }
    sort: { frontmatter: { date: DESC } }
  ) {
    nodes {
      frontmatter {
        date
      }
    }
  }
}

ここで初めてエラーを吐く ↓。

{
  "errors": [
    {
      "message": "Field \"lt\" is not defined by type \"StringQueryOperatorInput\".",
      "locations": [
        {
          "line": 3,
          "column": 35
        }
      ]
    }
  ]
}

どうやら日付としてではなく、ただの文字列として認識しちゃってるようだ。
なので、 lt の指定ができなくてエラーを吐く。

ハマりポイントその 2

他にありがちなのは、時分秒のうち、時を 1 桁にしちゃってもエラーになる。
まさしくこの記事を書いててやらかしてるんだけど、
2023-02-12 0:39 は NG。
2023-02-12 00:39 は OK。

その 1 同様に、これも特定の query をするまで、エラーが見えないのが厄介。

ハマりポイントその 3

filter 側も YYYY-MM-DD じゃないとだめ。
しかもこっちはエラーすら吐かない

↓ の query では YYYY/MM/DD になっており、エラーを吐かないが、期待した動作にはならない。

query MyQuery {
  allMarkdownRemark(
    filter: { frontmatter: { date: { lt: "2023/02/12" } } }
    sort: { frontmatter: { date: DESC } }
  ) {
    nodes {
      frontmatter {
        date
      }
    }
  }
}

query 結果の傾向を見てると、↑ の場合は 2024 年未満の記事が query されるようだ。
2023/02/11 の記事はもちろん、2023/12/31 の記事も query されちゃう。ナンジャソリャ。

対策

ブログ記事用の template で dateformatString を指定して query するようにして、

export const postQuery = graphql`
  query ($id: String!, $formatString: String) {
    current: markdownPost(id: { eq: $id }) {
      date(formatString: $formatString)
    }
  }
`;

コンポーネント側で "Invalid date" だったらエラーに落とすようにしたら良い。

if (date === `Invalid date`) {
  throw new Error(
    [
      `Invalid date!!`,
      `Don't use the \`/\`  as separator.`,
      `e.g., ❌: \`2023/02/11 09:12\` => ⭕: \`2023-02-11 09:12\` .`,
      `Set the hour to 2 digits,`,
      `e.g., ❌: \`2023-02-11 9:12\` => ⭕: \`2023-02-11 09:12\` .`,
    ].join(` `)
  );
}

エラーに落とすと、画面にデカデカとポップアップ表示されるので、これで見逃さない。

余談

本当はページアクセス時じゃなくて、
ビルド時にエラーに落としたいんだけど、方法が分からなかった...。

gatsby-transformer-remark が parser を公開してれば良かったんだけど、そんなもんない。

ならばと、gatsby-node.js で query する作戦に切り替えたが、これも仕様上無理そうだった。

残念。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?