コード
GASで当日日付で07:30未満かつ前日日付07:30以上のデータが含まれる行を抽出して、別シートへ貼り付けたい。 ![![イメージ説明](7da6756ae204efde321ae56f8e7daab9.png)](5a3b7f2a877e5110a7ac66eb4c714f73.png) ### 発生している問題・エラーメッセージ 2次元配列でシートのデータを取得しましたが、日付の行、時間の列で判定して条件を満たしていたらその行を取得する方法がわかりません。
エラーメッセージ
### 該当のソースコード GAS ソースコード function myFunction() { //**********rb=robot管理票**********// //**********fb=障害一覧*************// //----------robot管理票のシート情報(コピー元)----------// var url = "マスキング"; var robotBook = SpreadsheetApp.openByUrl(url); var robotMgtSheet = robotBook.getSheetByName("管理"); //**----------障害一覧の情報(ペースト先)----------**// var failureBook = SpreadsheetApp.getActiveSpreadsheet(); var fS_Nissi = failureBook.getSheetByName("日誌用"); //**----------シートのコピペ→名前変更----------**// var getRobotMgtSheet = robotBook.getSheets()[1]; getRobotMgtSheet.copyTo(failureBook); var fbSheet = failureBook.getSheetByName("管理 のコピー"); fbSheet.setName("障害管理"); //**----------余分な列、行の削除処理**********// fbSheet.deleteColumns (1,7); fbSheet.deleteColumns (6,8); fbSheet.deleteColumns (8,5); fbSheet.deleteRow (1); fbSheet.setFrozenColumns(0); // fbSheet.deleteRows(100,3000); //**----------ステータス列の移動処理----------**// var cl = fbSheet.getRange(1,1).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow(); var rng = fbSheet.getRange(cl,1); fbSheet.moveColumns(rng,4); //**----------発生日を降順でSORT----------**/ fbSheet.sort(1,false); //**----------日付の取得----------**// //現在日時のDateオブジェクトを作る var date = new Date(); //現在の「日」を取得し表示形式を整形する var day = date.getDate(); var today = Utilities.formatDate(date, 'JST', 'yyyy/MM/d'); //前日日付にしたいので-1する date.setDate(day-1); //日付の表示形式を整形する var yesterday = Utilities.formatDate(date, 'JST', 'yyyy/MM/d'); //**----------定義----------**// var okData_days = [] //発生日時の格納先 var aValues = fbSheet.getRange('A:A').getValues(); //"障害報告"の"発生日時"部分の値を全て取得 var lastRow = aValues.filter(String).length; //空白の要素を除いた長さを取得 //**----------発生日が"前日"かつ"7:30以降を取得し貼り付け----------**// for(var i=1,y=1; i<lastRow; i++,y++){ var fbHASSEI_Day = fbSheet.getRange(i,1,1).getDisplayValue(); var fbHASSEI_Time= fbSheet.getRange(i,2,1).getDisplayValue(); var fbTime = fbHASSEI_Time.split(':'); if(yesterday == fbHASSEI_Day){ if(fbTime[0] == "07"){ if(fbTime[1] >= "30"){ var okData = fbSheet.getRange(i,1,1,7).getDisplayValues(); fS_Nissi.getRange(y+5,2,1,7).setValues(okData);} }else if (fbTime[0] > "07"){ var okData = fbSheet.getRange(i,1,1,7).getDisplayValues(); fS_Nissi.getRange(y+5,2,1,7).setValues(okData); } } } ### 試したこと for文を利用して、当日の日付かつ発生時間が07:30未満のものを判定し別シートへ貼り付けるコードを書きましたが、何度やっても貼り付ける行がずれたりしてしまう。当日だけの処理がうまくいっても前日の日付の判定をしたあとそのデータをどうすればよいのかか悩んでいます。 追記(2021/10/18 20:44) 最初は、シートの日付を判定し対象の者を別のシートへ1行ずつ貼り付ける処理を作っていました。 ただ、日付の判定+時間の判定が一致したときのみ貼り付ける処理にしてみたら貼り付け先シートの行がずれたりします。 追記(2021/10/18/23:39) //**----------発生日が"前日"かつ"7:30以降を取得し貼り付け----------**//の処理の部分は 判定の結果は欲しいデータになっていますが、貼り付け先(添付画像参照)のシートにこの式だと3段飛ばしてから連続してデータが入力されてしまいます。 恐らく、一行ずつ読み込んでいってる際に変数の加算がおかしくなっているのかと思われますがわからないのです。。。 ![イメージ説明](adc3c852ef9e5a5c5624686b8091eed6.png) 追記(2021/10/20/22:12) 画像を追加いたします。 fbSheet日付部分のスクショ ![イメージ説明](f36ec3a4d89be28e06d91ccd2f459bdb.png) fbSheet時間部分のスクショ ![イメージ説明](5a516ce715c62ab7a20b69d5eef8253c.png) qnoir様修正案のコード **36行目から記載** //----------日付の取得----------// //現在日時のDateオブジェクトを作る var date = new Date(); //現在の「日」を取得し表示形式を整形する var day = date.getDate(); var today = Utilities.formatDate(date, 'JST', 'yyyy/MM/d'); //前日日付にしたいので-1する date.setDate(day - 1); //日付の表示形式を整形する var yesterday = Utilities.formatDate(date, 'JST', 'yyyy/MM/d'); // 追加 fbSheet.getRange('A:A').setNumberFormat('yyyy/MM/dd'); // A列の表示形式を日付形式にする。 fbSheet.getRange('B:B').setNumberFormat('HH:mm'); // B列の表示形式を時刻形式にする。 //----------定義----------// var okData_days = [] //発生日時の格納先 var aValues = fbSheet.getRange('A:A').getValues(); //"障害報告"の"発生日時"部分の値を全て取得 var lastRow = aValues.filter(String).length; //空白の要素を除いた長さを取得 // *******以下 修正案********** // 管理シートのデータを二次元配列で取得 var sourceData = fbSheet.getRange(1, 1, lastRow, 7).getValues(); // 「今日の7:30」を作成 var baseDateTime = new Date(); baseDateTime.setHours(7); baseDateTime.setMinutes(30); baseDateTime.setSeconds(0); baseDateTime.setMilliseconds(0); // 書き込み用の配列 var outputValues = []; // 配列から1行ずつ日時を取得して比較 for (var i = 0, y = 0; i < sourceData.length; i++) { var row = sourceData[i]; // 当日の7:30との差(秒)を計算 var duration = Math.floor(baseDateTime.getTime() / 1000) - **Math.floor(getDateTime(row[0], row[1]).getTime() / 1000);** //エラーコード80行目対象箇所 // 当日の7:30との差が、0秒より大きく24時間以下の場合は、書き込み用の配列に加える if (duration > 0 && duration <= 60 * 60 * 24) { outputValues.push(row); } } // 日誌用シートのB列6行目以降にデータを書き込む fS_Nissi.getRange(6, 2, outputValues.length, 7).setValues(outputValues) } /************************************************ * 日付と時刻のセルから、対応する日時データを返す。 * * 引数: * date : Date : 日付 * time : Date : 時刻 * * 返り値:Date * :指定されたdate と timeに対応するDateオブジェクト * ***********************************************/ function getDateTime(date, time) { **var hour = time.getHours();** //エラーコード104行目対象箇所 var minute = time.getMinutes(); date.setHours(hour); date.setMinutes(minute); return date; } エラーコード エラー TypeError: time.getHours is not a function getDateTime @ コード.gs:104 myFunction @ コード.gs:80
「for文を利用して、当日の日付かつ発生時間が07:30未満のものを判定し別シートへ貼り付けるコードを書きましたが、何度やっても貼り付ける行がずれたりしてしまう。」とのことですが、
差し支えなければ、その書いてみたコードも質問文に追記していただけないでしょうか。
(うまく動かないコードでもぜんぜん構いません)
さらに、「今はこうなってしまうけれど、本当はどういう動作にしたい」という点も、可能であれば画像をつけて説明していただけると、わかりやすいかなとは思います。
qnoir様
当質問をご覧いただきありがとうございます。
自分がやりたいことを再投稿いたしました。
追記・修正依頼あればください。
よろしくお願いいたします。
貼り付け先のCシートは、処理前の時点では4行目以降空白であり、条件(「当日の7:30未満、前日の7:30以降」)に合致する行をCシートの4行目以降に、隙間なく貼り付けていきたい、という理解でよろしいでしょうか?
(「貼り付ける行がずれたりしてしまう」というのは「隙間なく貼り付けたいのに、現状だと行が飛び飛びになってしまう」、という意味でしょうか)
貼り付け先のシートは、このようなひな型になっており6行目(No.1)から連続して判定を通ったデータが入力されるようにしたいです。
setValuesで貼り付ける座標が、日誌用シートのgetRange(5+y,2,1,7).setValue(okData );
で貼り付けれると認識しているのですがループの一週目がなぜか9行目から始まるのです。
日付判定に該当するデータ数を増やすと、10行目から始まったり11行目から始まったりします。(始まりだけが違うだけで、連続して入力はされます)
そもそも、ロジックがよくないのかどうなのか。。。
やりたいことは、3000行、7列のシートから前日07:30~当日07:30のデータだけを日誌用シートに貼り付けることです。
私が、考えたロジックは
対象シートをコピー→コピーしたシートを必要な行と列だけに加工して発生日を降順でソート→発生日で上から順番に前日日付かつ07:30以上のデータがあれば、日誌用シートへ貼り付け。(これをループ)
そのあと、当日かつ07:30未満のデータがあれば日誌用シートの続きへ貼り付け。(ループ)
そのあと、日付が昇順になるようにソート処理でもかけようかと考えています。
追加ですみません。
質問文中のプログラムでは時刻の大小をすべて2桁の文字列で比較していますが、質問欄記載の画像では、時間(hour)が1桁のものがあります。
実際のデータでは、時間(hour)は2桁表示(0時~9時は00~09という表示)になっている、という理解でよろしいでしょうか?
それとも、実際のデータでは、時間(hour)は1桁になっているものもあるのでしょうか?
また、A列・B列の表示形式は、書式なしテキストではなく、日付・時刻型である、という理解でよろしいでしょうか。
実際のデータは、時間の表示は09時なら9と表示されています。
A列・B列の表示形式は、A列は日付型、B列は時刻型です。
時刻判定なんですが、時間で判定するやり方がよくわからなかったので。
”:”で左辺、右辺に分割して、数字を文字列として判定しようと思ったのです。
時間で判定ってできるのでしょうか・・・
たとえば、シート上の時刻が1:00の場合、getDisplayValuesは、表示されている文字そのままをとってくるため、
現状のコードだと、"1"と"07"を比較することになります。
しかし、"1"<"07"はfalseとなるので、正しく比較できていません。
もし、現状のコードを生かして、文字列で正しく比較できるようにするのであれば、
障害管理シート(元データ)の時刻列を選択し、
メニューの表示形式→数字→表示形式の詳細設定→その他の日付や時刻の形式
を開き、
「カスタムの日付と時刻の形式」ダイアログで「時(01)」をクリックし、
「先行ゼロ付きの時(01)」を選択し、適用ボタンを押します。
https://teratail-v2.storage.googleapis.com/uploads/contributed_images/037a65576d139526e739a53fb044a07f.png
https://teratail-v2.storage.googleapis.com/uploads/contributed_images/664122facca7f155d08e70cb0403f9c1.png
https://teratail-v2.storage.googleapis.com/uploads/contributed_images/2e64c2cba7482a7c731159a014a5b757.png
これによって時刻が00:00形式になり、正しく比較できるようになります。
文字列で比較しない場合は、時間で判定する、つまり日付時刻型で比較することも可能です(時間の表示形式に関係なく比較できることもあり、可能であれば時間で判定するのがおすすめだと思います)。
ただしこの場合、現状のコードの一部を変える必要が出てきます。
元データは諸事情により、変更できないのです。(だから元シートを別のシートへ移して加工する必要があります)
ですので、時間で判定できるとおっしゃっていますが。
それは、日付も合わせて判定できるということでしょうか?
日付時刻型ということは、日付と時間が別れている(今のシートの状態)と判定できないということですか?
日付と時間がわかれていても、その日付と時間を統合して日時オブジェクトにすれば、判定は可能です。
回答の後半に記載の「getDateTime()」というオリジナルの関数が、「指定した日付と時間を統合して日時オブジェクトにする関数」となっています。
回答1件
あなたの回答
tips
プレビュー