質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

2352閲覧

〇ヶ月後、〇年後の応当日。

Take_it

総合スコア357

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

1グッド

0クリップ

投稿2019/07/12 01:29

####やりたいこと
年次有給休暇の発効処理。
入社年月日の6か月後(半年後)の応当日、以後そこからさらに1年後(入社から1年半後)、2年後(入社から2年半後)・・・というように日付を取得したい。

####試したこと
本番環境ではデータベースに登録してある入社年月日から順に取得し、システムにアクセスした日を超えたらループを終了することを想定しています。
日付を正しく取得できるかを確かめるための以下のテストでは、2019-01-01から2019-12-31までの1年間の日付に対して、半年後~10年半後までを生成してみました。

PHP

1<?php 2ini_set( 'display_errors', 1 ); 3 $base_dates = array(); 4 $st = new DateTimeImmutable('2019-01-01'); 5 $date = new DateTime('2019-01-01'); 6 $ed = new DateTimeImmutable('2019-12-31'); 7 $stop = 0; 8 $array = array(); 9 echo "<pre>"; 10 print_r($date); 11 echo "</pre>"; 12// exit; 13 while($stop<1)://一致するまで繰り返す 14 $day = $date->format('Y-m-d'); 15 $hantoshi = new DateTime($day); 16 $hantoshi = $hantoshi->modify('+6 months')->format('Y-m-d'); 17 $y1 = new DateTime($day); 18 $y1 = $y1->modify('+6 months +1 year')->format('Y-m-d'); 19 $y2 = new DateTime($day); 20 $y2 = $y2->modify('+6 months +2 year')->format('Y-m-d'); 21 $y3 = new DateTime($day); 22 $y3 = $y3->modify('+6 months +3 year')->format('Y-m-d'); 23 $y4 = new DateTime($day); 24 $y4 = $y4->modify('+6 months +4 year')->format('Y-m-d'); 25 $y5 = new DateTime($day); 26 $y5 = $y5->modify('+6 months +5 year')->format('Y-m-d'); 27 $y6 = new DateTime($day); 28 $y6 = $y6->modify('+6 months +6 year')->format('Y-m-d'); 29 $y7 = new DateTime($day); 30 $y7 = $y7->modify('+6 months +7 year')->format('Y-m-d'); 31 $y8 = new DateTime($day); 32 $y8 = $y8->modify('+6 months +8 year')->format('Y-m-d'); 33 $y9 = new DateTime($day); 34 $y9 = $y9->modify('+6 months +9 year')->format('Y-m-d'); 35 $y10 = new DateTime($day); 36 $y10 = $y10->modify('+6 months +10 year')->format('Y-m-d'); 37 $array[$day]['半年後'] = $hantoshi; 38 $array[$day]['1年半後'] = $y1; 39 $array[$day]['2年半後'] = $y2; 40 $array[$day]['3年半後'] = $y3; 41 $array[$day]['4年半後'] = $y4; 42 $array[$day]['5年半後'] = $y5; 43 $array[$day]['6年半後'] = $y6; 44 $array[$day]['7年半後'] = $y7; 45 $array[$day]['8年半後'] = $y8; 46 $array[$day]['9年半後'] = $y9; 47 $array[$day]['10年半後'] = $y10; 48 49 $date = $date->modify('+1 day'); 50 if($date>$ed): 51 ++$stop; 52 endif; 53 endwhile; 54 55 echo "<pre>"; 56 print_r($array); 57 echo "</pre>"; 58 exit; 59?>

これだと結果として月末が31日まである月とそうではない月とで、月末応当日が期待した結果になりません。
例:5/31の半年後は11/30としたいが、12/1になってしまう。

そこで、次のやり方を試みました。

PHP

1<?php 2ini_set( 'display_errors', 1 ); 3 $base_dates = array(); 4 $st = new DateTimeImmutable('2010-01-01'); 5 $date = new DateTime('2010-01-01'); 6 $ed = new DateTimeImmutable('2010-12-31'); 7 $now = new DateTimeImmutable(); 8 $today = $now->format('Y-m-d');//対象日 9 $stop = 0; 10 $array = array(); 11 12 while($stop<1)://一致するまで繰り返す 13 $day = $date->format('Y-m-d'); 14 $d = $date->format('d');//日付のみ抽出 15 $h = new DateTime($day); 16 $h = $h->modify('+6 months'); 17 $h_d = $h->format('d'); 18 if($h_d!=$d)://異なる日が返った 19 $h = $h->modify('last day of last month');//前月の月末日 20 endif; 21 $array[$day]['半年後'] = $h->format('Y-m-d');//半年後の日付。$hは半年後のDateTimeオブジェクト 22 //対象日と一致するか過去の日付群 23 $stop2 = 0; 24 $cnt = 1; 25 while($stop2<1): 26 $h->modify('+1 year');//1年後ろへ 27 if($h>=$now)://超えた 28 ++$stop2; 29 else://超えてない 30 $array[$day][$cnt] = $h->format('Y-m-d'); 31 ++$cnt; 32 endif; 33 endwhile; 34 $date = $date->modify('+1 day'); 35 if($date>$ed): 36 ++$stop; 37 endif; 38 endwhile; 39 40 echo "<pre>"; 41 print_r($array); 42 echo "</pre>"; 43 exit; 44?>

(こちらでは先ほどと違い、2010-01-01~2010-12-31の各日付に対しての、半年後~〇年半後を生成していき、今日の日付に到達したら処理を止めるようにしてあります)

この方法だと、5/31の半年後応当日は意図した通り11/30になっており、概ね良好なのですが、
8/29~8/31が入社日となった場合、平年はこれらは全て各年の2/28が応当日として正解ですが、閏年の場合は2/29を応当日としなければいけません。

入社年月日の月と日を取り出し、月が8でかつ日が29以上で、なおかつ生成した応当日の年が閏年の場合は・・・・と力業で解決する以外に、なにかもっとスマートに応当日を求める方法はないものでしょうか。

m.ts10806👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/07/12 01:39

発効、応当日 などちょっと誤変換?誤字?っぽいのがあるので調整してもらえたらと(要件を伝えるためになるべくノイズはなくしてもらいたいので)
m.ts10806

2019/07/12 01:40

あ、いや、「発効」は大丈夫なのか・・失礼
m.ts10806

2019/07/12 01:41

あ、「応当日」も大丈夫ですね、これまた失礼
Take_it

2019/07/12 01:41

応当日 は 応当日 で合ってると思いますが。 https://ja.wiktionary.org/wiki/%E5%BF%9C%E5%BD%93%E6%97%A5 発効日 は、 発行日 の誤用ではないかというご指摘でしょうか。 別に紙切れを「発行」するわけではなく、「有給休暇取得の権利」が「効力を発する」ので、「発効日」と表現しています。
m.ts10806

2019/07/12 01:56

回答依頼いただいていますし失礼もしてしまったので しっかり考えたうえで回答させていただきました。 ご参考まで。
guest

回答2

0

ベストアンサー

date()のフォーマット"t"で「指定の月の日数」が取得できます。

php

1<?php 2echo date("t",strtotime("20180201")).PHP_EOL; 3echo date("t",strtotime("20190201")).PHP_EOL; 4echo date("t",strtotime("20200201")).PHP_EOL; 5echo date("t",strtotime("20210201")).PHP_EOL; 6echo date("t",strtotime("20220201")).PHP_EOL; 7echo date("t",strtotime("20230201")).PHP_EOL; 8/** 928 1028 1129 1228 1328 1428 15**

問題になるのは2月だけなので、"t"を利用すれば閏年判定を入れなくても
「8月且つ29日以降の入社日であれば2月の最終日("t")とする」が対応できそうに思います。

投稿2019/07/12 01:54

編集2019/07/12 01:56
m.ts10806

総合スコア80850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Take_it

2019/07/12 02:17

なるほど!確かに閏年判定は関係なくできました。 $d = $date->format('d');//日付のみ抽出 のところで、 $m = $date->format('m');//月のみ抽出 も加えておき、 $array[$day][$cnt] = $h->format('Y-m-d'); を、 if($m=='8' AND $d>=29): $array[$day][$cnt] = $h->format('Y-m-t'); else: $array[$day][$cnt] = $h->format('Y-m-d'); endif; とすることで、 [2010-08-28] => Array ( [半年後] => 2011-02-28 [1] => 2012-02-28 [2] => 2013-02-28 [3] => 2014-02-28 [4] => 2015-02-28 [5] => 2016-02-28 [6] => 2017-02-28 [7] => 2018-02-28 [8] => 2019-02-28 ) [2010-08-29] => Array ( [半年後] => 2011-02-28 [1] => 2012-02-29 [2] => 2013-02-28 [3] => 2014-02-28 [4] => 2015-02-28 [5] => 2016-02-29 [6] => 2017-02-28 [7] => 2018-02-28 [8] => 2019-02-28 ) [2010-08-30] => Array ( [半年後] => 2011-02-28 [1] => 2012-02-29 [2] => 2013-02-28 [3] => 2014-02-28 [4] => 2015-02-28 [5] => 2016-02-29 [6] => 2017-02-28 [7] => 2018-02-28 [8] => 2019-02-28 ) [2010-08-31] => Array ( [半年後] => 2011-02-28 [1] => 2012-02-29 [2] => 2013-02-28 [3] => 2014-02-28 [4] => 2015-02-28 [5] => 2016-02-29 [6] => 2017-02-28 [7] => 2018-02-28 [8] => 2019-02-28 ) と、意図した結果を導くことができました。 日付関係で、「〇ヶ月後、〇年後の応当日」って結構使うので、DateTimeクラスでもっとサクっと実現できたらいいのになぁ。。 ありがとうございました!
m.ts10806

2019/07/12 02:20

ヒントになったようで何よりです。 「29日以降」「半年後」というのも若干イレギュラーでもありますので、 そこは固定で判定するしかないかなとも思いました。
guest

0

当該日が月末(翌日の日付が1日)だったとき、翌日に対して○ヶ月後を実行し1日引く

投稿2019/07/12 02:00

yambejp

総合スコア114810

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問