• 締切済み

出勤時刻と退勤時刻のみを管理するシステム

PHPとJavaScriptで出勤時刻と退勤時刻のみを管理するシステムを作成する場合、SQLの知識は不要ですか? 大まかな作成手順を教えていただけると幸いです。出勤、退勤時刻以外の労働時間数や残業時間等は管理対象外とします。 機能と画面構成は以下の通りです。 【機能】 (1) 出勤時刻の打刻 (2) 退勤時刻の打刻 (3) 出勤時刻の修正 (4) 退勤時刻の修正 (5) 期間指定による出勤表の表示 【画面構成】 (1) 出勤打刻 ・ページタイトル ・JavaScriptで現在の時刻をリアルタイムに表示 ・打刻ボタン (2) 退勤打刻 ・ページタイトル ・JavaScriptで現在の時刻をリアルタイムに表示 ・打刻ボタン (3) 出勤表 ・ページタイトル ・期間指定フォーム ・日別で出勤打刻と退勤打刻を一覧表示 (4) 出勤打刻の修正 ・ページタイトル ・時刻修正フォーム (5) 退勤打刻の修正 ・ページタイトル ・時刻修正フォーム

みんなの回答

回答No.6

> 回答ありがとうございます。全体像はなんとなく理解できました。期間指定による出勤表の表示(期間指定フォーム、日別で一覧表示)の部分はどのように考えればいいでしょうか? 回答遅くなってしまいましたが、本件は一旦AsarKingChangさんの回答に記載されていたテーブルを前提に考えます。 ただ、AsarKingChangさんがおっしゃる通り、日をまたいだ勤怠が発生したときにどうするのか(炎上プロジェクトとか夜勤とか)、を考えると、datetime型で設定するのが私もよいと思います。 なので、 =========================== CREATE TABLE `timecard` ( `user_name` varchar(255) NOT NULL UNIQUE, `begin` datetime DEFAULT NULL, `finish` datetime DEFAULT NULL, `date` datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; =========================== とするのがよさそうですね。(その他ユーザ情報をリレーションするとかそういうのは先の回答を参考にしていただきつつ。) で、ご質問の回答ですが、最初に私が回答した、「選択(取得)」の項目で良いかなと思います。 質問者さんが作成したテーブルに充てるなら SELECT * FROM timecard WHERE begin BETWEEN ? AND ?; として、PHP的には、 <?php $pdo = new PDO('mysqlのDSN'); $stmt = $pdo->prepare('SELECT * FROM timecard WHERE begin BETWEEN ? AND ?'; $stmt->execute(array('2021-10-01 00:00:00', '2021-10-31 23:59:59')); foreach ($stmt as $row) { // 取得したレコードをなんか処理する } ?> みたいな感じが最小要件ですかね。 打刻システム上、打刻の時刻を24時以降も入力可能とするなら、少し工夫が必要ですかね(26時退勤、つまり深夜2時に退勤する、みたいな) <?php /* ==打刻値がPOSTされてきた想定================================== */ // 入力値 $taikin = '25:31'; list ($hour, $min) = explode(':', $taikin); $date = new DateTime(); $date->setTimezone(new DateTimeZone('Asia/Tokyo')); $date->setTime(0, 0, 0); $date->modify("+ {$hour} hours + {$min} minutes"); echo $date->format('Y-m-d H:i:s') . PHP_EOL; /* ==DBから値を取得する場合================================== */ $row = [ 'begin' => '2021-10-01 09:00', 'finish' => '2021-10-02 03:28', ]; $begin = new DateTimeImmutable($row['begin']); $finish = new DateTimeImmutable($row['finish']); $stampTime = $finish->diff($begin); // 勤務時間 echo $stampTime->format('%H:%i') . PHP_EOL; /* ==表示を24時間以上表記にすることを要求されたなら================== */ $beginDay = $begin->setTime(0, 0, 0); $finishDay = $finish->setTime(0, 0, 0); $dayDiff = $finishDay->diff($beginDay); $stampBegin = $begin->format('H:i'); $days = (int) $dayDiff->format('%d'); if ($days > 0) { // 日付の差が1日以上あったら時刻に日数×24する $hour = (int) $finish->format('H') + ($days * 24); $min = (int) $finish->format('i'); $stampFinish = sprintf("%02d:%02d", $hour, $min); } else { $stampFinish = $finish->format('H:i'); } // 画面表示用の出勤時刻と退勤時刻 echo "出勤:{$stampBegin}" . PHP_EOL; echo "退勤:{$stampFinish}" . PHP_EOL; ?> ちょっと処理が思いつかなくて思いのほかダサくなりましたが、とりあえずおいておきますね。(効率いい方法はネットで調べてください)

OBAKEI
質問者

補足

補足ありがとうございます。時刻修正のフォームを作るときはセレクトフォームではなく、<input type="text" name="hour">のようにして、バリデーション処理を追加する方針で合っていますか?(時間:06~24時の間、分と秒:00~59の間 半角数字のみ)

回答No.5

>回答ありがとうございます。timecardという名前のテーブルを作成し、ユーザー名(またはユーザーID)、出勤時間、退勤時間、日付を以下のようにCREATE TABLEで定義すればいいですか? 特に問題はないと思いますよ。 ただ、もしも「日をまたいでしまったら?」 残業が午前1時に終わった? だと、timeだと、無理が出るので、 結局は全部datetimeでいいかと。 あと、ユーザーIDを文字にするのではなく、 別にユーザーだけのテーブルを作っておいて user_data { id: int なり bigint; 主+unique `user_name` varchar(255) NOT NULL UNIQUE, } ←こっち側にuser_nameを入れておく timecard { user_id -> リレーション:user_data : id, index. }←このように格納すれば、存在しないユーザーが 打刻できない。また、user_idがunique + indexになるので、 検索も早くなります。 おまけですが、初打刻時は、 begin = default CURRENT_TIMESTAMP にしちゃえば、データ追加しただけで、自動的に時間入りますね。 (だって追加時は新規でしょうから) となれば、もはや、dateカラムは要らない。。 今回は、ondup の恩恵は得られにくいですが。 後、きっちり作ろうとせず、 やってみてダメなら、直す!って軽いスタンスでも いいと思いますよ~。(趣味なら) PHPMYADMINなどで、動きを見ながら作っていく~ ってスタイルでも、勉強なら全然ありなので、 気楽に~!が私なりの回答ですかね。 1点だけ追加 ある範囲が「当日とみなすか?」で既にあるか? →あるなら、退室打刻 →ないなら、新規打刻をやればOKかと思います。

OBAKEI
質問者

補足

補足ありがとうございます。時刻修正のフォームを作るときはセレクトフォームではなく、<input type="text" name="hour">のようにして、バリデーション処理を追加する方針で合っていますか?(時間:06~24時の間、分と秒:00~59の間 半角数字のみ)また、DBに保存するときは、時間、分、秒をそれぞれ分けたほうがいいですか?

回答No.4

<?php /*================== data.txtが、以下のようなフォーマットだったら employeeId,date,timestamp taro,2021-01-10,09:01, giro,2021-01-10,08:59, siro,2021-01-10,09:00, ===================*/ // なんかフォームとか、GETパラメータとかで日付が指定されていたなら $date = new DateTime($_POST['target_date']); $fp = fopen('data.txt', 'r'); $collection = []; while($line = fgets($fp, 4096)) { $data = explode(',', $line); // カンマで切り分けて $targetDate = new DateTime($data[1]); // カンマ区切り配列の2番目 if ($date->format('Y-m-d') === $targetDate('Y-m-d')) { // 同じ日付だったら収集 $collection[] = $data; } } // みたいな。日付範囲指定とかだったら、getTimestamp()とかやるとUnixタイムスタンプ取れるのでそれ差を比較するとか。 // Carbonという便利な日付ライブラリがあるのでそういうの使ってもよし。 ?> というように、ある程度泥臭い処理をしていく必要があるわけです。 SQLiteやMySQLなんかだったら、 SELECT * FROM ScheduleTbl WHERE dateCol BETWEEN ? AND ?; みたいなSQL書いてやって、「?」のところに日付の範囲を入れてやれば取得できるので簡単ですね。 今回やりたい要件だけを満たすなら、データの関連付け(リレーション)することもないので、 結構単純なSQLだけで済むので復習して洗いなおしてみるのが良いと思います。 // 削除(WHERE句以降が条件文) DELETE FROM YourTableName WHERE EmployeeId = ? AND dateCol = ?; // 更新(WHERE句以降が条件文) UPDATE YourTableName SET timestampCol = ? WHERE EmployeeId = ? AND dateCol = ?; // 登録 INSERT INTO YourTableName (EmployeeId, dateCol, timestampCol) VALUES (?, ?, ?); // 選択(取得) SELECT EmployeeId, dateCol, timestampCol FROM YourTableName WHERE dateCol BETWEEN ? AND ?; こんな感じです。

OBAKEI
質問者

補足

回答ありがとうございます。全体像はなんとなく理解できました。期間指定による出勤表の表示(期間指定フォーム、日別で一覧表示)の部分はどのように考えればいいでしょうか?

回答No.3

本件、システムを使うのは誰でしょう。自分自身のみですか。 また、期間はどの程度利用されるのでしょう。 それ次第で、SQL(RDB)の知識の有無が変わってくる気はします。 基本的にテキストファイルをシークしてデータを探して、変更するのは、思いのほか面倒になると思います。 要件に「修正」、とあります。 ファイルのなかから該当行探し当てるのは簡単ですが、該当行のデータだけ修正をする、というのが難しく、一回全行読み取ってから全行書き換えることになります。 また、一覧表示も条件を付けて表示させることになると、自分でIF文で分岐させる必要が出てきますが、何らかの検索条件変更等が入った場合に、修正に時間がかかることになりそうです。 SQLであれば、UPDATE文流せば必要な個所だけ一発で修正ができますし、SELECT文の条件を書き換えれば簡単に一覧取得ができます。 何らかの理由でMySQLや、SQLServerなどといったDBが用意できない、ということであれば、PHPにビルトインされているファイルベースのDBのSQLiteがあります。 これを用いることで簡易的なDBを使うことが可能です。 検討してみてください。

OBAKEI
質問者

補足

回答ありがとうございます。SQLについて復習しておきます。(5)の期間指定による出勤表の表示(期間指定フォームと日別に一覧表示)はどのように考えればよいでしょうか?

回答No.2

もう一点 サーバー時間も、サーバー側のロケーションが正しくないと 正しい値を指しません。 次に、SQLの時刻もロケーション依存です。 "select now();" も、SQL次第の結果なのでね。

OBAKEI
質問者

補足

回答ありがとうございます。timecardという名前のテーブルを作成し、ユーザー名(またはユーザーID)、出勤時間、退勤時間、日付を以下のようにCREATE TABLEで定義すればいいですか? CREATE TABLE `timecard` ( `user_name` varchar(255) NOT NULL UNIQUE, `begin` time DEFAULT NULL, `finish` time DEFAULT NULL, `date` datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

回答No.1

>・JavaScriptで現在の時刻をリアルタイムに表示 これやっちゃだめ! JavaScriptが表示するのはPC時間でサーバー時間じゃないです。 だから、パソコンの時計を変えれば、その時間で 打刻されてしまいます。 あくまでサーバー時間で打刻しましょう。 後は、おおよそ、その通りでOKです。

関連するQ&A