できない.dev

日付文字列を日付型にするには

「2026-08-14」のような文字列を日付・日時の型へ読み込む基本形を各言語で示す。
書式を明示して読む書き方と、読んだ値にタイムゾーンが付くかどうかの差までを扱う。

公開:

各言語見出しの横のバッジは検証状態を表す。実行確認済みはコードを実際に実行して確認したもの、静的確認は構文と公式 API ドキュメントで確認したものである。

Python 実行確認済み

from datetime import datetime, date
 
# strptime は書式を明示して読む。1 文字でも違えば ValueError になる
dt = datetime.strptime("2026-08-14 09:05:00", "%Y-%m-%d %H:%M:%S")
print(dt)                                    # 2026-08-14 09:05:00
print(dt.tzinfo)                             # None(naive のまま)
 
print(date.fromisoformat("2026-08-14"))      # 2026-08-14
print(datetime.fromisoformat("2026-08-14T09:05:00+09:00"))  # オフセット付きは aware
 
try:
    datetime.strptime("2026/08/14", "%Y-%m-%d")
except ValueError as e:
    print("ValueError:", e)                  # 書式不一致は例外で分かる

strptime は第 2 引数の書式に完全一致した文字列だけを受け取り、合わなければ ValueError を投げる。
ISO 8601 と分かっているなら書式を書かずに済む fromisoformat のほうが短く書ける。
どちらも文字列にオフセットが含まれていなければ tzinfo は None のままなので、タイムゾーンを伴う計算をする前に aware へ揃える。

うまくいかない時: Python で datetime の naive と aware を比較できず TypeError になる

JavaScript 実行確認済み

// 仕様で保証されるのは ISO 8601 だけ。しかも日付のみと日時とで基準が変わる
console.log(new Date("2026-08-14").toISOString());                // 2026-08-14T00:00:00.000Z(UTC 扱い)
console.log(new Date("2026-08-14T09:05:00+09:00").toISOString()); // 2026-08-14T00:05:00.000Z
 
// オフセットを省いた日時はローカル時刻として読まれる
console.log(new Date("2026-08-14T09:05:00").getHours()); // 9(実行環境のローカルで 9 時)
 
// 非 ISO の書式は実装依存。読めないと Invalid Date になる
console.log(Number.isNaN(new Date("14/08/2026").getTime())); // true = パース失敗
 
// 独自書式は自分で分解して組み立てる(月は 0 始まり)
const [d, m, y] = "14/08/2026".split("/").map(Number);
console.log(new Date(y, m - 1, d).toDateString()); // Fri Aug 14 2026

new Date が仕様として保証するのは ISO 8601 の書式だけで、それ以外の解釈は実装に委ねられている。
同じ ISO でも日付だけの "2026-08-14" は UTC、時刻まで書いてオフセットを省いた場合はローカル時刻として読まれるため、日付だけ扱いたいときは基準の違いで 1 日ずれることがある。
読めなかったときは例外ではなく Invalid Date が返るので、getTime() が NaN かどうかで判定する。

TypeScript 実行確認済み

const raw: string = "2026-08-14T09:05:00+09:00";
console.log(new Date(raw).toISOString()); // 2026-08-14T00:05:00.000Z
 
// new Date は失敗しても Date 型を返すので、型では失敗に気づけない
function parseIso(s: string): Date {
  const d = new Date(s);
  if (Number.isNaN(d.getTime())) throw new Error(`日付として読めない: ${s}`);
  return d;
}
 
console.log(parseIso("2026-08-14").getUTCFullYear()); // 2026
try {
  parseIso("2026-13-99");
} catch (e) {
  console.log((e as Error).message); // 日付として読めない: 2026-13-99
}

使い方は JavaScript と同じで、new Date は失敗しても戻り値が Date 型のままである。
つまり型検査ではパース失敗を防げないので、境界で NaN を確かめて弾く関数を 1 つ用意し、そこを通った値だけを後段へ渡す。
厳密な書式検証や独自書式が必要なら date-fns や Temporal の polyfill を使う。

Go 静的確認

package main
 
import (
	"fmt"
	"time"
)
 
func main() {
	// レイアウトは書式記号ではなく参照時刻 2006-01-02 15:04:05 そのもので書く
	d, _ := time.Parse("2006-01-02", "2026-08-14")
	fmt.Println(d) // 2026-08-14 00:00:00 +0000 UTC(場所を書かないと UTC)
 
	t, _ := time.Parse(time.RFC3339, "2026-08-14T09:05:00+09:00")
	fmt.Println(t.Format(time.RFC3339))
 
	// 場所を渡すと、オフセット無しの文字列をその地域の時刻として読む
	jst, _ := time.LoadLocation("Asia/Tokyo")
	l, _ := time.ParseInLocation("2006-01-02 15:04", "2026-08-14 09:05", jst)
	fmt.Println(l)
 
	if _, err := time.Parse("2006-01-02", "2026/08/14"); err != nil {
		fmt.Println("parse error:", err)
	}
}

time.Parse のレイアウトは %Y のような書式記号ではなく、参照時刻 2006-01-02 15:04:05 を並べ替えて表す点が独特である。
文字列にオフセットが無く、かつ time.Parse を使うと結果は UTC になるため、地域時刻として読みたいときは time.ParseInLocation に場所を渡す。
書式不一致は error で返るので戻り値を必ず確認する。

Rust 静的確認

// Cargo.toml に chrono = "0.4" を追加する
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime};
 
fn main() {
    let d = NaiveDate::parse_from_str("2026-08-14", "%Y-%m-%d").unwrap();
    println!("{}", d); // 2026-08-14
 
    let dt = NaiveDateTime::parse_from_str("2026/08/14 09:05", "%Y/%m/%d %H:%M").unwrap();
    println!("{}", dt);
 
    let off: DateTime<FixedOffset> =
        DateTime::parse_from_rfc3339("2026-08-14T09:05:00+09:00").unwrap();
    println!("{}", off);
 
    // 失敗は Result で返るので、unwrap せず match や ? で扱う
    println!("{}", NaiveDate::parse_from_str("2026/08/14", "%Y-%m-%d").is_err()); // true
}

標準ライブラリに日付の書式解析は無いので chrono を使う。
タイムゾーンを持たない値は NaiveDate / NaiveDateTime、オフセット付きの文字列は DateTime::parse_from_rfc3339 で受ける。
いずれも Result を返すため、unwrap で潰さず match や ? で失敗を扱うと入力エラーをそのまま呼び出し元へ伝えられる。

Java 実行確認済み

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
 
public class Main {
    public static void main(String[] args) {
        System.out.println(LocalDate.parse("2026-08-14"));                    // 2026-08-14
        System.out.println(OffsetDateTime.parse("2026-08-14T09:05:00+09:00")); // 2026-08-14T09:05+09:00
 
        DateTimeFormatter f = DateTimeFormatter.ofPattern("uuuu/MM/dd HH:mm");
        System.out.println(LocalDateTime.parse("2026/08/14 09:05", f));        // 2026-08-14T09:05
 
        try {
            LocalDate.parse("2026/08/14");
        } catch (DateTimeParseException e) {
            System.out.println("DateTimeParseException: " + e.getMessage());
        }
    }
}

java.time の parse は ISO 8601 が既定なので、LocalDate.parse や OffsetDateTime.parse は書式指定なしで読める。
独自書式は DateTimeFormatter.ofPattern を渡す。
パターンの年は yyyy ではなく uuuu を選ぶと、紀元をまたぐ入力で意図しない解釈になるのを避けられる。
失敗は DateTimeParseException になる。

C# 実行確認済み

using System;
using System.Globalization;
 
class Program {
    static void Main() {
        var d = DateOnly.ParseExact("2026-08-14", "yyyy-MM-dd", CultureInfo.InvariantCulture);
        Console.WriteLine(d.ToString("yyyy-MM-dd")); // 2026-08-14
 
        var o = DateTimeOffset.Parse("2026-08-14T09:05:00+09:00", CultureInfo.InvariantCulture);
        Console.WriteLine(o.ToString("o")); // 2026-08-14T09:05:00.0000000+09:00
 
        // 失敗を例外にしたくないときは TryParseExact
        var ok = DateTime.TryParseExact("2026/08/14 09:05", "yyyy/MM/dd HH:mm",
            CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt);
        Console.WriteLine($"{ok} {dt:yyyy-MM-dd HH:mm}"); // True 2026-08-14 09:05
 
        Console.WriteLine(DateTime.TryParseExact("14/08/2026", "yyyy-MM-dd",
            CultureInfo.InvariantCulture, DateTimeStyles.None, out _)); // False
    }
}

DateTime.Parse は既定で実行環境のカルチャに従うため、同じ文字列でも動く PC によって結果が変わる。
書式が決まっているなら ParseExact に CultureInfo.InvariantCulture を渡して固定する。
失敗を例外にしたくない場面では TryParseExact を使い、戻り値の bool で成否を判定する。

つまずき

「読めているのに値がずれる」ときは、たいてい書式ではなくタイムゾーンの解釈が原因である。
JavaScript の new Date は、日付だけの "2026-08-14" を UTC の 0 時として読む一方、"2026-08-14T09:05:00" のようにオフセットを省いた日時はローカル時刻として読む。
UTC より西側の環境では前者の日付が 1 日前として表示されるため、日付だけを扱うつもりの処理が月末や締め日でずれる。
Go も同様で、time.Parse は場所を指定しない限り UTC として読む。
日付だけを扱いたいなら、日時型ではなく日付専用の型(Python の date、C# の DateOnly、Java の LocalDate)で受けるのが確実である。

書式は明示して読む

入力の書式が決まっているなら、推測に任せる関数ではなく書式を渡す関数を選ぶ。
Python の strptime、Go の time.Parse、Java の DateTimeFormatter.ofPattern、C# の ParseExact はいずれも書式に一致しない入力を失敗として返すので、壊れたデータが黙って別の日付になることがない。
とくに C# の Parse と JavaScript の new Date は、実行環境のカルチャや実装依存の解釈が混ざる。
"03/04/2026" のような曖昧な入力は、書式を固定しないと 3 月 4 日と 4 月 3 日のどちらにも読めてしまう。

失敗の伝わり方が言語で違う

パース失敗の知らせ方は言語ごとに大きく異なる。
Python と Java は例外、Go と Rust は戻り値(error / Result)、C# は例外版と Try 版の両方がある。
JavaScript だけは例外も戻り値の型変化も無く、Invalid Date という「Date 型のまま壊れた値」が返る。
そのため JavaScript と TypeScript では、getTime() が NaN かどうかを確かめる検査を境界に置かないと、不正な入力が後段まで素通りして原因の分かりにくい表示崩れになる。

この記事は役立ちましたか?