33
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

うるう年の一年前を取得すると…

Last updated at Posted at 2023-12-08

冒頭

現場のPJでの詳細設計にて以下のような記載をしました。
「○○日より1年前の日付を取得する。」
特定の日付を基準にして、その前後の日付を取得するというよくある処理だと思うのですが
レビューにて「うるう年の一年前の日付を取得した場合どうなりますか?」と質問があり、私もふと疑問に思いました。

「うるう年の一年前の日付を取得したら、前年の3月1日なのか?それとも2月28日なのか?」

今回の記事はそんな疑問から始まった記事であり、実際にいくつかの言語、DBで試してみた結果を書いていきたいと思います。

Javaの場合

Javaにて日付の計算を行う場合、Calendarクラスを使用します。Caleandarクラスのインスタンスを生成し、生成したインスタンスのsetTimeメソッドの引数にDate型を指定することで日時の設定ができます。そしてaddメソッドにて第一引数にCalendar.YEAR、第二引数にint型(加算の場合は正の数、減算の場合は負の数)を指定することで日付の計算が可能となります。
以下がサンプルコードになります。

main.java
import java.util.Calendar;
import java.util.Date;
import java.text.SimpleDateFormat;

public class Main {
    public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Date date1 = sdf.parse("2020/02/29");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date1);
        calendar.add(Calendar.YEAR, -1);
        Date date2 = calendar.getTime();
        System.out.println(sdf.format(date2)); //2019/02/28
    }
}

Javaの場合はうるう年の一年前の日付を取得した場合、2月28日となりました。

JavaScriptの場合

JavaScriptにて日付の計算を行う場合、Date型のインスタンスを生成した後に、生成したインスタンスのsetFullYearメソッドを使用し、引数にて生成インスタンスのgetFullYearメソッド使用して取得した年を加算、減算することで可能となります。
(本記事では年単位の計算を行っていますが、setMonth、setDateメソッドを使用することで月単位、年単位での計算も可能です。)
以下がサンプルコードになります。

main.js
    var dt = new Date(2020, 1, 29);
    dt.setFullYear(dt.getFullYear() - 1);
    console.log(dt);//2019/03/01

JavaScriptの場合はうるう年の一年前の日付を取得した場合、3月1日となりました。
Javaでは2月28日、JavaScriptでは3月1日と「うるう年の1年前の日付を取得する」という処理について言語により結果が異なるということがわかりました。
引き続き他の言語、DBも見ていきます。

PHPの場合

PHPにて日付の計算を行う場合、strtotime関数を使用する方法とDateTimeクラスのmodifyメソッドを使用する方法の2つのやり方があります。
以下がサンプルコードになります。

main.php
<?php
echo date("Y-m-d", strtotime("2020-02-29 -1 year")); 
$date = new DateTime('2020-02-29');// 2019-03-01
$date->modify('-1 year');
echo $date->format('Y-m-d'); // 2019-03-01
?>

strtotime関数を使用する方法、DateTimeクラスのmodifyメソッドを使用する方法いずれも3月1日となりました。

PostgreSQLの場合

PostgreSQLにて日付の計算を行う場合、INTERVAL型で時間を指定し、日付から加算、減算することで可能となります。
以下がサンプルコードになります。

postgre.spl
select cast('2020/02/29' as date) - cast('1 year' as INTERVAL)
--2019-02-28T00:00:00Z

PostgreSQLの場合はうるう年の一年前の日付を取得した場合、2月28日となりました。

MySQLの場合

MySQLにて日付の計算を行う場合、DATE_ADD、DATE_SUB関数を使用し、第一引数に計算元となる日付、第二引数にINERVAL型で時間を指定することで、計算元日付からそれぞれ加算、減算することが可能となります。
以下がサンプルコードになります。
(減算のため、DATE_SUB関数を使用していますが、DATE_ADD関数で第二引数にINTERVAL -1 YEARを指定することで実質減算を行うこともできます。)

mysql.spl
select DATE_ADD('2020/02/29', INTERVAL -1 YEAR) FROM dual;
--2019-02-28

MySQLの場合はうるう年の一年前の日付を取得した場合、2月28日となりました。

SQLiteの場合

SQLiteにて日付の計算を行う場合、date関数を使用し第一引数に計算元となる日付、第二引数に時間を指定することで加算、減算することが可能となります。
以下がサンプルコードになります。

sqlite.spl
select date('2020-02-29', '-1 year');
--2019-03-01

SQLiteの場合はうるう年の一年前の日付を取得した場合、3月1日となりました。

まとめ

ここまで、いくつかの言語、DBでうるう年の一年前の日付の取得結果を確認してきましたが、まとめると以下のようになります。

Java → 2月28日を出力
Java Script → 3月1日を出力
PHP → 3月1日を出力
PostgreSQL → 2月28日を出力
MySQL → 2月28日を出力
SQLite → 3月1日を出力

言語、DBによってうるう年の一年前の日付の取得結果は異なるという面白い結果が得られました。
他の言語、DBではどうなるのか、あるいはどうしてこのような違いが生まれるのか、日付計算のロジックに違いがあるのかといったように話を広げても面白いかもしれません。
今回の記事は以上となります。

33
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?