@@ -258,16 +258,36 @@ TypeScriptの\ ``Date``\ 型は数字に毛の生えたようなものですの
258258* サーバーでは常にエポック時刻で扱う(ただし、言語によっては秒単位だったり、ミリ秒単位だったり、マイクロ秒単位だったり違いはあるため、そこはルールを決めておきましょう)
259259* サーバーからフロントに送った段階で\ ``new Date() ``\ などを使って、ローカル時刻化する
260260
261- 日付のフォーマット
261+ 特定の日時の\ ``Date ``\ インスタンスの作成
262+ -----------------------------------------------------
263+
264+ 特定の日時インスタンスを作成するには、\ ``Date() ``\ コンストラクタの引数に数値を設定して作成します。月の数値が1少なく評価される(1月は0)な点に注意が必要です。この日時は現在のタイムゾーンで評価されます。
265+
266+ .. code-block :: ts
267+
268+ // 2020年9月21日21時10分5秒
269+ // 日本で実行すると日本時間21時(UTCでは9時間前の12時)に
270+ const d = new Date(2020, 8, 21, 21, 10, 5)
271+
272+ UTCの時刻から生成したい場合には、\ ``Date.UTC() ``\ 関数を使います。これはエポック秒を返すのでこれを\ ``new Date() ``\ に渡すことで、UTC指定の時刻のインスタンスが作成できます。
273+
274+ // UTCの2020年9月21日11時10分5秒
275+ // 日本で実行すると日本時間20時(日本時間はUTCは9時間進んでいるように見える)に
276+ const d = new Date(Date.UTC(2020, 8, 21, 11, 10, 5))
277+
278+ 日付のフォーマット出力
262279-------------------------------------------
263280
264- RFC-3393形式にするには 、\ ``toISOString() ``\ メソッドを使います。
281+ : RFC: ` 3393 ` \ 形式にするには 、\ ``toISOString() ``\ メソッドを使います。 \ `` toString() `` \ だとECMAScriptの仕様書で定められたロケール情報も含む文字列で出力を行ます。後者の場合、ミリ秒単位のデータは丸められてしまいます 。
265282
266283.. code-block :: ts
267284
268285 const now = new Date()
269- const.toISOString()
270- // '2020-09-06T13:34:37.557Z'
286+ now.toISOString()
287+ // '2020-09-21T12:38:15.655Z'
288+
289+ now.toString()
290+ // 'Mon Sep 21 2020 21:38:15 GMT+0900 (Japan Standard Time)'
271291
272292 短い形式やオリジナルの形式にするには自分でコードを書く必要があります。短く日時を表現しようとする場合のコードは次のようになります。月のみカレンダーの表記と異なって、0が1月になる点に注意してください。
273293
@@ -289,3 +309,121 @@ RFC-3393形式にするには、\ ``toISOString()``\ メソッドを使います
289309 // "2020/09/06 13:55:43"
290310
291311 ``padStart() ``\ と、テンプレート文字列のおかげで、以前よりははるかに書きやすくなりましたが、Day.jsなどの提供するフォーマット関数を使った方が短く可読性も高くなるでしょう。
312+
313+ 日付データの交換
314+ -------------------
315+
316+ クライアントとサーバーの間ではJSONなどを通じてデータをやりとりします。JSONでデータを転送するときは数値か文字列で表現する必要があります。日付データは既に説明した通りに、ミリ秒か秒のどちらかの数値で交換するのがもっともコード的には少ない配慮で実現できます。しかし、一方で出力された数字の列を見ても、即座に現在の日時を暗算できる人はいないでしょう。可読性という点では文字列を使いたいこともあるでしょう。本節ではデータをやりとりする相手ごとのデータ変換の仕方について詳しく説明していきます。
317+
318+ TypeScript(含むJavaScript同士)
319+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
320+
321+ TypeScript(含むJavaScript)であれば、\ ``toISOString() ``\ でも、\ ``toString() ``\ でも、どちらの方式で出力した文字列であってもパースできます。\ ``new Date() ``\ に渡すと\ ``Date ``\ のインスタンスが、\ ``Date.parse() ``\ に渡すと、エポック時刻が帰ってきます。
322+
323+ .. code-block :: ts
324+
325+ const fromToISOString = new Date(`2020-09-21T12:38:15.655Z`)
326+ // 2020-09-21T12:38:15.655Z
327+
328+ const fromToString = new Date(`Mon Sep 21 2020 21:38:15 GMT+0900 (Japan Standard Time)`)
329+ // 2020-09-21T12:38:15.000Z
330+
331+ const fromToISOStringEpoch = Date.parse(`2020-09-21T12:38:15.655Z`)
332+ // 1600691895655
333+
334+ const fromToStringEpoch = Date.parse(`Mon Sep 21 2020 21:38:15 GMT+0900 (Japan Standard Time)`)
335+ // 1600691895000
336+
337+ Goとの交換の場合
338+ ~~~~~~~~~~~~~~~~~~~~~~~~
339+
340+ Goでは日付のフォーマットが何種類か選べますが、このうち、タイムゾーンの時差が数値で入っているフォーマットはTypeScriptでパース可能です。ナノ秒の情報がミリ秒に丸められてしまいますが、一番精度良く伝達できるのは\ ``time.RFC3339Nano ``\ の出力です。
341+
342+ * ``time.RubyDate ``
343+ * ``time.RFC822Z ``
344+ * ``time.RFC1123Z ``
345+ * ``time.RFC3339 ``
346+ * ``time.RFC3339Nano ``
347+
348+ .. code-block :: go
349+ :caption: GoでRFC3339Nanoで出力
350+
351+ package main
352+
353+ import (
354+ "fmt"
355+ "time"
356+ )
357+
358+ func main() {
359+ now := time.Now()
360+ fmt.Println(now.Format(time.RFC3339Nano))
361+ // 2020-09-21T21:35:45.057076+09:00
362+ }
363+
364+ .. code-block :: ts
365+ :caption: TypeScriptでパース
366+
367+ const receivedFromGo = new Date(`2020-09-21T21:35:45.057076+09:00`)
368+ // 2020-09-21T12:35:45.057Z
369+
370+ 他の言語に出力する場合、\ ``toISOString() ``\ が無難でしょう。Goは\ ``time.RFC3339 ``\ か、\ ``time.RFC3339Nano ``\ を使ってパースできます。結果はどちらも同じです。
371+
372+ .. code-block :: go
373+
374+ package main
375+
376+ import (
377+ "fmt"
378+ "time"
379+ )
380+
381+ func main() {
382+ t, err := time.Parse(time.RFC3339, "2020-09-21T12:38:15.655Z")
383+ fmt.Println(t)
384+ // 2020-09-21 12:38:15.655 +0000 UTC
385+ }
386+
387+ Pythonとの交換の場合
388+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
389+
390+ Pythonで出力する場合は\ ``datetime.datetime.isoformat() ``\ メソッドを使うと良いでしょう。このメソッドはタイムゾーン情報を取り払い、現在のタイムゾーンの表記そのものをフォーマットして出力します。TypeScriptの\ ``new Date() ``\ はUTCであることを前提としてパースするため、出力時はUTCとして出すように心がける必要があります。このUTCで出色された文字列はTypeScriptでパースできます。
391+
392+ .. code-block :: python
393+
394+ from datetime import datetime, timezone
395+
396+ # localの場合はastimezone()を呼んでUTCに
397+ localtime = datetime.now()
398+ utctime = localtime.astimezone(timezone.utc)
399+ utctime.isoformat()
400+ # 2020-09-21T13:42:58.279772+00:00
401+
402+ # あるいは、最初からUTCで扱う
403+ utctime = datetime.utcnow()
404+ utctime.isoformat()
405+ # 2020-09-21T13:42:58.279772+00:00
406+
407+ パースはやっかいです。Stack Overflowでスレッドが立つぐらいのネタです\ [# ]_\ 。Python 3.7からは``fromisoformat()``\ というクラスメソッドが増えましたが、以前からの\ ``datetime.strptime() ``\ にフォーマット指定を与えた方が高速とのことです。
408+
409+ .. code-block :: python
410+
411+ from datetime import datetime
412+
413+ s = ' 2020-09-21T12:38:15.655Z'
414+
415+ datetime.fromisoformat(s.replace(' Z' , ' +00:00' ))
416+ # datetime.datetime(2020, 9, 21, 12, 38, 15, 655000, tzinfo=datetime.timezone.utc)
417+
418+ datetime.strptime(s, ' %Y-%m-%d T%H:%M:%S.%f %z' )
419+ # datetime.datetime(2020, 9, 21, 12, 38, 15, 655000, tzinfo=datetime.timezone.utc)
420+
421+ いっそのこと、エポック時刻で扱う方法の方がシンプルでしょう。TypeScriptはミリ秒単位で、Pythonは秒単位なので、1000で割ってから渡す必要があるのと、UTCの数値であることを明示する必要があります。
422+
423+ .. code-block :: python
424+
425+ from datetime import datetime
426+ datetime.fromtimestamp(1600691895655 / 1000.0 , timezone.utc)
427+ # datetime.datetime(2020, 9, 21, 12, 38, 15, 655000, tzinfo=datetime.timezone.utc)
428+
429+ .. [# ] https://stackoverflow.com/questions/127803/how-do-i-parse-an-iso-8601-formatted-date
0 commit comments