Help us understand the problem. What is going on with this article?

【GAS】YYYY/MM/DD/hh/mm/ssからUNIXタイムスタンプを生成する

GASで引数に日時を取るスラッシュコマンドを作るにあたって、「スラッシュコマンドで指定する日付と時刻はわかりやすいYYYY/MM/DD/hh/mm/ssがいい。でもSlack APIを叩く時はUNIXタイムスタンプで指定しないといけない」という都合により、GASで「YYYY/MM/DD/hh/mm/ss→UNIXタイムスタンプ」の変換をすることになったんですが、思いの外ネット上にベストマッチなソリューションが見当たらなかったので書き残しておきます。

実装①

//2020年1月1日12時34分56秒
var str = "2020/01/01/12/34/56"
var array = str.split(/\//).map(Number)
var date = new Date(array[0], array[1] - 1, array[2], array[3], array[4], array[5])
date = (date.getTime() / 1000) + ''
Logger.log(date) // -> 1577849696

実装②

var str = "2020/01/01/12/34/56"
var array = str.split(/\//)
var date = Utilities.formatString("%s-%s-%sT%s:%s:%s+09:00", array[0], array[1], array[2], array[3], array[4], array[5])
date = Date.parse(date) / 1000 + ''
Logger.log(date) // -> 1577849696

確認

UNIX時間⇒日付変換 - 高精度計算サイト - Keisan - CASIO
スクリーンショット (47).png

1000で割る意味

getTime()Date.parse()によって返ってくるUNIX時は単位がミリ秒になっています。Slack APIで指定するタイムスタンプは秒単位でなければならないので、1000で割った値を文字列に変換しています。

実装①のメリデメ

メリット

  • 一度数値に変換するので、引数のバリデーションとかゼロ埋めとか気にしなくていい(?)
  • 短くて読みやすい(?)

デメリット

  • Dateオブジェクトを経由するのが煩わしくないこともない
  • Dateクラスのメソッドの仕様が厄介

デメリットの方について少し説明しますと、数列からDateオブジェクトを生成するnew Date()の構文は

new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);

なのですが、このmonthIndexは0から11で指定するんですね。

注: 引数 monthIndex は 0 から始まります。 つまり 1 月 = 0、 12 月 = 11 です。

Date - JavaScript | MDN

なので、new Date()に渡す時にそこだけ- 1する必要があります。

あと、公式マニュアルを見返していて気付いたんですが(強調は筆者)、

注: Date を複数の引数を伴ってコンストラクタとして呼び出された場所では、値が論理範囲より大きくても (month 値に 13 を与えたり、minute 値に 70 を与える)、調整された値になります。つまり、new Date(2013, 13, 1) は、new Date(2014, 1, 1) と等しくなるように調整され、両者とも 2014-02-01 の日付を生成します

……何…… ……だと……(画像略)

var str = "2020/13/01/01/03/05"
var array = str.split(/\//).map(Number)
var date = new Date(array[0], array[1] - 1, array[2], array[3], array[4], array[5])
Logger.log(date) // -> Fri Jan 01 01:03:05 GMT+09:00 2021

……ほん…… ……とだ……(来年の元日って金曜なんだ)

これだとうっかりタイポした時にちゃんと動作してくれないどころか全く予想外の結果になってしまいますね・・・。

結局バリデーションを自分で設定しないといけないとなると、最初に挙げたメリットもおじゃんになってしまいました。無念。

実装②のメリデメ

メリット

  • 分割してフォーマットに流し込んでパースするだけ
  • パースした返り値がUNIX時の整数値になっているため目的に合致している
  • フォーマットが厳密に決まっているので、実装①のような厄介な挙動をしない

デメリット

  • 特にない?

↓の記事ではDate.parse()の返り値がDateではなく整数になることを「」と形容していますが、今回のような使い方をする場合にはまさしく割れ鍋に綴じ蓋ですね。

JavaScript の Date は罠が多すぎる - Qiita

そして"2020/13/01/01/03/05"のようなありえない日付を指定した場合の挙動ですが、

var str = "2020/01/13/12/34/56"
var array = str.split(/\//)
var date = Utilities.formatString("%s-%s-%sT%s:%s:%s+09:00", array[0], array[1], array[2], array[3], array[4], array[5])
date = Date.parse(date) / 1000 + ''
Logger.log(date) // -> NaN

ちゃんと失敗してくれています。これなら例外処理を入れるにもif(isNaN(date))で済みます。いいですね。っていうかマニュアルにちゃんと書いてあるんですけども。

文字列を解釈できなかったり不正な日付 (例えば 2015-02-31) が指定された場合 NaN を返します。

Date.parse() - JavaScript | MDN

ちなみに、Date.parse()といえばブラウザによって挙動が異なる1ことで有名(らしい)ですが、今回はGASなのでGASで動けば十分ということで、これでいいと思います(GASの仕様が変わらなければ)。

まとめ

2つの実装の長所・短所を比較した結果、実装②の方が良さそうだなと思いました。

書き始める前は実装①推しだったんですが、やはりマニュアルはちゃんと読んでおくべきですね。色んな意味で勉強になりました。

最後まで読んでいただきありがとうございました。


  1. でも→を見る限りでは、最新バージョンならほとんどのブラウザで問題なく動作するんですかね?Date.parse() ブラウザー実装状況 - JavaScript | MDN 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away