- PR -

時刻計算について

投稿者投稿内容
みかん
会議室デビュー日: 2004/05/01
投稿数: 10
投稿日時: 2004-05-13 10:48
現在、JSPとMySQLを用いてタイムカードを作成しています。
IDとパスワードを入力する事で個人のタイムカード画面に入れるようになっています。
フォームの構成としてはログインと同時に現在の年月日がテキストに表示され、その下には出勤コマンドボタンがあり、ボタンを押すと右にあるテキストに現時刻が表示される仕組みです。同様に退勤ボタンとテキストをその下に設けてあります。その他には記入ボタンがあります。
来た時には出勤ボタン→記入、帰る時には退勤ボタン→記入の順で押してもらっています。
そして、その日の勤務時間(退勤時間−出勤時間)を出力し、月の平均労働時間を出力させています。プログラムは以下の通りです。

<%@ page contentType="text/html; charset=Shift_JIS"
import="java.sql.*,java.util.*,java.text.*" %>
<%@ include file="inc1.jsp" %>
<%@ include file="class1.jsp" %>
<%-- タイムカード表示 --%>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=x-sjis">
<title>タイムカード一覧表示</title>
</head>
<body>
<%
//ユーザ情報を取得する
String uid = request.getParameter("uid");
String name = cnvString(request.getParameter("name"));

//日付を取得する
Calendar cal = Calendar.getInstance();
int yyyy;
int mm;
int dd;
try {
yyyy = Integer.parseInt(request.getParameter("yyyy"));
mm = Integer.parseInt(request.getParameter("mm"));
dd = Integer.parseInt(request.getParameter("dd"));
}
catch (Exception e) {
yyyy = cal.get(Calendar.YEAR);
mm = cal.get(Calendar.MONTH) + 1;
dd = cal.get(Calendar.DATE);
}
String hiduke = yyyy + "-" + mm + "-" + dd;
int lastd = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
//データベースに接続する
Class.forName(jdbc);
Connection conn = DriverManager.getConnection(url);
Statement st;
String sql;
ResultSet rs;

try {
if (request.getParameter("kbn").equals("ent")) {
//記入ボタンが押された時、対象日付のデータを取得する
st = conn.createStatement();
sql = "SELECT * FROM kinmu WHERE uid = '"
+ uid + "' AND hiduke ='" + hiduke + "'";
rs = st.executeQuery(sql);

//データがない時は出社と見なす(データ追加)
if (!rs.next()) {
sql = "INSERT INTO kinmu ("
+ " uid, "
+ " name, "
+ " hiduke, "
+ " shussha, "
+ " taisha "
+ ") values ("
+ "'" + uid + "',"
+ "'" + name + "',"
+ "'" + hiduke + "',"
+ "'" + request.getParameter("shussha") + "',"
+ "'" + request.getParameter("shussha") + "'"
+ ")";
}
//データが存在するときは退社(データ更新)
else {
sql = "UPDATE kinmu SET "
+ " taisha = '" + request.getParameter("taisha") + "'"
+ " WHERE no = " + rs.getInt("no");
}
st = conn.createStatement();
st.executeUpdate(sql);
}
}
catch (Exception e) {
}

//対象年月の勤務データを取得する
st = conn.createStatement();
String ymd_1st = yyyy + "-" + mm + "-1";
String ym_last = yyyy + "-" + mm + "-" + lastd;
//勤務時間を計算する
sql = "SELECT no, uid, hiduke, shussha, taisha,"
+ "TIME_TO_SEC(taisha) - TIME_TO_SEC(shussha)"
+ "AS ktime FROM kinmu "
+ "WHERE uid = '" + uid
+ "' AND hiduke BETWEEN '"
+ ymd_1st + "' AND '" + ym_last + "'"
+ "ORDER BY hiduke desc";
rs = st.executeQuery(sql);
%>
     ・
     ・
     略
     ・
     ・
<%
//勤務合計時間を算出する
total += rs.getInt("ktime");
  //cnvSec2Hourは時間数への表記変換としてclass1.java内で定義しています
out.println(cnvSec2Hour(rs.getInt("ktime")));
%>

<%
//データ件数を取得する
Statement st1 = conn.createStatement();
String sql1 = "SELECT COUNT(*) FROM kinmu WHERE uid = '" + uid
+ "' AND hiduke BETWEEN '"
+ ymd_1st + "' AND '" + ym_last + "'"; //実行するSQL
//実行する
ResultSet rs1 = st.executeQuery(sql1);
rs1.next();
int count = rs1.getInt(1);
%>
<%
int heikin = total / count;
%>

<td align="right" colspan="4">当月合計</td>
<td align="right"><%=cnvSec2Hour(total)%></td></tr>
<tr><td align="right" colspan="4">当月平均</td>
<td align="right"><%=cnvSec2Hour(heikin)%></td>
      ・
      ・
</body>
</html>

そこで、問題になっているのが出社も退社も同じ日にちであれば良いのですが、万が一退社の時間が日をまたいでしまった場合の計算です。(例)1:00−9:00=−8:00
と計算されてしまいます・・・何か良い方法はないでしょうか??
退社の初期値として23:99を入力しておき出社の初期値として00:00を入力しておくことで日をまたぐ場合でも計算は可能であると考えましたが「データがない時は出社と見なす」「データが存在するときは退社と見なす」としているため現在のプログラムでは深夜1:00に退社し同日10:00に出社するという事が不可能となります。「出社ボタンが押された時」「退社ボタンが押された時」とするのも良いかと思ったのですが5/1300:00〜5:00、5/1310:00〜19:00となった場合のデータ件数(出勤日数)を取得する方法が分かりません。
どなたかご教授の程よろしくお願いします。
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2004-05-13 11:25
「退勤時刻を入力したとき、当日の出勤時刻データが無い場合、前日の退勤時刻と見なす。」

ってのはいかがでしょうか。
ただ、この場合、出勤時刻、退勤時刻を、それぞれ年月日も含めて
DBに格納しておいた方がいいかと思います。
DBのデータだけで判別できますし、会社に滞在している時間が
24時間を超えても対処できますし・・・(- -;

もし、今からテーブル設計を変更できないとしたら、プログラムで対処するしかないでしょう。
タラン
大ベテラン
会議室デビュー日: 2004/03/17
投稿数: 138
投稿日時: 2004-05-13 14:01
日が変わっている場合のみチェックしてください。

退社時間が12以下の場合には退社時間に12を足して計算するようにしたらどうでしょう。

確認はしてないですが多分そうすればできる気がします。だめかな。。T.T

結果教えてくださいね。


この場合は SELECT文を少し変えなきゃ!

[ メッセージ編集済み 編集者: ヒデミ 編集日時 2004-05-13 14:03 ]
すなめり
常連さん
会議室デビュー日: 2003/01/29
投稿数: 37
お住まい・勤務地: 横浜
投稿日時: 2004-05-13 14:47
//記入ボタンが押された時、対象日付のデータを取得する
のところを、
//記入ボタンが押された時、最新のレコードに退社時刻が入力されているかを調べる
というようにしてはどうでしょう。
退社時刻が入っていれば出社、入っていなければ退社とみなすのです。

Edossonさんのご指摘のように、年月日も含めて格納すると、時刻の計算も
問題なくなると思います。
24時間以上連続の勤務がないなら、勤務時間が負の値になったら24を足す、
でもよいのですけどね。

勤務日数の計算ですが、レコードに年月日が入っているのなら、distinctを
使って重複を削除してからカウントすると、お望みの結果が得られるのでは
ないかと思います。

それより、気になったのは、ユーザがうっかり出社なり退社なりを記録し損ねた
場合はどうするのかな、ということです。
退社と出社はブラウザ側ではどちらを入力しているのか判っている筈ですから、
JavaScriptでも使ってhiddenタグで出社と退社のどちらを記録しようと
しているかをJSPに返し、それが先のロジックに合わない場合はエラーを返すと
よいのかな、と思います。
例:ユーザが出社を記録するつもりなのに、最新のレコードに退社時刻が入力
 されていなかった場合は、退社時刻の記録忘れとみなしてエラーとする。
タラン
大ベテラン
会議室デビュー日: 2004/03/17
投稿数: 138
投稿日時: 2004-05-13 14:53
退社時間は出社時間を入力する時に入力されてますよね。
なので退社時間を忘れた場合勤務時間が0になります。

dbテーブルの修正ができない前提で書いてみます。


画面のところ
<input type="hidden" name="FLAG" value="">

<出社button> [ 日付 ] FALG = "0"
<退社button> [ 日付 ] FALG = "1"


処理

@FALGチェック
AFALG == 0なのに 同じ日付がある場合はエラー処理するか
B同じ日付がない:INSERT (日付がない場合SCRIPTEで防ぐかシステム日付をDEFALUTで入れるか)
(退社日付はどうしようかな)
 出社日付は入力して退社日付は入力してない可能性がありますね。
 こういう場合対象から除外したりしてもいいと思いますよ。例:WHERE 出社日付 != 退社日付 のみ取得する。
CFALG == 1の場合退社時間をUPDATEする。
(正確には出社日付をSELECTして出社日付より前の日付はエラー処理する。)

D対象年月の勤務データ取得する
 − SELECT 出社日付/退社日付(別々に取得する、退社ー出社ではなく)
 − FOR(件数)
    IF(日が変わった場合)
     (退社時間 + 24 )ー出社時間

取得したUIDと時間をとこかに保存しておく必要がありますが...

FLAGが必要ではなければ
ないままでDだけ参考にすればいいと思います。
こういう感じではどうですか。



[ メッセージ編集済み 編集者: ヒデミ 編集日時 2004-05-14 09:22 ]
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2004-05-13 15:13
行儀の悪い投稿だったので、削除します。m(_ _)m

[ メッセージ編集済み 編集者: Edosson 編集日時 2004-05-13 15:26 ]
みかん
会議室デビュー日: 2004/05/01
投稿数: 10
投稿日時: 2004-05-14 11:26
Edossonさん、ヒデミさん、すなめりさんお返事ありがとうございました。
早速参考にさせて頂きます。
みかん
会議室デビュー日: 2004/05/01
投稿数: 10
投稿日時: 2004-05-17 16:06
度々すみません。お世話になります。
以前、みなさんからして頂いたアドバイスを基に、作成していたのですが問題点が出てきたのでお力を貸して頂きたいと思い、書き込みをしました。

出社や退社の際にタイムカードを押し忘れた時などの対処法としては、他のページで変更出来るようにするという事で解決しました。

今問題になっているのは、「最新のレコードに退社時刻が入力されているかを調べる」という部分です。
以前は

try {
if (request.getParameter("kbn").equals("ent")) {
//記入ボタンが押された時、対象日付のデータを取得する
st = conn.createStatement();
sql = "SELECT * FROM kinmu WHERE uid = '"
+ uid + "' AND hiduke ='" + hiduke + "'";
rs = st.executeQuery(sql);
       ・
       ・
       ・


としていた部分を以下のように変更しました。
また、kinmuテーブルに退社日付としてthidukeを追加しました。
テーブルの構成としてはno,name,uid,hiduke,thiduke,shussha,taishaとなっています。
また、それぞれの型としてはint,varchar,varchar,date,date,time,timeです。

//最新データを取得する
st1 = conn.createStatement();
sql1 = "SELECT max(no) from kinmu WHERE uid = '"
+ uid + "'";
rs1 = st1.executeQuery(sql1);
try {
if (request.getParameter("kbn").equals("ent")) {
//最新日付のデータを取得する
st = conn.createStatement();
sql = "SELECT * FROM kinmu WHERE no = " + rs1.getInt("no");
rs = st.executeQuery(sql);
Time shussha = rs.getTime("shussha");
Time taisha = rs.getTime("taisha");
//出社と退社時間が同じ場合は退社とみなす(データ更新)
if (shussha==taisha) {
sql = "UPDATE kinmu SET "
+ " taisha = '" + request.getParameter("taisha") + "'"
+ " thiduke = '" + hiduke +"'"
+ " WHERE no = " + rs.getInt("no");
}
//それ以外は出社とみなす(データ追加)
else {
sql = "INSERT INTO kinmu ("
+ " uid, "
+ " name, "
+ " hiduke, "
+ " shussha, "
+ " taisha "
+ ") values ("
+ "'" + uid + "',"
+ "'" + name + "',"
+ "'" + hiduke + "',"
+ "'" + request.getParameter("shussha") + "',"
+ "'" + request.getParameter("shussha") + "'"
+ ")";
}
st = conn.createStatement();
st.executeUpdate(sql);
}

この部分で行き詰まってしまったためこれ以降のプラグラムはいじっていません。
エラーは出ないのですが、追加も変更もされなくなってしまいました。
どこが違っているのかわかりません・・・
どなたかご教授の程宜しくお願いします。

スキルアップ/キャリアアップ(JOB@IT)