20210901のJavaに関する記事は12件です。

JSTL の使用手順を易しく解説

自主学習エンジニアがJSTLを使用するにあたって Eclipseとかもそうですが パソコンに疎い人間にはインストール方法でさえ、英語多いし何かとめんどくさいことが多いと感じました... 今回、JSTLを導入するにあたって少し手間取ってしまいました。 図を用いた解説し、わかりやすい記載となるよう心掛けてますので、参考になれば幸いです。 JSTLとは JSTLは「JSP Standard Tag Library」の略で、JSP内でよく使われる機能をタグライブラリとしてまとめたもの インストール手順 JSTLをインストールするには、2つの異なるJARをダウンロードします。 ・Maven RepositoryのJSTL-APIダウンロード先 https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api/1.2 ダウンロードの記載がないので混乱してしまいましたが、fileのjarをクリックするとダウンロードができました ・Maven RepositoryのJSTL実装ダウンロード先 JSTL-APIのダウンロード同様の個所を選択します なお、Microsoft Edge バージョン 92.0.902.84 (公式ビルド) (64 ビット)ではブロックされてしまう場合があるため、他のブラウザで行ってください。(私はGoogleを使用してダウンロードができました。) JARファイルの配置手順 ダウンロードしたJARファイルをプロジェクトの以下に位置します。ドラックアンドドロップで可能です。 WebContent/WEB-INF/lib 次に、ファイルをコピーするを選択しOKをクリックします。 完了画面がこちらです 導入自体は難しくないのですが、ダウンロード先でどこでダウンロードできるか非常にわかりにくかったので記事にしました。 ご覧頂きありがとうございました、以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JAVAでのUDP通信(オンラインチャット実装)

目標 顧客があるサービスのオンラインヘルプに問い合わせすると想定し、チャット機能をjavaで実装する。 機能だけ実装し、UI部分は無し。 TODO整理 目標を実現するのに必要なのは以下が考えられます。 UDP通信 UDP通信特徴 ①リアリティ性が求められない ②かつクライアントとサーバーか、クライアントとクライアントとの通信にこだわらない 今回の実装にUDP通信を使います。 スレッド メッセージ受け取るにも送るのにも同時に行う必要があるのため、スレッドを実装すると考えらる。 実装 メッセージ送信処理 UDP通信はクラスDatagramSocketを使う SendThread.java package com.maekawa.onlineChat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.*; import java.nio.charset.StandardCharsets; public class SendThread implements Runnable { //UDP通信を行うためのソケット DatagramSocket socket = null; //入力を一行ずつ読み込む BufferedReader reader = null; private int fromPort; private String toIp; private int toPort; //コネクションを一回接続のため、初期化してコンストラクタにした。 //送信元のポートと送信先IPとポート初期化処理する public SendThread(int fromPort, String toIp, int toPort) { this.fromPort = fromPort; this.toIp = toIp; this.toPort = toPort; try { socket = new DatagramSocket(fromPort); //コンソールからの入力ストリームを受ける InputStreamReader streamReader = new InputStreamReader(System.in); reader = new BufferedReader(streamReader); } catch (SocketException e) { e.printStackTrace(); } } //ひたすらにメッセージ送信処理をするメソッド @Override public void run() { //whileがないと、一回メッセージ送ったら、接続遮断されちゃう while (true) { try { String data = reader.readLine(); byte[] datas = data.getBytes(); //送信先のIPとポート指定 InetSocketAddress socketAddress = new InetSocketAddress(this.toIp, this.toPort); //パケット送信準備 DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, socketAddress); //送信する socket.send(packet); if(data.equals("bye")){ break; } } catch (IOException e) { e.printStackTrace(); } //接続を遮断する socket.close(); } } } メッセージ受け取る処理する ReceiveThread.java import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; import java.nio.charset.StandardCharsets; public class ReceiveThread implements Runnable { DatagramSocket socket = null; private int receivePort; private String whois; //コネクション設立ためのメソッド public ReceiveThread(int receivePort, String whois) { this.receivePort = receivePort; this.whois = whois; try { //顧客問い合わせ用にこのポートで待ち受けする。 socket = new DatagramSocket(receivePort); } catch (SocketException e) { e.printStackTrace(); } } //受け取ったメッセージをひたすらに処理するメソッド @Override public void run() { while (true) { try { //受け取ったパケットを格納する byte[] datas = new byte[1024]; DatagramPacket packet = new DatagramPacket(datas, 0, datas.length); socket.receive(packet); byte[] data = packet.getData(); String msg = new String(data, 0, data.length); //受け取ったメッセージを出力 System.out.println(whois + msg); if (msg.equals("bye")) { break; } } catch (IOException e) { e.printStackTrace(); } } //接続を遮断する socket.close(); } } 利用者 利用者は送ると受け取る両方用意する Server.java public class Server { public static void main(String[] args) { //顧客への回答スレッド,2222ポートからlocalhostの8888に問い合わせする new Thread(new SendThread(2222,"localhost",8888)).start(); //ヘルパーからのメッセージは9999ポートで受け取る new Thread(new ReceiveThread(9999,"顧客")).start(); } } Custumer.java public class Custumer { public static void main(String[] args) { //顧客問い合わせするスレッド,8888ポートからlocalhostの9999に問い合わせする new Thread(new SendThread(7777,"localhost",9999)).start(); //ヘルパーからのメッセージは7777ポートで受け取る new Thread(new ReceiveThread(8888,"ヘルパー")).start(); } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JAVAでオンラインチャット(チャットボット)実現

目標 顧客があるサービスのオンラインヘルプに問い合わせすると想定し、チャット機能をjavaで実装する。 機能だけ実装し、UI部分は無し。 TODO整理 目標を実現するのに必要なのは以下が考えられます。 UDP通信 UDP通信特徴 ①リアリティ性が求められない ②かつクライアントとサーバーか、クライアントとクライアントとの通信にこだわらない 今回の実装にUDP通信を使います。 スレッド メッセージ受け取るにも送るのにも同時に行う必要があるのため、スレッドを実装すると考えらる。 実装 メッセージ送信処理 UDP通信はクラスDatagramSocketを使う SendThread.java package com.maekawa.onlineChat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.*; import java.nio.charset.StandardCharsets; public class SendThread implements Runnable { //UDP通信を行うためのソケット DatagramSocket socket = null; //入力を一行ずつ読み込む BufferedReader reader = null; private int fromPort; private String toIp; private int toPort; //コネクションを一回接続のため、初期化してコンストラクタにした。 //送信元のポートと送信先IPとポート初期化処理する public SendThread(int fromPort, String toIp, int toPort) { this.fromPort = fromPort; this.toIp = toIp; this.toPort = toPort; try { socket = new DatagramSocket(fromPort); //コンソールからの入力ストリームを受ける InputStreamReader streamReader = new InputStreamReader(System.in); reader = new BufferedReader(streamReader); } catch (SocketException e) { e.printStackTrace(); } } //ひたすらにメッセージ送信処理をするメソッド @Override public void run() { //whileがないと、一回メッセージ送ったら、接続遮断されちゃう while (true) { try { String data = reader.readLine(); byte[] datas = data.getBytes(); //送信先のIPとポート指定 InetSocketAddress socketAddress = new InetSocketAddress(this.toIp, this.toPort); //パケット送信準備 DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, socketAddress); //送信する socket.send(packet); if(data.equals("bye")){ break; } } catch (IOException e) { e.printStackTrace(); } //接続を遮断する socket.close(); } } } メッセージ受け取る処理する ReceiveThread.java import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; import java.nio.charset.StandardCharsets; public class ReceiveThread implements Runnable { DatagramSocket socket = null; private int receivePort; private String whois; //コネクション設立ためのメソッド public ReceiveThread(int receivePort, String whois) { this.receivePort = receivePort; this.whois = whois; try { //顧客問い合わせ用にこのポートで待ち受けする。 socket = new DatagramSocket(receivePort); } catch (SocketException e) { e.printStackTrace(); } } //受け取ったメッセージをひたすらに処理するメソッド @Override public void run() { while (true) { try { //受け取ったパケットを格納する byte[] datas = new byte[1024]; DatagramPacket packet = new DatagramPacket(datas, 0, datas.length); socket.receive(packet); byte[] data = packet.getData(); String msg = new String(data, 0, data.length); //受け取ったメッセージを出力 System.out.println(whois + msg); if (msg.equals("bye")) { break; } } catch (IOException e) { e.printStackTrace(); } } //接続を遮断する socket.close(); } } 利用者 利用者は送ると受け取る両方用意する Server.java public class Server { public static void main(String[] args) { //顧客への回答スレッド,2222ポートからlocalhostの8888に問い合わせする new Thread(new SendThread(2222,"localhost",8888)).start(); //ヘルパーからのメッセージは9999ポートで受け取る new Thread(new ReceiveThread(9999,"顧客")).start(); } } Custumer.java public class Custumer { public static void main(String[] args) { //顧客問い合わせするスレッド,8888ポートからlocalhostの9999に問い合わせする new Thread(new SendThread(7777,"localhost",9999)).start(); //ヘルパーからのメッセージは7777ポートで受け取る new Thread(new ReceiveThread(8888,"ヘルパー")).start(); } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【STS初学者必見】STS(Spring Tool Suite)とH2(簡単に使えるDBMS)を使用してSQL文を発行したかった際に起きた、しょうもない記録

某プログラミングスクール卒業生の備忘録(今回は本気の備忘録) お久しぶりです!本日は、ほんとにただの備忘録なので、参考程度にだけ覚えておいてください。 ※内容がしょうもなさすぎて(笑) 使用環境 ・Mac OS ・Java 11 ・STS(SpringToolSuite) 2.5.4 参考書籍 はじめてのSpring Boot[改訂版] STSでSQLファイルを作成する際、MySQLWorkBenchが開く ということで。 JDBCを使用してSQL文でデータを引っ張ってこようっていう、本の演習をしていたんですけど、 springプロジェクト内の「src/main/resources」の配下に ・schema.sql ・data.sql の二つを作成しようとしたんですよね。 作成した瞬間、別のテキストでダウンロードした、MySQLの操作ツール「MySQL WorkBench」ってやつが起動したんです。 これは違うと思い、ひたすらSQLファイルの作成方法 今回使用するH2データベースの接続方法を調べていたんです(1時間半くらい...)。 結論、それでよかった はい、そうです。その操作ツールでコマンド打ち込んで、「command + S」で保存すれば、ちゃんとファイルにコマンド保存できました。 てっきり、インストールしていたMySQLに関係するんじゃねぇかって決めつけていました。 アホですね。。。 確認できた方法は、Finderにある自分のプロジェクトの中にある 上記二つのファイルを「VSCode」なんかで見ることができます。 最後に 非常にアホでした。笑 決めつけは良くないですね笑 みなさんも同じことになったら、この記事をぜひ参考にしてください笑 ではまた!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

暗号化スイート(AES-GCM)でTLSの安全性を強化する方法

TLS1.2で暗号化スイートを利用して安全性を強化する方法について、紹介させていただきます。 1.暗号化スイートとは SSL/TLS にてデータを暗号化して通信を行うには、自分自身と通信相手の両方が利用可能なアルゴリズムを使う必要があります。 不特定の相手と両者が利用可能なアルゴリズムを確認しあうために使われるのが 暗号スイート(cipher suite) となります。 2.Tomcatで暗号化スイートの設定について 2.1との暗号化スイートを使います? JAVAで指定できる暗号化スイートは以下のサイトを参照してください https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html 例えば、AES-GCMを利用する場合、 上記サイトから関連する暗号スイートをリストアップしました AES-GCM TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS_DH_RSA_WITH_AES_128_GCM_SHA256 TLS_DH_RSA_WITH_AES_256_GCM_SHA384 TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 TLS_DH_DSS_WITH_AES_128_GCM_SHA256 TLS_DH_DSS_WITH_AES_256_GCM_SHA384 TLS_DH_anon_WITH_AES_128_GCM_SHA256 TLS_DH_anon_WITH_AES_256_GCM_SHA384 TLS_PSK_WITH_AES_128_GCM_SHA256 TLS_PSK_WITH_AES_256_GCM_SHA384 TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA2 TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA3 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA25 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA38 TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 2.2暗号化スイート(AES-GCM)をTomcatのコンフィグに指定 server.xml  <Connector port="8888" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" sslEnabledProtocols="TLSv1.3,TLSv1.2" ciphers="TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256" /> 2.3検証 ウェブサイトをアクセスして、TLS通信に置いて、証明書が適用されている事を確認 wiresharkで暗号スイートが適用されている事を確認
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java Word文書でハイパーリンクの挿入・読み取り

ハイパーリンクを挿入することで、ワード内の文字列や図形に別の場所の情報をリンクさせることができます。今回は、Spire.Doc for Javaという使いやすいライブラリを活用して、Word文書にハイパーリンクを挿入、そしてWord文書内のハイパーリンクを読み取る方法を紹介していきます。 1.E-iceblueの公式サイトからFree Spire.doc for Java無料版をダウンロードしてください。 2.IDEを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire.doc.jarを参照に追加してください。   ハイパーリンクを挿入 import com.spire.doc.Document; import com.spire.doc.FileFormat; import com.spire.doc.Section; import com.spire.doc.documents.HorizontalAlignment; import com.spire.doc.documents.HyperlinkType; import com.spire.doc.documents.Paragraph; import com.spire.doc.documents.ParagraphStyle; import com.spire.doc.fields.DocPicture; public class InsertHyperlinks { public static void main(String[] args) { //Wordオブジェクトを作成します。 Document doc = new Document(); Section section = doc.addSection(); //サイトのリンクを追加します。 Paragraph paragraph = section.addParagraph(); paragraph.appendText("サイトのリンク:"); paragraph.appendHyperlink("https://www.google.com/","ホームページ", HyperlinkType.Web_Link); //メールのリンクを追加します。 paragraph = section.addParagraph(); paragraph.appendText("メールのリンク:"); paragraph.appendHyperlink("mailto:support@google.com","support@google.com", HyperlinkType.E_Mail_Link); //段落の形式を設定します。 ParagraphStyle style1 = new ParagraphStyle(doc); style1.setName("style"); style1.getCharacterFormat().setFontName("Ms mincho"); doc.getStyles().add(style1); for (int i = 0; i < section.getParagraphs().getCount(); i++) { section.getParagraphs().get(i).getFormat().setHorizontalAlignment(HorizontalAlignment.Center); section.getParagraphs().get(i).getFormat().setAfterAutoSpacing(true); section.getParagraphs().get(i).applyStyle(style1.getName()); } //保存します doc.saveToFile("InsertHyperlinks.docx", FileFormat.Docx_2013); } } 実行結果 リンクを読み取る import com.spire.doc.*; import com.spire.doc.documents.DocumentObjectType; import com.spire.doc.documents.Paragraph; import com.spire.doc.fields.Field; import java.util.ArrayList; import java.util.List; public class ExtractHyperlinkAddress { public static void main(String[] args){ //Wordファイルをロードします。 Document doc = new Document(); doc.loadFromFile("test.docx"); //sectionを取得します。 Section section = doc.getSections().get(0); //リンクの数列を取得します。 List hyperlinks = new ArrayList(); //段落をループします。 for (Paragraph para : (Iterable) section.getParagraphs()) { for (DocumentObject obj:(Iterable) para.getChildObjects()) { if (obj.getDocumentObjectType().equals(DocumentObjectType.Field)) { Field field = (Field) obj; if (field.getType().equals(FieldType.Field_Hyperlink)) { hyperlinks.add(field); } } } } //リンクを取得します。 String text = hyperlinks.get(0).getFieldText(); String address = hyperlinks.get(0).getValue(); System.out.println("リンクのテキスト:"+ text + "\n" + "リンクの位置:"+ address); } }  
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

java エンコーディングMS932にマップできません エラー解消しよう (記録)

Java日本語のコンパイルエラー解消 以下のコードをコンパイルしようとしてエラーが発生 MyApp.java import java.io.*; class MyApp{ public static void main(String[] args) throws IOException { System.out.println("文字を入力してください"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str = br.readLine(); System.out.println(str + "が入力されました。"); } } ↓コンパイル実行 javac MyApp.java ↓エラー発生 MyApp.java:11: エラー: この文字は、エンコーディングMS932にマップできません System.out.println(str + "縺悟?・蜉帙&繧後∪縺励◆"); 対処法(コンパイル時のコマンドを変更する) × javac MyApp.java ↓ 〇 javac -encoding utf-8 MyApp.java
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java基礎③]データの変換(キャストする)整数→実数 文字列→整数

初めに Java学習3日目です。今回は、データ型の変換について学びました。 データ型の変換をデータのキャストと言うそうです。 小数点あり→整数型 double型の3.14と定義した値を3と表示します。 コード public class Main { public static void main(String[] args) { double number1 = 3.14; System.out.println((int)number1); } } 整数を小数点ありに変換 コード public class Main { public static void main(String[] args) { double number1 = 3; System.out.println((double)number1); } } 文字列を数値に変換 コード public class Main { public static void main(String[] args) { String text = "123"; System.out.println(text);        #出力結果 123 System.out.println(Integer.parseInt(text));        #出力結果 123 System.out.println(Double.parseDouble(text));        #出力結果 123.0 } } 「parseInt」は文字列はint型に変換してくれるメソッド。 「parseDouble」は文字列をdouble型に変換してくれるメソッド。 捕捉 データ型の自動変換 割引価格を計算してみる 以下のコードはエラーになります。 int discountPrice = price * 0.5;は、 int型で定義していますが0.5という少数をかけることにより、 double型に変換されてしまっているからです。 エラーになるコード public class Main { public static void main(String[] args) { int price = 1800; System.out.println("定価" + price + "円"); int discountPrice = price * 0.5; System.out.println("割引価格は" + discountPrice + "円"); } } 一部、以下のように修正します。 intにキャストする int discountPrice = (int)(price * 0.5); 消費税こみの価格を出す コード public class Main { public static void main(String[] args) { int price = 1800; System.out.println("定価" + price + "円"); int discountPrice = (int)(price * 0.5); System.out.println("割引価格は" + discountPrice + "円"); int taxinPrice = (int)(discountPrice*1.1); System.out.println("税込価格は" + taxinPrice + "円"); } } まとめ データ型の変換を「キャストする」と言う。 #文字列→整数 System.out.println(Integer.parseInt(text)); #文字列→実数 System.out.println(Double.parseDouble(text)); #intで定義してても、少数点のある数字をかけると、double型になる。 int discountPrice = price * 0.5;は、 double型に自動変換されてしまう。 以下のようにint型にキャストする。 int discountPrice = (int)(price * 0.5);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

== operator for String object in Java

First please read this if you don't sure how to use == operator for object. Example from The Java® Language Specification Got from here. package testPackage; class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); // (1) System.out.print((Other.hello == hello) + " "); // (2) System.out.print((other.Other.hello == hello) + " "); // (3) System.out.print((hello == ("Hel"+"lo")) + " "); // (4) System.out.print((hello == ("Hel"+lo)) + " "); // (5) System.out.println(hello == ("Hel"+lo).intern()); // (6) } } class Other { static String hello = "Hello"; } package other; public class Other { public static String hello = "Hello"; } The output is true true true true false true Things you need to know about String class String object is immutable A pool of strings, initially empty, is maintained privately by the class String. You may use intern() for looking up reference (Output of (6)) All String constants will refer to the same String instance if the values are the same during compile time, no matter what package is in. And a reference will be stored in pool stated in point 2 (Output of (1), (2), (3), (4)) New String object will be created during runtime (Output of (5)) Suggestion Don't use == operator for checking if value of two String objects are equal. Please use equals() instead.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

消費税

TAX_RATE =0.8;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

== operator for object in Java

In past I don't understand why code in inner block doesn't run. if (new Integer(1) == new Integer(1)) { doImportantJob(); }; Since "==" operator for object means if both objects point to the same memory location. The code above means two Integer(1) object is created, of course two sides must point to different memory location.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LocalDateTimeの相互変換 決定版

はじめに タイムゾーンがある場合に迷ったりしたので、LocalDateTimeを使用した日付の処理についてまとめました。 目次 1. now()で日時を取得する 2. format(LocalDateTimeから文字列への変換) 3. parse(文字列からLocalDateTimeに変換) 4. LocalDateTime同士の比較について 5. UNIX時間(エポック秒)の変換 6. Use case 公式ドキュメント ZonedDateTime (Java Platform SE 8 ) DateTimeFormatter (Java Platform SE 8 ) ZoneId (Java Platform SE 8 ) 1. now()で日時を取得する // タイムゾーンなしのUTC、JSTそれぞれで取得したい場合 LocalDateTime.now(ZoneId.of("UTC")); LocalDateTime.now(ZoneId.of("Asia/Tokyo")); LocalDateTime.now(); // 実行されるサーバによってタイムゾーンが異なるため注意 // 2021-08-30T09:00:00.123456 // 2021-08-30T18:00:00.123456 // 2021-08-30T18:00:00.123456  <- ローカルで実行した場合はJSTでした // タイムゾーンありの日付を取得したい場合(戻り値は ZonedDateTime クラスとなる) LocalDateTime.now(ZoneId.of("UTC")).atZone(ZoneId.of("UTC")); LocalDateTime.now(ZoneId.of("Asia/Tokyo")).atZone(ZoneId.of("Asia/Tokyo")); // 2021-08-30T09:00:00.123456Z[UTC] // 2021-08-30T18:00:00.123456+09:00[Asia/Tokyo] // NGパターン (時間がずれます) LocalDateTime.now(ZoneId.of("UTC")).atZone(ZoneId.of("Asia/Tokyo")); // 2021-08-30T09:00:00.123456+09:00[Asia/Tokyo] // 初めからZonedDateTimeで取得することもできます // タイムゾーンありの場合はこちらで取得した方が良さそうです ZonedDateTime.now(ZoneId.of("UTC")); ZonedDateTime.now(ZoneId.of("Asia/Tokyo")); // 2021-08-30T09:00:00.123456Z[UTC] // 2021-08-30T18:00:00.123456+09:00[Asia/Tokyo] 【要点】 タイムゾーンのあり/なしに関わらず、now()の引数に指定したZoneIdの日時が取得されます。 2. format(LocalDateTimeから文字列への変換) // タイムゾーンなし LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("UTC")); localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE); // 2021-08-30T09:00:00.123456 // 2021-08-30 // タイムゾーンあり ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("UTC")); zonedDateTime.format(DateTimeFormatter.ISO_DATE_TIME); zonedDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSxxx")); // 2021-08-30T09:00:00.123456Z[UTC] // 2021-08-30T09:00:00.123456+00:00 // フォーマットの際にJSTに変換 zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo")).format(DateTimeFormatter.ISO_DATE_TIME); zonedDateTime.format(DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.of("Asia/Tokyo"))); // 2021-08-30T18:00:00.123456+09:00[Asia/Tokyo] // 2021-08-30T18:00:00.123456+09:00[Asia/Tokyo] 【要点】 以下のformatterが主に使用されると思うので対応を覚えておくといいと思います。 形式 タイムゾーン formatter 年月日 + 時分秒 なし ISO_LOCAL_DATE_TIME 年月日 なし ISO_LOCAL_DATE 年月日 + 時分秒 あり ISO_DATE_TIME 3. parse(文字列からLocalDateTimeに変換) // タイムゾーンなし LocalDateTime.parse("2021-08-30T09:00:00.123456", DateTimeFormatter.ISO_LOCAL_DATE_TIME); // 年月日をフォーマットする場合はLocalDateクラスになっていることに注意 LocalDate.parse("2021-08-30", DateTimeFormatter.ISO_LOCAL_DATE); // 2021-08-30T09:00:00.123456 // 2021-08-30 // タイムゾーンあり ZonedDateTime.parse("2021-08-30T09:00:00.123456Z", DateTimeFormatter.ISO_DATE_TIME); DateTimeFormatter.ISO_DATE_TIME.parse("2021-08-30T09:00:00.123456Z", ZonedDateTime::from); // 2021-08-30T09:00:00.123456Z // 2021-08-30T09:00:00.123456Z // LocalDateTimeでもフォーマットできますが、タイムゾーンがなくなるのでお勧めしません // タイムゾーンありの文字列はformatterをISO_DATE_TIMEにしないとエラーとなります LocalDateTime.parse("2021-08-30T09:00:00.123456Z", DateTimeFormatter.ISO_DATE_TIME); LocalDateTime.parse("2021-08-30T18:00:00.123456+09:00", DateTimeFormatter.ISO_DATE_TIME); // 2021-08-30T09:00:00.123456 // 2021-08-30T18:00:00.123456 // フォーマット時にJSTに変換することもできます ZonedDateTime.parse("2021-08-30T09:00:00.123456Z", DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.of("Asia/Tokyo"))); // 2021-08-30T18:00:00.123456+09:00[Asia/Tokyo] 【要点】 タイムゾーンありの文字列は基本的にZonedDateTimeを使用した方が良いと思います。 後述しますが、ZonedDateTime同士で比較することでタイムゾーンを意識しなくて良くなるためです。 4. LocalDateTime同士の比較について // equalsではなくisEqualを使用するのに注意 ZonedDateTime utc = ZonedDateTime.parse("2021-08-30T09:00:00.123456+00:00", DateTimeFormatter.ISO_DATE_TIME); ZonedDateTime jst = ZonedDateTime.parse("2021-08-30T18:00:00.123456+09:00", DateTimeFormatter.ISO_DATE_TIME); utc.isEqual(jst); // true ZonedDateTime utc = ZonedDateTime.parse("2021-08-30T09:00:01.123456+00:00", DateTimeFormatter.ISO_DATE_TIME); ZonedDateTime jst = ZonedDateTime.parse("2021-08-30T18:00:00.123456+09:00", DateTimeFormatter.ISO_DATE_TIME); utc.isAfter(jst); utc.isBefore(jst); // true // false 【要点】 ZonedDateTimeで比較することでUTCとJSTでタイムゾーンが異なっても正しく比較できます。 isAfterは引数より自分が未来か、isBeforeは引数より自分が過去かという風に、引数の日付を起点に過去か未来かを考えると理解しやすいと思います。 5. UNIX時間(エポック秒)の変換 // LocalDateTime -> エポック秒 LocalDateTime localDateTimeUtc = LocalDateTime.parse("2021-08-30T09:00:00.123456", DateTimeFormatter.ISO_LOCAL_DATE_TIME); LocalDateTime localDateTimeJst = LocalDateTime.parse("2021-08-30T18:00:00.123456", DateTimeFormatter.ISO_LOCAL_DATE_TIME); localDateTimeUtc.toEpochSecond(ZoneOffset.UTC); localDateTimeUtc.toEpochSecond(ZoneOffset.ofHours(9)); // NG localDateTimeJst.toEpochSecond(ZoneOffset.UTC); // NG localDateTimeJst.toEpochSecond(ZoneOffset.ofHours(9)); // 1630314000 -> 2021-08-30T09:00Z // 1630281600 -> 2021-08-30T00:00Z // 1630346400 -> 2021-08-30T18:00Z // 1630314000 -> 2021-08-30T09:00Z // ZonedDateTimeの場合 ZonedDateTime zonedDateTimeUtc = ZonedDateTime.parse("2021-08-30T09:00:00.123456Z", DateTimeFormatter.ISO_DATE_TIME); ZonedDateTime zonedDateTimeJst = ZonedDateTime.parse("2021-08-30T18:00:00.123456+09:00", DateTimeFormatter.ISO_DATE_TIME); zonedDateTimeUtc.toEpochSecond(); zonedDateTimeJst.toEpochSecond(); // 1630314000 -> 2021-08-30T09:00Z // 1630314000 -> 2021-08-30T09:00Z // エポック秒 -> LocalDateTime // UTC : 2021-08-30T09:00Z Instant instant = Instant.ofEpochSecond(1630314000); // ZonedDateTimeに変換 instant.atZone(ZoneId.of("UTC")); instant.atZone(ZoneId.of("Asia/Tokyo")); // 2021-08-30T09:00Z[UTC] // 2021-08-30T18:00+09:00[Asia/Tokyo] // LocalDateTimeに変換 instant.atZone(ZoneId.of("UTC")).toLocalDateTime(); LocalDateTime.ofInstant(instant, ZoneId.of("UTC")); // 2021-08-30T09:00 // 2021-08-30T09:00 【要点】 LocalDateTimeからエポック秒に変換する際は、タイムゾーンがどこなのかを意識していないと時間がずれてしまいます。 ZonedDateTimeで保持しておけばタイムゾーンを意識せずエポック秒に変換できるので便利です。 6. Use case // 文字列で日時(UTC)を受け取り、タイムゾーンなしの文字列(JST)に変換 ZonedDateTime.parse("2021-08-30T09:00:00.123456Z", DateTimeFormatter.ISO_DATE_TIME) .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.of("Asia/Tokyo"))); // 2021-08-30T18:00:00.123456 // now()で現在日付を取得した後、前日の23時59分59秒を設定する LocalDateTime.now(ZoneId.of("Asia/Tokyo")) .minusDays(1) .toLocalDate() .atTime(LocalTime.MAX) .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); // 2021-08-29T23:59:59.999999999 LocalTime.MAXは秒以下が9桁になるので、用途によっては独自にフォーマットした方が良いかもしれません。 おわりに この記事を書いている中で思ったのは、ZonedDateTimeで初めにタイムゾーンを決めて保持しておけばそれ以降変換の際にタイムゾーンを意識しなくてもよいので基本的にはZonedDateTimeで保持した方が良いのではないかということです。 LocalDateTimeだとZonedDateTimeやエポック秒に変換する際にタイムゾーンがUTCかJSTのどっちだったか気にする必要があります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む