以下はGatsbyのversion2.30.1
の話。ちなみにタイトル詐欺で結局自分は使う方向にしている。
2021-01-01T06:00+09:00
のような形でpublishDateを保存しているpublishDate(formatString: "YYYY年MM月DD日")
のようにフォーマットしてフロントに渡している2020年12月31日
と表示される(内部的には2020-12-31T21:00+00:00
になっており、アーカイブでは2021年1月に正しく分類される).format()
を使っているという説明だがその前に .utc()
でutcモードにされている.utcOffset()
を使えばこれは回避されるが、そういうのはフロントでやればいいじゃんという姿勢っぽい内部的にはmoment.jsが使われているようなので、該当部分のソースコードをみて挙動を確認してみた。
const moment = require('moment');
const time = "2021-01-01T06:00+09:00"; // contentful側に保存されている形式
// gatsby/packages/gatsby/src/schema/types/date.ts
const ISO_8601_FORMAT = [
`YYYY`,
`YYYY-MM`,
`YYYY-MM-DD`,
`YYYYMMDD`,
// Local Time
`YYYY-MM-DDTHH`,
`YYYY-MM-DDTHH:mm`,
`YYYY-MM-DDTHHmm`,
`YYYY-MM-DDTHH:mm:ss`,
`YYYY-MM-DDTHHmmss`,
`YYYY-MM-DDTHH:mm:ss.SSS`,
`YYYY-MM-DDTHHmmss.SSS`,
`YYYY-MM-DDTHH:mm:ss.SSSSSS`,
`YYYY-MM-DDTHHmmss.SSSSSS`,
// `YYYY-MM-DDTHH:mm:ss.SSSSSSSSS`,
// `YYYY-MM-DDTHHmmss.SSSSSSSSS`,
// Local Time (Omit T)
`YYYY-MM-DD HH`,
`YYYY-MM-DD HH:mm`,
`YYYY-MM-DD HHmm`,
`YYYY-MM-DD HH:mm:ss`,
`YYYY-MM-DD HHmmss`,
`YYYY-MM-DD HH:mm:ss.SSS`,
`YYYY-MM-DD HHmmss.SSS`,
`YYYY-MM-DD HH:mm:ss.SSSSSS`,
`YYYY-MM-DD HHmmss.SSSSSS`,
// `YYYY-MM-DD HH:mm:ss.SSSSSSSSS`,
// `YYYY-MM-DD HHmmss.SSSSSSSSS`,
// Coordinated Universal Time (UTC)
`YYYY-MM-DDTHHZ`,
`YYYY-MM-DDTHH:mmZ`,
`YYYY-MM-DDTHHmmZ`,
`YYYY-MM-DDTHH:mm:ssZ`,
`YYYY-MM-DDTHHmmssZ`,
`YYYY-MM-DDTHH:mm:ss.SSSZ`,
`YYYY-MM-DDTHHmmss.SSSZ`,
`YYYY-MM-DDTHH:mm:ss.SSSSSSZ`,
`YYYY-MM-DDTHHmmss.SSSSSSZ`,
// `YYYY-MM-DDTHH:mm:ss.SSSSSSSSSZ`,
// `YYYY-MM-DDTHHmmss.SSSSSSSSSZ`,
// Coordinated Universal Time (UTC) (Omit T)
`YYYY-MM-DD HHZ`,
`YYYY-MM-DD HH:mmZ`,
`YYYY-MM-DD HHmmZ`,
`YYYY-MM-DD HH:mm:ssZ`,
`YYYY-MM-DD HHmmssZ`,
`YYYY-MM-DD HH:mm:ss.SSSZ`,
`YYYY-MM-DD HHmmss.SSSZ`,
`YYYY-MM-DD HH:mm:ss.SSSSSSZ`,
`YYYY-MM-DD HHmmss.SSSSSSZ`,
// `YYYY-MM-DD HH:mm:ss.SSSSSSSSSZ`,
// `YYYY-MM-DD HHmmss.SSSSSSSSSZ`,
// Coordinated Universal Time (UTC) (Omit T, Extra Space before Z)
`YYYY-MM-DD HH Z`,
`YYYY-MM-DD HH:mm Z`,
`YYYY-MM-DD HHmm Z`,
`YYYY-MM-DD HH:mm:ss Z`,
`YYYY-MM-DD HHmmss Z`,
`YYYY-MM-DD HH:mm:ss.SSS Z`,
`YYYY-MM-DD HHmmss.SSS Z`,
`YYYY-MM-DD HH:mm:ss.SSSSSS Z`,
`YYYY-MM-DD HHmmss.SSSSSS Z`,
`YYYY-[W]WW`,
`YYYY[W]WW`,
`YYYY-[W]WW-E`,
`YYYY[W]WWE`,
`YYYY-DDDD`,
`YYYYDDDD`,
]
// moment()はローカルモード
const localTime = moment(time);
console.log(localTime); // Moment<2021-01-01T06:00:00+09:00>
// moment.utc()はutcモード
const utcTime = moment.utc(time);
console.log(utcTime); // Moment<2020-12-31T21:00:00Z>
// GatsbyのGraphQLのformatString("YYYY-MM-DDTHH:mmZ")でやってること
console.log(moment.utc(time, ISO_8601_FORMAT, true).format("YYYY-MM-DDTHH:mmZ")) // 2020-12-31T21:00+00:00
// 以下のようにutcOffsetを使えばタイムゾーンにも対応できるが、それはしない方向らしい
const utcOffset = moment(time).format('Z');
console.log(moment.utc(time, ISO_8601_FORMAT, true).utcOffset(utcOffset).format("YYYY-MM-DDTHH:mmZ")) // 2021-01-01T06:00+09:00
日付にUTC offset情報が入らないようにContent modelを修正した。エントリの日付情報を扱うfieldのSettingsからAppearanceのFormatのプルダウンを開いて、Date and time without timezoneを選択。
これでpost画面からUTC選択メニューがなくなった。
過去に投稿した記事には相変わらずUTC offsetが残っているのでこれを修正する必要がある。これはContent Management APIでサクっと。
require("dotenv").config({ path: `.env.development` });
const env = process.env;
process.on("unhandledRejection", console.dir);
const contentful = require("contentful-management");
const client = contentful.createClient({
accessToken: env.CONTENTFUL_PERSONAL_ACCESS_TOKEN,
});
const convertNoUtcOffset = async (entries) => {
for (let item of entries.items) {
try {
if (item.fields.publishDate.ja.split('+')[1]) {
const convertedTime = await item.fields.publishDate.ja.split('+')[0];
console.log(`converted: ${item.fields.publishDate.ja} --> ${convertedTime}`);
item.fields.publishDate.ja = convertedTime;
const updatedEntry = await item.update();
await updatedEntry.publish();
}
} catch (err) {
console.log('skipped for some reason');
}
};
}
const checkPublishDate = (entries) => {
for (let item of entries.items) {
try {
if (item.fields.publishDate.ja.split('+')[1]) {
console.log(`warning: ${item.fields.title.ja}`);
console.log(item.fields.publishDate.ja);
} else {
console.log(item.fields.publishDate.ja)
}
} catch (err) {
throw err;
}
}
}
(async () => {
const space = await client.getSpace(env.CONTENTFUL_SPACE_ID);
const environment = await space.getEnvironment("master");
const entries = await environment.getEntries({
content_type: "blogPost",
limit: 200,
order: "sys.createdAt",
});
convertNoUtcOffset(entries);
checkPublishDate(entries);
})();