ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

Android の Instrumented Test で指定のサイズのテストだけ実行する (@SmallTest とか @LargeTest とか)

Android Testing Support Library (ATSL) の話。 バージョン 0.5 時点での情報です。

ライブラリの準備方法などはドキュメントを読んでください。

テストサイズを表すアノテーション

android.support.test.filters というパッケージがあって、この中にはテストをフィルタするのに使用できるアノテーションが入っています。 その中に、テストのサイズを表すためのアノテーションが 3 つ入っています。

これらはテストクラス自体に付けることもできますし、メソッド単体に付けることもできます。 実装を見たところ、メソッドとクラスの両方にアノテーションが付けられている場合はメソッドアノテーションが優先されるようです。

ちなみに、Android Testing Support Library じゃなくて android.test.suitebuilder.annotation パッケージの方にも同名のアノテーションがありますが、そっちは deprecated ぽいし AndroidJUnitRunner と組み合わせて使うことはできないぽいので注意しましょう。

AndroidJUnitRunner とテストサイズによるフィルタリング

AndroidJUnitRunner でテストを実行する場合、テストサイズによるフィルタリングが可能です。 下記 Javadoc にいろいろ書かれています。

adb でテスト実行する場合

上のドキュメントでは、adb コマンドでテストを実行する際にどういうオプションを渡せばいいかが主に書かれています。 例えば、small サイズのテストのみを実行する場合は、以下のようになります。

adb shell am instrument -w -e size small your.test.target/android.support.test.runner.AndroidJUnitRunner

Gradle の connectedAndroidTest タスクで実行する場合

AndroidManifest.xml で指定する (ただし現在はバグで動かない)

上のドキュメントには All arguments can also be specified in the in the AndroidManifest via a meta-data tag ということが書かれています。 すなわち、テスト用のアプリパッケージの AndroidManifest.xml ファイル (app/src/androidTest/AndroidManifest.xml ファイル) に以下のような記述をすると、small サイズのテストのみが実行されるはず、ということです。

    <instrumentation
        android:name="android.support.test.runner.AndroidJUnitRunner"
        android:targetPackage="...">
        <meta-data android:name="size"
                   android:value="small"/>
    </instrumentation>

ただし現在はバグで動きません。 (指定が無視されます。) バグ報告を上げたので、対応状況は下記ページをご覧ください。

バグがなければ、上のような記述をしておけば ./gradlew :app:connectedAndroidTest という感じで Gradle タスクでテストを実行したときにテストサイズのフィルタリングが効きます。

Gradle のビルドスクリプトで指定する

AndroidManifest.xml に書かずに Gradle のビルドスクリプトにオプションを指定することができます。 上の方法の代わりにこの方法を使うことで、上のバグを回避できます。 sumio さんに教えて頂きました。


android {
    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArguments size: 'small'
    }
}

上のような感じで書きます。

Android Studio 上でテストを実行する場合

Android Studio 上でテストを実行する場合は、build.gradle での記述が有効にならないので、configurations を弄る必要があります。 下図のような感じで、Extra options に 「-e size small」 と入力すれば良いです。

f:id:nobuoka:20160527031054p:plain

おわり

@SmallTest アノテーションとか @LargeTest アノテーションとかがあって、テスト実行時にそれらのフィルタリングができるという情報を過去に見たのですが、いざやってみるとあまり情報がなくてうまくいかなかったのでまとめてみました。

コミットごとのテストは @SmallTest だけにして、ある程度開発が終わってレビューに出す前の段階になったら @MediumTest@LargeTest のテストも行うようにする、とかにしたらテストにかかる時間が短くなっていいかもしれませんね。

関連ページ

ISO 8601 DateFormat 1.0.0 (Java 向けライブラリ) をリリースしました

2016 年 5 月 3 日に ISO 8601 DateFormat の 1.0.0 をリリースしました。 ISO 8601 形式 (もしくは RFC 3339W3C-DTF 形式) の日付時刻文字列のパースとフォーマットのための DateFormat のサブクラスを提供するライブラリです。

Bintray の JCenter リポジトリで公開しています。

現在は、時刻オフセット付きの拡張形式の日付時刻文字列のみをサポートしています。

  • 2016-01-01T00:30:21Z
  • 2016-01-01T09:30:21+09:00

動機

Java では、ISO 8601 形式の日付時刻文字列をパースする方法がいろいろあります。 例えば、SimpleDateFormat で “yyyy-MM-dd'T'HH:mm:ssX” というフォーマットを使う (Java SE 7 以降) とか、Date and Time API (JSR 310; Java SE 8 以降) を使うとか、Joda-Time ライブラリを使うとか、Apache Commons Lang ライブラリを使うなどです。

しかし、Java SE 6 環境や Android プラットフォームでは、大きなライブラリを導入することなく ISO 8601 形式の文字列をパースすることが簡単ではありませんでした。 そのため、このようなライブラリを公開しました。

使い方

Gradle を使っている場合、以下のようにリポジトリと依存を追加します。

repositories {
    jcenter()
}
dependencies {
    compile 'info.vividcode:date-format-iso8601:1.0.0'
}

あとは、以下のように使うだけです。

import info.vividcode.time.iso8601.Iso8601ExtendedOffsetDateTimeFormat;

DateFormat f = new Iso8601ExtendedOffsetDateTimeFormat();
Date d1 = f.parse("1970-01-01T00:00:00Z");
Date d2 = f.parse("1970-01-01T09:00:00+09:00");

最新の情報はリポジトリの README ファイルを見てください。

ISO 8601 関連の情報

小さなライブラリが欲しいのでなければ、Joda-Time や Apache Commons Lang、JSR 310 のバックポートライブラリなどを使うのが良いかもしれません。

「DroidKaigi 2016」 と 「関モバ #11」 で発表しました

「DroidKaigi 2016」 にて 『5 年続く 「はてなブックマーク」 アプリを継続開発する技術』 というタイトルで、また 「関モバ #11」 で 『Components­Recycler­Adapter — RecyclerView で複数の view type や複雑なデータ構造を扱う』 というタイトルで、それぞれ発表しました。

DroidKaigi 2016

5 年前に最初のリリースが行われたアプリを継続的に開発しており、そのための取り組みを共有しました。

要点をまとめると以下のようになります。

  • テストは Testing Support Library に頼っている。
    • 最近は Android の標準のテストフレームワークが充実してきている。
    • まだほとんどテストを書いていないというプロジェクトでは、まずは標準のテストフレームワークを使い始めると良いと思う。
    • 今回の DroidKaigi でも、テストに関する多数のセッションがあり、参考になる。
  • CI については、社内の Jenkins サーバー上でテストの実行やリリースパッケージ作成の自動化を行っている。
    • 各種タスクを Gradle タスクとして定義し、タスクの実行をシェルスクリプトで記述。
    • 最近は Jenkins Workflow plugin への移行を進めている。 (Groovy での DSL が書きやすいとか、リリースパッケージのアップロード処理の前に人の確認を挟みやすいなどの利点のため。)
  • Preview 版 (production flavor の preview) を定義して、開発中の機能を preview 版で有効に。
    • 長い期間の開発でも他ブランチとのコンフリクトをしづらく & チーム内配布で確認しやすく。
  • Annotations Support Library を活用。
  • 必要に応じてライブラリ的なものを作る。
    • 例えば 「関モバ #11」 で発表した ComponentsRecyclerAdapter など。

Preview 版について補足

開発中の機能を Preview 版 (product flavor の preview) でのみ有効にする、という話がスライド中に出てきます。 これについて、具体的な方法がわからないということで質問いただきました。 (src/preview/java 下に preview 版専用のソースコードを書くとすると面倒くさすぎるのでは? という。)

具体的には、ソースコードは全て src/main/java 下に置いて、

  • build.gradle ファイル内で buildConfigField を使って preview 版専用の機能を有効にするかどうかの値を持ったフィールドを BuildConfig に生成し、
  • Java のコード中で BuildConfig のフィールドを見て if で条件分岐して機能を有効にしたり無効にしたりする

という感じです。

関西モバイルアプリ研究会 #11


ComponentsRecyclerAdapter を用いて複数の view type や複雑なデータ構造を扱う

複数の item view や複数のデータセットによる複雑なデータ構造を扱いやすくする RecyclerView.Adapter のサブクラス ComponentsRecyclerAdapter の紹介です。

Android の Drawable への着色について (Drawable tinting)

Android APIs を眺めていると “tint” って単語が良く出てきます (“android:backgroundTint” とか “android:progressTint” とか) が、tint についてあんまり日本語の情報がなかったのでまとめてみます。

ちなみに “tint” の英語としての意味は、名詞で 「色合い」 とか 「染料」、動詞だと 「色を付ける」 や 「染める」 などです。

このエントリの内容

  • API level 21 から使えるようになった Drawable への色付け (Drawable tinting) について説明します。
    • アルファマスクとして Drawable を定義し、表示時に色を指定するための機能です。
  • View の背景の Drawable への着色のための、あるいは ProgressBarImageView などで表示される Drawable への着色のためのメソッドXML の属性を紹介します。
  • これらの機能を API level 21 未満でも使用できるようにするための Android Support Library が提供するメソッドを紹介します。

Drawable への着色 (Drawable tinting)

API level 21 から、Drawable リソースをアルファマスクとして定義し、その Drawable に色を付けて表示する、ということができるようになりました。 同じ形で異なる色のアイコンを複数個用意したいというような場面で便利ですね。

Android 5.0(API レベル 21)以降では、アルファ マスクとして定義されたビットマップや 9-patch に色を付けることができます。 着色には、カラーリソースまたはカラーリソースに変換されるテーマ属性を使用できます(?android:attr/colorPrimary など)。

ドローアブルの使用 | Android Developers

bitmapあるいはnine-patcheをアルファマスクとして定義しcolorリソースやテーマの属性で色づけする

L Developer Preview マテリアルデザイン - アニメーション - Firespeed

Drawable クラスに、下記のメソッドが追加されています。

これらを使うことで、Drawable に着色することができます。

// 通常通り Drawable オブジェクトを取得し、#setTint メソッドや #setTintMode メソッドを呼ぶことで着色。
Drawable d = getDrawable(R.drawable.example);
d.setTint(ContextCompat.getColor(this, R.color.exampleTint));
d.setTintMode(PorterDuff.Mode.SRC_IN);

// 後はこの Drawable オブジェクトを使う。
imageView.setDrawable(d); // 例えば ImageView で表示する。

ちなみに、この機能が導入される前から、同様のことが Drawable#setColorFilter メソッド で実現できていたようです。 setColorFilter を呼んだ場合は、tint の設定は上書きされます。

Tint mode について

Drawable#setTintMode(PoterDuff.Mode) メソッドでは、元の Drawable と Tint の色をどのように混ぜるかを Porter-Duff のルールで指定します。 元の Drawable が destination で、着色する色が source です。

デフォルトでは Source In Destination 規則 (PorterDuff.Mode.SRC_IN) が使用されます。 これは、単純に tint が不透明な単色の場合、合成後の各ピクセルの不透明度は元の Drawable の不透明度になり、合成後の各ピクセルの色は tint の色になるというものです。 まさに Drawable がアルファマスクになるわけです。

Porter-Duff のルールについては以前このブログに書きました。 下記エントリを参照してください。

Support library による Drawable への着色のサポート

API level 21 から導入された Drawable への着色の機能ですが、v4 Support Library に含まれる DrawableCompat クラスを使うことで、古い API level でも同様の機能を実現できます。

Drawable d = DrawableCompat.wrap(ContextCompat.getDrawable(this, R.drawable.example));
DrawableCompat.setTint(d, ContextCompat.getColor(this, R.color.exampleTint));
DrawableCompat.setTintMode(d, PorterDuff.Mode.SRC_IN);

対象の Drawable を DrawableCompat#wrap メソッドに渡して tint 対応の Drawable に変換し、それを DrawableCompat#setTint メソッドなどに渡す、という使い方になります。

Drawable への着色の応用

実際に Drawable への着色をしたい場面というのは、例えば View の背景に Drawable をセットしてその Drawable に着色するだとか、ImageView で表示する Drawable に着色するだとか、あるいは ProgressBar の (プログレスバーそのものを表す) Drawable に着色するだとか、そういう場面が多いでしょう。 そのような場面で簡単に Drawable への着色が行えるように、Java クラスのメソッドやレイアウトの XML で使える属性などが用意されています。

各 view の背景の Drawable への着色 (Background tint)

API level 21 で導入された下記のメソッドXML 属性を使用して、簡単に背景の Drawable に着色できます。

API level 21 未満の環境でこれらの機能が使えるように、v7 appcompat library が各種 compatible widget を提供しています。 (ただし、対応されている View のクラスは一部のみ。) よって、v7 appcompat library を使うことで、以下のようにして API level 21 未満の環境でも background tint を使用できます。

<!-- v7 appcompat library を使用していると、この TextView はインフレート時に AppCompatTextView に変換される。 -->
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/example_text_view_background"
    app:backgroundTint="@color/exampleTextViewBackgroundTint"/>

ただ、上のような書き方をすると Android Studio でエラーが表示されるのが悩ましいところです。 (AppCompatTextView への変換まで認識してくれないため。)

f:id:nobuoka:20160213200931p:plain

v7 appcompat library の compatible widget については以前エントリを書きましたので、詳しくは下記エントリを参照してください。

その他の Drawable の着色

ImageView には、表示する Drawable に着色するためのメソッドが存在します。

ProgressBar でも Drawable への着色が可能です。

調べられていませんが、Drawable を扱う他の View クラスにも似たような機能があるかもしれません。

API level 21 未満でこのような機能を使えるようにする互換クラスは (今のところ) Android Support Library には含まれていないようですので、API level 21 未満では直接 Drawable に着色したうえで ImageView にセットしたり ProgressBar にセットしたりする必要がありそうです。

まとめ

  • API level 21 から Drawable への色付けがサポートされました。 (Drawable tinting)
    • 基本的には、アルファマスクとして Drawable を定義し、表示時に色を指定するという使い方が想定されています。
  • View の背景の Drawable への着色や、ProgressBarImageView などで表示される Drawable への着色も簡単に行えるようになっています。
  • Android Support Library を使うことで、Drawable への着色の機能や View の背景の Drawable への着色が API level 21 未満でも利用できます。

関連ページ

Android の Java で時刻を扱う (Date、Calendar、DateFormat クラス)

Java エンジニアの皆様は Java SE 8 で導入された Date-Time パッケージ (Date and Time API; JSR 310) を便利に使っていることと思います。 残念ながら Android プラットフォームにはそれらの API がありませんので、Android アプリ開発時に時刻を扱う場合は、古くからある API を使用することになります。

この記事では、Android アプリ開発時にお世話になる Date クラス、Calendar クラス、DateFormat クラスについて、それぞれの役割や使い方、気を付けるべきことをまとめます。

追記

(2020-06-03) Android での Date-Time パッケージ

AndroidAPI Level 26 からは java.time パッケージが使えるようになっています。

Android 8.0 (API level 26) adds support for several additional OpenJDK Java APIs:

  • java.time from OpenJDK 8.
  • java.nio.file and java.lang.invoke from OpenJDK 7.
Android 8.0 Features and APIs  |  Android Developers

また、Android Gradle Plugin 4 からは、Java 8+ API desugaring support により、API Level 26 未満のプラットフォームでも java.time パッケージを使用するアプリをビルドできるようになったようです。

If you're building your app using Android Gradle plugin 4.0.0 or higher, the plugin extends support for using a number of Java 8 language APIs without requiring a minimum API level for your app.
(略)
The following set of APIs are supported when building your app using Android Gradle plugin 4.0.0 or higher:

  • (略)
  • A subset of java.time
Use Java 8 language features and APIs  |  Android Developers

(2016-02-18) JSR 310 の Android バックポート

JSR 310 の Android バックポートライブラリの存在を知りました。 Android ではこれを使うのがいいかもしれないですね。

ところで Time クラスは?

Android APIs には Time クラスってやつが含まれています。 API level 22 で非推奨 (deprecated) になったのでそっとしておきましょう。 (これまでありがとうございました。)

気を付けるべきことまとめ

記事が長いので、気を付けるべきことを最初に書いておきます。

  • Date オブジェクト自体はタイムゾーンを持ちません。
    • Calendar を使って指定の Date の年月日や時、分、秒などを取得するとき、あるいはそれらの値を設定したり計算したりするときは、Calendar に適切なタイムゾーンを設定しましょう。 ロケールも必要に応じて設定しましょう。
    • DateFormat を使って Web API などに投げるための時刻の文字列を生成するときは、DateFormat に適切なタイムゾーンを設定しましょう。 ロケールLocale.US が良さそうです。 *1
  • DateFormat を使って Web API などから取得した時刻の文字列を解析する際は、必要であれば適切なタイムゾーンを設定しましょう。 (解析対象の文字列にタイムゾーンが含まれているのであれば必要ない。) ロケールLocale.US が良さそうです。
  • Android *2SimpleDateFormat は、ISO 8601 や RFC 822 で定義されていて実際にしばしば使われる 「Z」 というタイムゾーン表記を解釈できない (Java SE 7 では X というフォーマット文字が導入されて解釈できるようになった) ので、気を付けましょう。
  • ユーザーに表示するための時刻の文字列を生成する際は、andorid.text.format.DateFormat オブジェクトを使うことで端末の設定を反映させると良いでしょう。

DateCalendarDateFormat、それぞれの役割

簡単にまとめると、Date クラスが 「時間軸上の特定の瞬間」 を表すもので、Calendar クラスが年月日や時、分、秒といった情報を扱うクラス、そして DateFormat が時刻を表す文字列と 「時間軸上の特定の瞬間」 の相互変換を行う、という感じです。 詳細は以下に述べます。

Date クラス

Date クラスは、時間軸上の特定の瞬間をミリ秒の精度で表現するクラスです。

純粋に 「時間軸上のある瞬間」 を表現するためのものなので、タイムゾーンを持ちませんし、自身が表現する時刻が何月何日の何時何分なのかを計算したりもしません。 時刻を表現する文字列をパースしたり、逆に時刻を表現する文字列を出力したりもしません。 (歴史的経緯によりそのような機能のメソッドが Date クラスに定義されていますが、非推奨です。)

Calendar クラス

Calendar クラスは、次の 2 つの機能を提供するクラスです。

  • 「時間軸上の特定の瞬間」 と 「何月なのかや何日なのか、何時なのかといった数値情報・カレンダー情報」 の相互変換
  • 何日なのかや何時なのかといった数値情報・カレンダー情報に対する計算。 (例えば、1 週間後の日時を取得する、など。)

Calendar オブジェクトで時刻を表現させようと思えば実際上は可能ではありますが、そういう使い方には Date オブジェクトを用いるべきみたいですね。 年月日などを扱うので、このクラスを使う際は当然 タイムゾーンを気にする必要があります

GregorianCalendar クラス

Calendar クラスは抽象クラスで、変換や計算の処理は各種サブクラスが提供することになっています。 世界のほとんどの地域で使用される標準的な暦体系に対する実装として、GregorianCalendar が提供されています。

DateFormat クラス (java.text パッケージ)

「時間軸上の特定の瞬間」 を表す値から日付・時刻を表す文字列を生成したり、逆にそれらの文字列を解析する機能を持つクラスです。

年月日などを扱うので、このクラスを使う際は当然 タイムゾーンを気にする必要があります

SimpleDateFormat クラス

DateFormat のサブクラスです。 自分で日付・時刻の文字列のフォーマットを指定する場合はこのクラスを使用することになります。

DateFormat クラス (android.text.format パッケージ)

めちゃくちゃややこしいのですが、Android APIs には android.text.format.DateFormat というクラスも含まれています。 このクラス自身もフォーマット機能を持っていますし、java.text.DateFormat オブジェクトを返すファクトリメソッドも持っています。

API level 23 の実装だと、java.text.Date クラスの getDateInstance メソッドや getTimeInstance メソッドも端末の設定を見てくれるようですが、API level 10 では android.text.format.DateFormatgetDateFormat メソッドなどを使わないと端末の設定が反映されないようです。 (どこで変更されたかは調べてない。)

なので、端末の設定を反映させて日時や時刻を表示したい場合は、android.text.format.DateFormat クラスを使ってフォーマットを決める必要があるようです。

使い方

各種ユースケースにおいて、上で紹介したクラスをどのように使うかを簡単に紹介します。

Web API でやり取りする時刻の文字列と Date オブジェクトを相互変換する

Web API のレスポンスで "2016-01-01 00:00:00+0900" みたいな時刻を表す文字列を受け取ることがあると思いますが、そういった文字列を Date オブジェクトに変換するにはフォーマットを指定して SimpleDateFormat オブジェクトを作成しましょう。

java.text.DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ", Locale.US);
// タイムゾーンが含まれていないような日付文字列を解析する場合は、適したタイムゾーンを指定しましょう。
// df.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));

Date d = df.parse("2015-01-01 00:00:00+0900");

ロケールタイムゾーンの処理にも関わってるぽいです (まじか……) し、Locale.US にしておくのが良さそうです。 例えば、パターン Z を使用してタイムゾーンを解析する場合、Locale.US ならば 「EDT」 を処理できますが、Locale.ROOTLocale.JAPAN だとパースエラーになります。 (API level 23 で確認。 ロケールに関係なく RFC 822 で定義されているタイムゾーンは解析して欲しい……。 厳しい。) でも Locale.US でも 「Z」 を処理できないから、数値でなく名前で表現されるタイムゾーンの解析周りについてはそもそも信用しないのがいいかもしれないですね。

Web API などに送るための時刻文字列を生成する場合も、同様に SimpleDateFormat を使いましょう。 タイムゾーンは、受け取り側が期待するであろうものを設定しておくのが安全だと思います。

java.text.DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ", Locale.US);
// タイムゾーンを出力するにしても Web API 側が期待するタイムゾーンを設定しておいた方が安全でしょう。
df.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));

String currentTime = df.format(new Date());

ユーザーに表示するために Date オブジェクトから時刻の文字列を生成する

ユーザーに表示するための時刻文字列は、ユーザーの端末のロケールタイムゾーンを使用すべきでしょう。 Java では DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault()) という感じでデフォルトロケールDateFormat を取得できますが、Android アプリの場合は、端末の設定を反映したフォーマットの DateFormat を取得するために android.text.format.DateFormat を使用するのが良さそうです。

詳細は以下のページを見てください。

(API level 23 では、DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault()) みたいな感じで取得した DateFormat オブジェクトも端末の設定を反映しているようでしたが、API level 10 だと反映してなかったので、古い端末もサポートするなら android.text.format.DateFormat を使うべきっぽいです。)

Date オブジェクトが表す日の 1 年後、を計算する

例えば今日の 1 年後を表す日を計算したいとします。 そういうときは Calendar を使います。 *3

// 操作対象の Date オブジェクト。
// 日本時間で 2016 年 2 月 29 日の 00:00:00。
Date d = new Date(145667160_0000L);

// Calendar オブジェクトを使って 1 年後を計算して Date オブジェクトを取得。
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("Asia/Tokyo"), Locale.JAPAN);
c.setTime(d);
c.add(Calendar.YEAR, 1); // 年に 1 加算。
Date dateOneYearAfter = c.getTime(); // 2017 年 2 月 28 日の 00:00:00 (日本時間)。

上の例では、タイムゾーンを Asia/Tokyo に設定しています。 タイムゾーンを適切に設定しないと、渡された Date オブジェクトが表す日付が変わる可能性がありますので、適切にタイムゾーンを設定しましょう。 ロケールも週の開始曜日などに影響するので必要に応じて設定しましょう。 (デフォルトタイムゾーン・デフォルトロケールが良い場合はもちろんデフォルトの値を使えば良いです。)

おわり

時刻を扱うときはタイムゾーンに気を付けなさい」 ということはみんな耳にタコができるぐらい言われてきたと思うので大丈夫だと思いますが、タイムゾーンをちゃんと設定するように気を付けましょう。

*1:ドキュメントにも 『The main reason you'd create an instance this class directly is because you need to format/parse a specific machine-readable format, in which case you almost certainly want to explicitly ask for “US” to ensure that you get ASCII digits (rather than, say, Arabic digits).』 って書かれてる。

*2:少なくとも API level 23 までは。 それより後のバージョンは不明。

*3:単純に 365 日間に相当するミリ秒を加算する、みたいな方法だとうるう年などが考慮できないのでだめですよね。 「1 ヶ月後」 とかだと何日分加算すればいいのかわかんないし。