2023年4月10日月曜日

年月に対する締め日範囲の算出

会計処理や月次レポートを行うシステムにおいて、対象年月(YYYYMM形式)と締め日(1~28,99:月末)から、対象年月に対する日付範囲を算出したい状況というのが稀に存在する。

今回はその局面で使えそうなコードを Java で書いてみようと思う。

public static void outputCutoffDateRange(int yyyymm, int cutoffDay) {
    int year = yyyymm / 100;
    int month = yyyymm % 100;

    YearMonth targetYearMonth = YearMonth.of(year, month);

    LocalDate startDate;
    LocalDate endDate;

    if (cutoffDay == 99) {
        endDate = targetYearMonth.atEndOfMonth();
        startDate = targetYearMonth.minusMonths(1).atEndOfMonth().plusDays(1);
    } else {
        startDate = targetYearMonth.atDay(cutoffDay).minusMonths(1).plusDays(1);
        endDate = targetYearMonth.atDay(cutoffDay);
    }

    LocalDate currentDate = startDate;
    while (!currentDate.isAfter(endDate)) {
        System.out.println(currentDate.getYear() * 10000 + currentDate.getMonthValue() * 100 + currentDate.getDayOfMonth());
        currentDate = currentDate.plusDays(1);
    }
}
単純に年月と締め日を使って開始日と終了日を算出し、開始から終了までの範囲を走査するだけである。
試しに実行してみる。それっぽい日付は出てるか?
public static void main(String[] args) {
    outputCutoffDateRange(202304, 15);
    System.out.println("---");
    outputCutoffDateRange(202303, 15);
    System.out.println("---");
    outputCutoffDateRange(202302, 99);
    System.out.println("---");
    outputCutoffDateRange(202302, 15);
}
これを基準に出力をDate型に変えたり、クラス化して Iterable で実装するなど使い方はいろいろあるかもしれない。

2023年4月9日日曜日

年月範囲の算出

会計処理や様々な期限のレポートを扱うシステムにおいて、開始年月から終了年月までの範囲を年月で扱いたい状況というのが稀に存在する。
  
今回はそれに対するコードを Java で書いてみようと思う。
public static void outputYearMonthRange(int startYearMonth, int endYearMonth) {
    int currentYearMonth = startYearMonth;
    while (currentYearMonth <= endYearMonth) {
        System.out.println(currentYearMonth);
        if (currentYearMonth % 100 == 12) {
            currentYearMonth += 89; // 12 -> 01
        } else {
            currentYearMonth += 1;
        }
    }
}
開始年月と終了年月をYYYYMM形式の数値として渡してもらい、開始から終了の範囲を走査するだけである。

試しに実行してみる。いい感じに出ている。
public static void main(String[] args) {
    outputYearMonthRange(202304, 202403);
}
出力を月初の Date型に変えたり、クラス化して Iterable で実装するなど組み込み方は色々あると思う。

2023年4月8日土曜日

高齢運転者による交通事故

ここ数年毎日のように高齢運転者による交通事故のニュースを目にして、その度に嫌な気分になる。実際、高齢者が起こした国内の事故統計情報を見る限り1日1件以上起こっている計算なのだから、目にするのは当然と言えるのだろう。

誰しもミスはあるし、事故が起こっても元の状態に戻せるならそこまで大きな問題でもないが、現実は残酷で、将来があったはずの若者が被害に合い、その後の生活に一生障害をかかえたり、場合によっては死亡する事故を見る限り、あまりにも非対称性が強い状況が多く、加害者である老人がそれに見合う代償を払えるかどうか怪しいことの方が多く感じる。


そのような状況に対して、私は一つエンジニアとして現実的な提言をしたい。

今後国内向けに新車として販売する一般の市販車に対して、運転免許証を車に刺さないと車のエンジンなりモーターが始動しないようにすべきだ。警察、消防、自衛隊などの特殊車両や、既に販売されている車、海外から輸入した車などは除外して良いと思う。自動車産業全体に時限措置を設け、5年程度の時間をかけて新規に販売される大多数の大衆車が運転免許証を刺さなければ動かない状態が作れることをひとまずのゴールと考える。

なぜ、運転免許証を使うのか?という観点に対して、一番の理由として現状の免許返納が意味のある行為になっていないからである。

歯に衣着せぬ物言いをさせてもらうが、既にボケ老人だった場合、免許を返納したとしても動く状態の車が残っており、家に車の鍵があれば、自身が免許を持っていない事も忘れて車を暴走させてしまうのは過去日本中で幾度となく事故が繰り返されている以上、覆りようのない事実である。

であるならば、物理的に運転免許証が無ければ動かせない状況を作ってしまう方が良く、それで事故被害者が減らせるなら安いものである。勝手に家族の免許証を老人に奪われた。などの屁理屈を言う輩は出るだろうが、管理できていない状況などは知ったことではない、奪われるようであれば、認知や行動に問題があるのだから、病院なり警察なりに連れて行き、被害が出る前に隔離されるべきである。本人にとっても家族にとっても責任が取れないことを起こす前にそうすべきだし、社会秩序や人々の安全を優先すべきではないだろうか?

また、一般人が使う車に免許証を刺さなければ動かせない制限が課されたとしても、そもそもに運転者は免許携帯が義務なのだから何の問題も無いはずである。多少不便になることは確かであるが、それで多くの人命が救われるのであれば全体が負担すべきコストとしては十分に釣り合うと感じる。毎回乗る際の手間の部分に関しては、確かに手間だとは思う。しかし、根本的な部分も含めて、より良いアイデアなりがあれば随時改善していけば良い話である。

技術的な実現性に関しては、現状エンジンの始動が電子制御になっていない車など皆無であり、その状況で制御を加えるのが難しいわけがない。そんなに簡単にできないというのなら技術者の頭を疑う。そして、日本の運転免許証には既に Mifare Type-B のチップが埋め込まれており、個人であっても市販の安価なカードリーダを使って中身にアクセスできる。実際に運転免許証に対してコマンドを叩き、PIN コードを渡せば、免許証にJPEG2000形式の顔写真やデータが入っていることを個人レベルで確認できるのだから。

そして、自動車でのカードの識別はPINコードを入れることもせず、個人認証をする必要なども一切なく、運転免許証のチップが埋め込まれたカードであることだけを認識できれば良いと考える。難しいことはさせず、誰でも使える手順にすることを考えると、これだけで目的は果たせるからである。

PINコードを入れない限り運転免許証の中のデータは取り出せないため、プライバシーやセキュリティの問題も回避できる。後ろめたい事も無く普通に生きている市民からすると、これで問題ないはずだ。権利侵害だ何だとやたら騒ぐ連中は犯罪者のような連中としか考えられないため、そのような輩の戯言は無視すべきだろう。

チップの認識だけであれば、機能的にも複雑さが抑えられるため、そのレベルのモジュールを大量に導入するのであれば、開発も生産も難しいはずがなく、今後の国産の新車に付けるのであれば価格も当然抑えられるべきであるが、生産側も慈善事業ではないため、ある程度の金額であれば仕方ないと思う。ただ、その価格分も国民の安全のために国策として税金投入しても未来の人命が救われるのであれば安いぐらいだ。国策として国交省辺りが主導的に行うのは利権が作られる可能性が高いとはいっても、実現性を考えれば理想かもしれない。

既存の車に対しては、後付けできるような運転免許証スロット的なモジュールを流通させ、モジュールや作業工賃などの一部をキャッシュバックするキャンペーンを国主導で実施するのも良いと思う。

もちろん、これだけでそれまでの問題が全て解決できるわけではないだろうし、上記の策も完璧なはずもないだろう。しかし、少なくともやらないより、やったほうが確実に人命が救えると確信しているし、我々はできることを模索し続け、実践し、間違っていたなら協議し、より良い方向へ軌道修正すれば良いだけの話ではないのだろうか?

交通事故自体が減ることと、被害があってもできるだけ軽症で済むことを願う。



2023年4月7日金曜日

JSONIC で総称型を使ったデコード

 以下、マニュアルに記載のある内容であり、知っている人にとっては読む価値は無いメモ書き。

何度も忘れるので、ここに書いておく。

Java で JSON を扱う場合に未だ JSONIC を使っている。jackson への移行が推奨されているが、特にパフォーマンス面での不満を感じる規模の要件を対処することもなく機能的にも困っていないため、未だに利用している。

さて、以下のようなシンプルな配列の JSON がサーバに投げ込まれた場合において

[1, 2, 3]

Java で対応する場合、List<Integer> の形式でデコードしたい状況が存在する。

ただし、Java の文法的に以下のように総称型は指定できないため書けない。

String json = "[1,2,3]";
List<Integer> list = JSON.decode(json, List<Integer>.class); // 文法エラーとなる

このような状況に対して、TypeReference クラスを使ってオブジェクトで指定する形を取れば解決する。

List<Integer> list = JSON.decode(json, new TypeReference<List<Integer>>() {});

あるいは渡されるデータをフロントエンド側で投げ込むデータを JSON Object そのものにしてもらい。

{"list": [1, 2, 3]}

以下のように JSON リクエストデータに対応するクラスを準備し、クラス自体を使ってデコードすればよい。

@Data
public class ListRequestJson implements Serializable {
  private List<Integer> list;
}

...

ListRequestJson req = JSON.decode(json, ListRequestJson.class);

2023年4月6日木曜日

PostgreSQL で変数を使う

PostgreSQL のクエリ内で変数を使う方法

運用環境で連番を持つマスタレコードをクエリを使って追加したい場合など、 採番結果を後続のクエリで適用したい状況で、どのように解決するか? このような場合、いくつか方法がある。
 
1. WITH の利用
2. PL/pgSQL の利用

他にも物理的な一時テーブルを作っての対処などでも目的は果たせるが、 それは通常の DB の使い方と変わらないため、ここでは省略する。

1. WITH の利用

以下のクエリが参考になる。
WITH variables AS (
    SELECT 10 AS my_variable
)
SELECT my_variable
  FROM variables;
WITH で定義した内容を後続のクエリで参照して使うことができる。
 
この方法では、WITH で一時テーブルを作り、その直後のクエリで参照すれば使えるだけであり、 一度採番した内容を変数に格納し、連続したクエリで変数を使い回すような処理には適用できない。 そのため、使える局面はかなり限定される。わざわざ覚えて使うほどのものではないと感じる。
 

2. PL/pgSQL の利用

stored procedure をクエリ上で使う方法である。
 
この方法であれば一般的なプログラミングと同じように 完全な変数宣言が可能となるため、連続した処理でも使い勝手が良い方法となる。
 
PL/pgSQL は PL/SQL や Pascal系の言語を書いたことがある人であれば覚える量も少なく簡単に書ける。
 
以下のようなコードが採番処理とレコードの登録、マスタからリンク整備の雛形として使えるだろう。
DO $$ 
DECLARE
	master_id VARCHAR;
	copy_id VARCHAR;
	temp_no INTEGER;
	copy_no INTEGER;
	rec RECORD;
BEGIN
	SELECT '今回追加するマスタID' INTO master_id;
	SELECT 'リンク内容をコピーするID' INTO copy_id;

	-- 登録済判定
	SELECT m.no INTO temp_no FROM master_table m WHERE m.id = master_id;
	IF (temp_no <> 0) THEN
		RAISE NOTICE 'ID:[%] 登録済のため中断', master_id;
		RETURN;
	END IF;

	-- 採番と登録
	SELECT Coalesce(Max(m.no), 0) + 1 INTO tempNo FROM master_table m;
	INSERT INTO master_table (no, id, ... 必要なカラム)
	VALUES (temp_no, master_id, ... マスタ設定内容);
	RAISE NOTICE 'ID:[%] 登録完了', master_id;

	-- 指定ID と同じグループにリンクを貼る
	SELECT m.no INTO copy_no FROM master_table m WHERE m.id = copy_id;
	IF (copy_no = 0) THEN
		RAISE NOTICE 'ID:[%] コピー元が未登録のため中断', copy_id;
	END IF

	-- リンクテーブルに対するSELECT結果を使って新規にリンクを登録する
	FOR rec IN SELECT * FROM link_table l WHERE l.no = copy_no;
	LOOP
		INSERT INTO link_table (no, linkNo) VALUES (temp_no, rec.linkNo);
	END LOOP;
	RAISE NOTICE 'ID:[%] リンク整備 完了', master_id;
END $$;
PL/pgSQL だと癖はあるが、SQL上で可能な操作は全てできるため、ロジックを組む力さえあればなんとでもなる。

2016年11月17日木曜日

Windows で Java から OpenOffice を使い Excel-PDF 変換を試した時のメモ書き

Windows で Java から OpenOffice を叩いて Excel-PDF 変換を試してみた時のメモ書きです。

環境整備


1. Java 開発環境は整備されている前提


2. OpenOffice をダウンロードしてインストール
http://www.openoffice.org/download/

※単体で OpenOffice が動くことを確認

2013年12月20日金曜日

PostgreSQL から SQL-Server へのテーブルスクリプトおよびクエリ移行のメモ

システムで使っている DB を PostgreSQL から MS SQL-Server へ移行する必要があったため、その時のメモを公開できる形でまとめておきます。動いた結果から書いているため、本来とは違う使い方だったり、使う人の環境やバージョンによっては、この限りでないかもしれません。この情報は参考程度にどうぞ。