Open1

国際化対応、DatePicker、Timezone留意点

SatoshiTechSatoshiTech

Supabase(date型)を使用した場合の、フロントエンド側の処理(多言語アプリ)

Dateオブジェクトの振る舞い(Timezone)

日本標準時での 2023-05-07は、UTC で見ると 2023 年 5 月 6 日の 15 時+9時間という考え方です。new Date('2023-05-07') で Date オブジェクトを作成すると、ブラウザはこの文字列をローカルタイムゾーンで解釈し、UTC で見たときの 2023 年 5 月 6 日の 15 時として Date オブジェクトを作成します。

DatePickerライブラリを使用すると、単純な文字列ではうけつけてくれないので、Dateオブジェクトの振る舞いを正しく理解した、処理が必要になります。

なにも配慮をしないと、DatePickerで2023年05月07日を選択したとき、選択後に表示されるDateInputフィールドの表示が、2023/05/06というおかしなことになる。

以下、対応後のコード

Postロジック

jsxの一部
 onChange={(date) => handleDateChange(date,"add")}
handleDateChange関数
  const handleDateChange = (date:Date|null,editStatus:"add"|"edit"):void =>{
      if(editStatus === "add"){
      if (date) {
        const dateInLocalTimezone = new Date(date.getTime() - (date.getTimezoneOffset() * 60000));
        setInputComment({
          ...inputComment,
          date: dateInLocalTimezone.toISOString().substring(0, 10),
        });
      } else {
        setInputComment({
          ...inputComment,
          date: null,
        });
      }
    // Edit comment date
    } else {
      if (date) {
        const dateInLocalTimezone = new Date(date.getTime() - (date.getTimezoneOffset() * 60000));
        dispatch(updateEditedComment({
            ...editedComment,
            date: date ? dateInLocalTimezone.toISOString().substring(0, 10) : '',
          })
        )
      } 
    }
  }

表示ロジック

APIで受け取った、DateStringの変換
  const switchDateFormatInList = (dateString: string):string => {
    const localDate = new Date(dateString)
    const offset = localDate.getTimezoneOffset() // ブラウザのローカルタイムとUTCとの差を分単位で取得
    const utcTimestamp = Date.parse(dateString) // UTCのタイムスタンプを取得

    // ブラウザのローカルタイムを計算して、フォーマットを整える
    const localTimestamp = utcTimestamp - (offset * 60 * 1000)
    const localDateObj = new Date(localTimestamp)

    const year = localDateObj.getFullYear()
    const month = ('00' + (localDateObj.getMonth() + 1)).slice(-2)
    const day = ('00' + localDateObj.getDate()).slice(-2)

    if (locale === 'ja-JP') {
      return `${year}/${month}/${day}`
    } else {
      return `${month}/${day}/${year}`
    }
  }