MariaDBプログラミングで役立つ!日付・時間関数のコード例とベストプラクティス

2025-05-27

以下に主要な日付・時間関数とその説明をいくつかご紹介します。

現在の日付・時刻を取得する関数

  • SYSDATE(): NOW() と似ていますが、関数が実行された時点の時刻を返します。NOW() はステートメントの開始時刻を返します。
  • CURTIME() / CURRENT_TIME(): 現在の時刻を HH:MM:SS 形式で返します。
    SELECT CURTIME(); -- 例: 17:32:39
    
  • CURDATE() / CURRENT_DATE(): 現在の日付を YYYY-MM-DD 形式で返します。
    SELECT CURDATE(); -- 例: 2025-05-25
    
  • NOW(): 現在の日付と時刻を YYYY-MM-DD HH:MM:SS 形式で返します。ミリ秒の精度を指定することもできます。
    SELECT NOW(); -- 例: 2025-05-25 17:32:39
    SELECT NOW(3); -- 例: 2025-05-25 17:32:39.123 (ミリ秒精度)
    

日付・時刻の加算・減算を行う関数

  • SUBTIME(expr1, expr2): 時間を日時値または時間値から減算します。
    SELECT SUBTIME('10:00:00', '01:30:00'); -- 例: 08:30:00
    
  • ADDTIME(expr1, expr2): 時間を時間または日時値に加算します。
    SELECT ADDTIME('10:00:00', '01:30:00'); -- 例: 11:30:00
    
  • SUBDATE(date, INTERVAL value unit): DATE_SUB() の同義語です。
  • DATE_SUB(date, INTERVAL value unit): 指定された日付から指定された期間を減算します。
    SELECT DATE_SUB('2025-05-25', INTERVAL 30 DAY);  -- 30日前
    -- 例: 2025-04-25
    
  • ADDDATE(date, INTERVAL value unit): DATE_ADD() の同義語です。
  • DATE_ADD(date, INTERVAL value unit): 指定された日付に指定された期間を加算します。
    • date: 操作対象の日付または日時。
    • value: 加算する数値。
    • unit: 加算する単位 (例: DAY, MONTH, YEAR, HOUR, MINUTE, SECONDなど)。
    SELECT DATE_ADD('2025-05-25', INTERVAL 7 DAY);   -- 7日後
    -- 例: 2025-06-01
    SELECT DATE_ADD(NOW(), INTERVAL 1 MONTH);       -- 1ヶ月後
    -- 例: 2025-06-25 17:32:39
    

日付・時刻の差を計算する関数

  • TIMESTAMPDIFF(unit, datetime_expr1, datetime_expr2): 2つの日時式間の指定された単位での差を返します。
    • unit: 差を計算する単位 (例: SECOND, MINUTE, HOUR, DAY, MONTH, YEARなど)。
    SELECT TIMESTAMPDIFF(HOUR, '2025-05-25 10:00:00', '2025-05-25 15:00:00'); -- 例: 5
    SELECT TIMESTAMPDIFF(MONTH, '2024-01-01', '2025-05-25'); -- 例: 16
    
  • TIMEDIFF(expr1, expr2): 2つの時間または日時値の差を返します。
    SELECT TIMEDIFF('10:30:00', '08:00:00'); -- 例: 02:30:00
    
  • DATEDIFF(expr1, expr2): 2つの日付間の日数を返します(expr1 - expr2)。時間部分は考慮されません。
    SELECT DATEDIFF('2025-05-30', '2025-05-25'); -- 例: 5
    

日付・時刻の一部を抽出する関数

  • EXTRACT(unit FROM date): 日付の特定の部分を抽出します。DATE_ADDDATE_SUBunitと同じものが使えます。
    SELECT EXTRACT(YEAR FROM '2025-05-25 17:32:39'); -- 例: 2025
    SELECT EXTRACT(HOUR FROM '2025-05-25 17:32:39'); -- 例: 17
    
  • WEEK(date) / WEEKOFYEAR(date): 年の週番号を返します。モードによって週の始まりが異なります。
  • QUARTER(date): 日付の四半期を返します (1-4)。
  • SECOND(time): 時刻の秒を返します (0-59)。
  • MINUTE(time): 時刻の分を返します (0-59)。
  • HOUR(time): 時刻の時間を返します (0-23)。
  • DAYNAME(date): 曜日の名前を返します (例: 'Sunday')。
  • WEEKDAY(date): 曜日のインデックスを返します (0=月曜日, 1=火曜日, ... , 6=日曜日)。
  • DAYOFWEEK(date): 曜日のインデックスを返します (1=日曜日, 2=月曜日, ... , 7=土曜日)。
  • DAY(date) / DAYOFMONTH(date): 月の日を返します (1-31)。
  • MONTHNAME(date): 月の名前を返します (例: 'May')。
  • MONTH(date): 日付の月を返します (1-12)。
  • YEAR(date): 日付の年を返します。
  • DATE_FORMAT(date, format): 日付を指定された形式の文字列にフォーマットします。format文字列には、特定の日付や時刻の要素を表す「指定子」(%Y, %m, %d, %Hなど)を使用します。
    SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日 %H時%i分%s秒');
    -- 例: 2025年05月25日 17時32分39秒
    
    SELECT DATE_FORMAT('2025-05-25', '%W, %M %D, %Y');
    -- 例: Saturday, May 25th, 2025
    
    よく使われる指定子の一部:
    • %Y: 4桁の年 (例: 2025)
    • %m: 2桁の月 (例: 05)
    • %d: 2桁の日 (例: 25)
    • %H: 2桁の24時間表記の時 (例: 17)
    • %i: 2桁の分 (例: 32)
    • %s: 2桁の秒 (例: 39)
    • %W: 曜日名 (例: Saturday)
    • %M: 月名 (例: May)
    • %D: 英語の序数付きの日 (例: 25th)
  • MAKETIME(hour, minute, second): 時、分、秒から時刻を作成します。
  • MAKEDATE(year, dayofyear): 年と年の通算日から日付を作成します。
  • LAST_DAY(date): 指定された日付の月の最終日を返します。
    SELECT LAST_DAY('2025-02-15'); -- 例: 2025-02-28
    
  • FROM_UNIXTIME(unix_timestamp): Unixタイムスタンプを日時値に変換します。
  • UNIX_TIMESTAMP(date): 日付をUnixタイムスタンプ (1970年1月1日 00:00:00 UTCからの秒数) に変換します。


データ型不一致によるエラー

よくあるエラー

  • [22007][1292] Incorrect datetime value: '...'
  • Data truncated for column '...' at row X
  • Incorrect datetime value: '...' for function str_to_date

原因
日付・時間関数に、期待されるデータ型(DATE, TIME, DATETIME)ではない値や、認識できない形式の文字列を渡そうとした場合に発生します。特に文字列から日付への変換(STR_TO_DATE)で、指定したフォーマットと実際の文字列が一致しないとこのエラーになります。

トラブルシューティング

  • 暗黙の型変換に注意
    • 文字列を直接日付型のカラムに挿入しようとすると、MariaDBが自動的に変換を試みますが、標準的な形式(YYYY-MM-DD または YYYY-MM-DD HH:MM:SS)でないと失敗することがあります。
    • 明示的に STR_TO_DATE() を使用することをお勧めします。
  • 入力値の確認
    • 関数に渡す値が本当に日付や時刻として有効な形式であるか確認します。例えば、 '2025-02-30' のように存在しない日付はエラーになります。
  • STR_TO_DATE() のフォーマット文字列の確認
    • 例: STR_TO_DATE('2025年05月25日', '%Y/%m/%d') のように、実際の文字列が '2025年05月25日' なのに、フォーマットを '/%m/%d' と指定するとエラーになります。正しくは '%Y年%m月%d日' です。
    • 大文字・小文字も区別されます(例: %Y%y は異なる)。

タイムゾーン関連の問題

よくあるエラー

  • 日時データが挿入された時間と異なる。
  • NOW()CURDATE() が期待する時間と異なる。

原因
MariaDBサーバーのタイムゾーン設定と、アプリケーションやクライアントのタイムゾーン設定が異なる場合に、特に NOW()UTC_TIMESTAMP() などの関数で取得される時刻がずれることがあります。

トラブルシューティング

  • UTCでデータを保存する
    • タイムゾーンの違いによる問題を避ける最も確実な方法は、データベースに常にUTCで日時を保存することです。
    • UTC_TIMESTAMP() 関数を使用します。
    • 表示する際に、アプリケーション側でユーザーのタイムゾーンに変換します。
  • セッションのタイムゾーン設定
    • 特定のセッションでタイムゾーンを変更できます。
    SET time_zone = 'Asia/Tokyo';
    SET time_zone = '+9:00'; -- UTCからのオフセット
    
  • MariaDBサーバーのタイムゾーン設定の確認
    SELECT @@global.time_zone, @@session.time_zone;
    
    通常は SYSTEM に設定されており、OSのタイムゾーンに従います。

日付範囲の問題

よくあるエラー

  • 計算結果がMariaDBのサポート範囲外の日付になる場合。
  • YEAR(date)MONTH(date) などで、日付が '0000-00-00' の場合。

原因
MariaDBは、一部の古いバージョンや設定で '0000-00-00' を有効な日付として扱うことがありますが、これは多くの日付関数で問題を引き起こします。また、日付の加減算によって、サポートされる日付範囲 ('1000-01-01' から '9999-12-31 23:59:59.999999') を超える結果が生じる場合もエラーまたはNULLになります。

トラブルシューティング

  • 計算結果の範囲チェック
    • 日付の加減算を行う際に、結果がMariaDBのサポート範囲内にあることを確認します。
  • 無効な日付の排除/修正
    • カラムに '0000-00-00' のような無効な日付が存在しないか確認し、あれば修正するか、NULL として扱うようにします。
    • SQL_MODENO_ZERO_DATENO_ZERO_IN_DATE を設定すると、無効な日付の挿入を防ぐことができます。

単位の誤用(INTERVAL など)

よくあるエラー

  • DATE_ADD()DATE_SUB() で期待通りの結果にならない。

原因
INTERVAL 句で使用する単位(DAY, MONTH, YEAR, HOUR, MINUTE, SECOND など)を間違えている。特に MONTHDAY を混同したり、時間単位を指定すべきところに日付単位を指定したりすることがあります。

トラブルシューティング

  • 引数の型の確認
    • ADDTIME()SUBTIME() などは時間または日時を扱います。日付だけを渡すとエラーになるか、予期しない結果になります。
  • 単位の確認
    • 例: DATE_ADD(NOW(), INTERVAL 1 DAYS) は正しくありません。単位は単数形(DAY)または複数形(DAYS)のどちらでも動作しますが、混乱を避けるために単数形の使用が推奨されます。
    • '1 01:00:00' のように、複数の単位を組み合わせる場合は 'DAY HOUR' のように指定する必要があります。
      SELECT DATE_ADD(NOW(), INTERVAL '1 01:00:00' DAY_HOUR); -- 1日1時間後
      

NULL 値の扱い

よくあるエラー

  • 日付・時間関数が NULL を返す。

原因
日付・時間関数に NULL 値を引数として渡すと、多くの場合、結果も NULL になります。これはエラーではありませんが、アプリケーション側で NULL の結果を期待していない場合に問題となることがあります。

トラブルシューティング

  • 入力値の NULL チェック
    • 関数に渡す前に、入力値が NULL でないかを確認します。
    • IFNULL(column, default_value) などを使用して、NULL の場合に代替値を指定することを検討します。
    • COALESCE(expr1, expr2, ...) も複数の式の中から最初の非NULL値を返すので便利です。

文字列と数値の自動変換

よくあるエラー

  • 日付文字列が数値として扱われ、予期しない結果になる。

原因
MariaDBは柔軟な型変換を行いますが、これが意図しない結果を招くことがあります。特に日付文字列を数値コンテキストで扱うと、その文字列の数値表現が使われることがあります。

  • 明示的な型変換の使用
    • 日付として扱いたい場合は、必ず STR_TO_DATE()CAST(... AS DATE) などを使用して明示的に変換します。
    • 数値として扱いたい場合は、+0 を加えるなどの方法で数値型に強制変換できます。
  • テストデータの使用
    • 問題を再現できる最小限のテストデータを作成し、それを使ってデバッグを行います。
  • SQLクエリの簡素化
    • 複雑なクエリで問題が発生した場合、日付・時間関数を含む部分だけを抜き出して、単純な SELECT 文でテストします。
  • エラーメッセージの確認
    • MariaDBのエラーメッセージは非常に役立ちます。エラー番号 ([22007][1292]) やメッセージの詳細を読み解くことで、原因を特定しやすくなります。


現在の日付・時刻の取得

最も基本的な操作です。アプリケーションから現在時刻をデータベースに記録する場合によく使われます。

-- 現在の日時を取得
SELECT NOW();
-- 例: 2025-05-25 17:35:12

-- 現在の日付のみを取得
SELECT CURDATE();
-- 例: 2025-05-25

-- 現在の時刻のみを取得
SELECT CURTIME();
-- 例: 17:35:12

プログラミング例(PHPの場合)

<?php
$servername = "localhost";
$username = "your_username";
$password = "your_password";
$dbname = "your_database";

// データベース接続
$conn = new mysqli($servername, $username, $password, $dbname);

// 接続チェック
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// 現在の日時を取得するクエリ
$sql = "SELECT NOW() AS current_datetime";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    $row = $result->fetch_assoc();
    echo "現在のシステム日時: " . $row["current_datetime"] . "<br>";
} else {
    echo "結果がありません。<br>";
}

// 現在の日付を取得するクエリ
$sql = "SELECT CURDATE() AS current_date";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    $row = $result->fetch_assoc();
    echo "現在の日付: " . $row["current_date"] . "<br>";
} else {
    echo "結果がありません。<br>";
}

$conn->close();
?>

日付の加算・減算

特定の日付から将来または過去の日付を計算する場合に非常に便利です。例えば、サブスクリプションの有効期限計算など。

-- 今日の日付に7日加算
SELECT DATE_ADD(CURDATE(), INTERVAL 7 DAY);
-- 例: 2025-06-01

-- 2ヶ月前の日付を計算
SELECT DATE_SUB(CURDATE(), INTERVAL 2 MONTH);
-- 例: 2025-03-25

-- 特定の日時データに3時間30分加算
SELECT DATE_ADD('2025-05-25 10:00:00', INTERVAL '3:30' HOUR_MINUTE);
-- 例: 2025-05-25 13:30:00

プログラミング例(Pythonの場合)

import mysql.connector
from datetime import datetime, timedelta

# データベース接続情報
db_config = {
    'host': 'localhost',
    'user': 'your_username',
    'password': 'your_password',
    'database': 'your_database'
}

try:
    conn = mysql.connector.connect(**db_config)
    cursor = conn.cursor()

    # 今日の日付に7日加算するSQL
    sql_add_days = "SELECT DATE_ADD(CURDATE(), INTERVAL %s DAY) AS future_date"
    days_to_add = 7
    cursor.execute(sql_add_days, (days_to_add,))
    result_add_days = cursor.fetchone()
    print(f"今日から{days_to_add}日後: {result_add_days[0]}")

    # 特定の日時から時間を減算するSQL (例: 請求書の支払い期限が過ぎたかどうか)
    specific_datetime = datetime(2025, 5, 20, 10, 0, 0) # Pythonのdatetimeオブジェクト
    hours_to_subtract = 5
    sql_sub_hours = "SELECT DATE_SUB(%s, INTERVAL %s HOUR) AS past_datetime"
    cursor.execute(sql_sub_hours, (specific_datetime, hours_to_subtract))
    result_sub_hours = cursor.fetchone()
    print(f"{specific_datetime} から {hours_to_subtract}時間前: {result_sub_hours[0]}")

except mysql.connector.Error as err:
    print(f"Error: {err}")

finally:
    if conn:
        cursor.close()
        conn.close()

日付の部分抽出

年、月、日、曜日などを個別に取得する場合に便利です。レポート作成やデータ分析によく使われます。

-- 特定の日の年、月、日を抽出
SELECT
    YEAR('2025-05-25') AS year_val,
    MONTH('2025-05-25') AS month_val,
    DAY('2025-05-25') AS day_val;
-- 例: year_val=2025, month_val=5, day_val=25

-- 曜日の名前と、曜日インデックス(日曜日=1)を取得
SELECT
    DAYNAME('2025-05-25') AS day_name,
    DAYOFWEEK('2025-05-25') AS day_of_week_index;
-- 例: day_name='Sunday', day_of_week_index=1

-- 時刻の時、分、秒を抽出
SELECT
    HOUR('17:35:12') AS hour_val,
    MINUTE('17:35:12') AS minute_val,
    SECOND('17:35:12') AS second_val;
-- 例: hour_val=17, minute_val=35, second_val=12

プログラミング例(Node.jsの場合)

const mysql = require('mysql');

// データベース接続設定
const connection = mysql.createConnection({
    host: 'localhost',
    user: 'your_username',
    password: 'your_password',
    database: 'your_database'
});

connection.connect(err => {
    if (err) {
        console.error('Error connecting to the database: ' + err.stack);
        return;
    }
    console.log('Connected to the database as id ' + connection.threadId);

    const targetDate = '2025-05-25';

    // 日付の一部を抽出するSQL
    const sql = `
        SELECT
            YEAR(?) AS year_val,
            MONTH(?) AS month_val,
            DAY(?) AS day_val,
            DAYNAME(?) AS day_name;
    `;

    connection.query(sql, [targetDate, targetDate, targetDate, targetDate], (error, results) => {
        if (error) {
            console.error('Error executing query: ' + error.stack);
            return;
        }

        if (results.length > 0) {
            const row = results[0];
            console.log(`日付: ${targetDate}`);
            console.log(`  年: ${row.year_val}`);
            console.log(`  月: ${row.month_val}`);
            console.log(`  日: ${row.day_val}`);
            console.log(`  曜日: ${row.day_name}`);
        } else {
            console.log('No results found.');
        }

        connection.end(); // 接続を閉じる
    });
});

日付のフォーマット変換

ユーザーフレンドリーな表示形式に変換したり、特定のデータインポート/エクスポート形式に合わせたりする場合に不可欠です。

-- 標準の日時を日本語形式にフォーマット
SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日 %H時%i分%s秒');
-- 例: 2025年05月25日 17時35分12秒

-- 特定の文字列形式をMariaDBの日付型に変換
SELECT STR_TO_DATE('2025/05/25 14:30:00', '%Y/%m/%d %H:%i:%s');
-- 例: 2025-05-25 14:30:00

-- 月の英語名と日の序数付きフォーマット
SELECT DATE_FORMAT('2025-05-25', '%W, %M %D, %Y');
-- 例: Sunday, May 25th, 2025

プログラミング例(Javaの場合)

import java.sql.*;

public class DateFormatExample {
    public static void main(String[] args) {
        String url = "jdbc:mariadb://localhost:3306/your_database";
        String user = "your_username";
        String password = "your_password";

        try (Connection con = DriverManager.getConnection(url, user, password)) {
            System.out.println("データベースに接続しました。");

            // 現在の日時を日本語形式でフォーマットするSQL
            String sqlFormat = "SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日 %H時%i分%s秒') AS formatted_datetime";
            try (Statement stmt = con.createStatement();
                 ResultSet rs = stmt.executeQuery(sqlFormat)) {
                if (rs.next()) {
                    System.out.println("フォーマットされた日時: " + rs.getString("formatted_datetime"));
                }
            }

            // 特定の文字列から日付型に変換するSQL
            String dateString = "2023-10-26 10:00:00 AM"; // 例えば、外部システムからのデータ
            String formatString = "%Y-%m-%d %h:%i:%s %p"; // MariaDBのフォーマット指定子
            String sqlParse = "SELECT STR_TO_DATE(?, ?) AS parsed_datetime";
            try (PreparedStatement pstmt = con.prepareStatement(sqlParse)) {
                pstmt.setString(1, dateString);
                pstmt.setString(2, formatString);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        // MariaDBはDATETIME型で返す
                        System.out.println("パースされた日時: " + rs.getTimestamp("parsed_datetime"));
                    }
                }
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

イベント間の期間や年齢の計算などに使用されます。

-- 2つの日付間の日数を計算
SELECT DATEDIFF('2025-06-01', '2025-05-25') AS days_diff;
-- 例: days_diff=7

-- 2つの日時間の時間差を計算 (結果は時間型)
SELECT TIMEDIFF('2025-05-25 18:00:00', '2025-05-25 15:30:00') AS time_diff;
-- 例: time_diff=02:30:00

-- 2つの日時間の年数を計算
SELECT TIMESTAMPDIFF(YEAR, '1990-01-15', CURDATE()) AS age_in_years;
-- 例: age_in_years=35 (現在の年と誕生日の年の差)

MariaDBの日付・時間関数は、データベースアプリケーション開発において非常に強力なツールです。上記で示した例はごく一部ですが、これらの関数を組み合わせることで、日付や時刻に関する様々な要件を満たすことができます。



アプリケーション言語の標準ライブラリを利用する

ほとんどのプログラミング言語には、日付と時刻を扱うための豊富な標準ライブラリが用意されています。これらは、日付のパース(解析)、フォーマット、加算・減算、差の計算など、データベース関数と同様の機能を提供します。

メリット

  • デバッグのしやすさ
    アプリケーションコードとしてデバッグしやすくなります。
  • 可搬性
    データベースに依存しないロジックになるため、将来的に別のデータベースシステムへ移行する際にコードの変更が少なくて済みます。
  • 柔軟性
    より複雑なロジックや、特定のビジネス要件に合わせたカスタムの日付計算を柔軟に実装できます。
  • パフォーマンス
    シンプルな日付操作の場合、アプリケーション側で処理することでデータベースへの負荷を軽減できます。特に大量のレコードに対して複雑な計算を行う場合でも、一度データを取得してアプリケーション側で処理することで、データベースサーバーのリソースを節約できる可能性があります。

デメリット

  • SQLクエリの複雑さ
    日付でフィルタリングやソートを行う場合、結局SQLの日付関数を使用する必要が出てきます。
  • 一貫性
    複数のアプリケーションが同じデータベースにアクセスする場合、それぞれが独自の日付操作ロジックを持つと、結果に一貫性がなくなるリスクがあります。
  • データ転送量
    日付計算の結果だけでなく、元の生の日付データをすべてアプリケーションに転送する必要があるため、データ量が大きくなる場合はネットワークI/Oが増加します。

具体的な例

a. PHPの DateTime クラス

PHPの DateTime クラスは、日付と時刻をオブジェクト指向で扱うための強力なツールです。

<?php
// 現在の日時を取得
$now = new DateTime();
echo "現在の日時: " . $now->format('Y-m-d H:i:s') . "<br>";

// 7日後を計算
$futureDate = new DateTime();
$futureDate->modify('+7 days');
echo "7日後: " . $futureDate->format('Y-m-d') . "<br>";

// 2つの日付の差を計算
$date1 = new DateTime('2025-05-20');
$date2 = new DateTime('2025-05-25');
$interval = $date1->diff($date2);
echo "日付の差: " . $interval->days . " 日<br>"; // 日数差
echo "詳細な差: " . $interval->format('%y年%m月%d日') . "<br>";
?>

b. Pythonの datetime モジュール

Pythonの datetime モジュールも非常に強力で、日付と時刻の操作全般をカバーします。

from datetime import datetime, timedelta, date

# 現在の日時を取得
now = datetime.now()
print(f"現在の日時: {now.strftime('%Y-%m-%d %H:%M:%S')}")

# 1ヶ月前を計算
one_month_ago = now - timedelta(days=30) # 厳密には30日前の計算
print(f"約1ヶ月前: {one_month_ago.strftime('%Y-%m-%d')}")

# 特定の文字列から日付をパース
date_string = "2024年12月25日"
parsed_date = datetime.strptime(date_string, '%Y年%m月%d日').date()
print(f"パースされた日付: {parsed_date}")

# 2つの日付間の差を計算
date_a = date(2025, 5, 1)
date_b = date(2025, 5, 20)
delta = date_b - date_a
print(f"日付間の日数差: {delta.days}日")

c. JavaScriptの Date オブジェクト

フロントエンドやNode.js環境で利用されます。

// 現在の日時を取得
const now = new Date();
console.log(`現在の日時: ${now.toLocaleString()}`);

// 10日後を計算
const tenDaysLater = new Date(now);
tenDaysLater.setDate(now.getDate() + 10);
console.log(`10日後: ${tenDaysLater.toLocaleDateString()}`);

// 2つの日付間のミリ秒差を計算し、日数に変換
const date1 = new Date('2025-05-01');
const date2 = new Date('2025-05-20');
const diffMs = date2.getTime() - date1.getTime(); // ミリ秒差
const diffDays = diffMs / (1000 * 60 * 60 * 24); // 日数
console.log(`日付間の日数差: ${diffDays}日`);

// 文字列から日付をパース (ISO 8601形式が推奨)
const parsedDate = new Date('2025-05-25T10:00:00');
console.log(`パースされた日時: ${parsedDate.toLocaleString()}`);

ORM (Object-Relational Mapping) の日付・時間機能を利用する

多くのORMフレームワーク(LaravelのEloquent、Django ORM、Hibernateなど)は、データベースのデータ型とプログラミング言語のデータ型間のマッピングを自動で行ってくれます。これにより、開発者は直接SQLの日付関数を書く代わりに、オブジェクト指向のメソッドを使って日付操作を行うことができます。

メリット

  • 生産性
    コード量が削減され、開発が迅速になります。
  • 安全性
    プリペアドステートメントが自動的に利用されるため、SQLインジェクションのリスクが低減します。
  • 抽象化
    SQLの知識をあまり持たなくても、日付操作が可能です。

デメリット

  • 複雑なクエリへの対応
    ORMの機能だけでは対応できない複雑な日付クエリの場合、結局生のSQLを書く必要が出てくることがあります。
  • オーバーヘッド
    ORM層を介するため、わずかなパフォーマンスオーバーヘッドが発生する可能性があります。

具体的な例(Laravel Eloquentの場合 - PHP)

Laravelのcreated_atupdated_atカラムは、自動的にCarbon(PHPのDateTimeを拡張したライブラリ)インスタンスとして扱われます。

<?php

use App\Models\Order;
use Carbon\Carbon;

// 例: 過去7日間の注文を取得
$recentOrders = Order::where('created_at', '>=', Carbon::now()->subDays(7))->get();

foreach ($recentOrders as $order) {
    echo "注文ID: " . $order->id . ", 注文日時: " . $order->created_at->format('Y年m月d日 H:i') . "<br>";

    // 注文が作成されてから何日経過したか
    echo "経過日数: " . $order->created_at->diffInDays(Carbon::now()) . " 日<br>";
}

// 例: ユーザーの年齢を計算(誕生日カラムがある場合)
// Предпо: Userモデルに`birth_date`カラムがあるとする
$user = User::find(1);
if ($user && $user->birth_date) {
    echo "ユーザー名: " . $user->name . "<br>";
    echo "年齢: " . $user->birth_date->age . "歳<br>"; // Carbonのageプロパティ
}
?>

ストアドファンクションやビューの活用

繰り返し使用される複雑な日付計算ロジックや、複数のアプリケーションで共通のロジックを強制したい場合、MariaDBのストアドファンクションとして日付操作をカプセル化する方法があります。

メリット

  • セキュリティ
    アプリケーションに直接SQLロジックを記述する代わりに、関数呼び出しのみを許可することができます。
  • パフォーマンス
    データベースサーバー内で処理が完結するため、ネットワークI/Oを減らせる場合があります。
  • ロジックの一元化
    データベースレベルでロジックを定義するため、どのアプリケーションからアクセスしても同じ結果が得られます。

デメリット

  • データベース依存
    データベースベンダーに強く依存するコードになります。
  • デバッグの難しさ
    ストアドファンクションのデバッグは、アプリケーションコードに比べて難しい場合があります。
DELIMITER //

CREATE FUNCTION CalculateAge(birth_date DATE)
RETURNS INT
DETERMINISTIC
BEGIN
    RETURN TIMESTAMPDIFF(YEAR, birth_date, CURDATE());
END //

DELIMITER ;

-- 使用例
SELECT CalculateAge('1990-01-15') AS age;
-- 例: age=35 (現在の年と誕生日の年の差)
  • 開発の生産性を重視、一般的なCRUD操作
    ORMフレームワークが提供する日付機能を活用します。
  • データの一貫性を重視、複数アプリケーションからのアクセス
    ストアドファンクションを検討する価値があります。
  • 複雑な日付計算、データベース側でのフィルタリング/集計
    MariaDBの日付関数を使うのが効率的です。特に、WHERE句やORDER BY句で日付を条件にする場合は、データベースの関数を使うべきです。
  • 簡単な日付操作、表示目的
    アプリケーション言語の標準ライブラリを使うのが最もシンプルで柔軟です。