「ThreeTenABP」で捨てれないのか android.text.format.DateUtils

Androidで日付表記をお手軽に国際化する « LINE Engineers' Blog

読んでみると, なんかいろいろややこしそう.

イギリス式: Fri, 18 Nov 2016
アメリカ式: Fri, Nov 18, 2016

イギリス英語: Fri, 18 Nov 2016
アメリカ英語: Fri, Nov 18, 2016
日本語: 2016年11月18日(金)

イギリス英語: 18/11/2016
アメリカ英語: 11/18/2016
日本語: 2016/11/18

Android 6.0: 2016年11月18日(金)
Android 4.1: 2016/11/18 (金)

Android 6.0: 2016年11月18日金曜日
Android 4.1: 2016年11月18日 (金)

日本語: 3 日前
英語: 3 days ago
フランス語: Il y a 3 jours

日本語: 11月18日
英語: on Nov 18
フランス語: le 18 nov.

挙動にぶれがあります(エミュレータにて動作確認)。小さいTextViewに表示する際にはOS versionによって見切れてしまっていないかなどの検証をしましょう。

OS version間での挙動差分や、ビジネス上アプリで必要な言語をAPIが対応してくれるかの検証は必要

Android 7.0でのICU4Jの導入と共に下記クラスがICU4JでのDateUtilsに対応するクラスとして案内されています。

うーむ...「日付表示」て, 書いときゃ世界のどこでもまあまあいけるやつはねえのかなあ, と.

ThreeTenABP で DateTimeFormatter を使う

「ThreeTenABP」て何なのかは, 作者であるぼくらの Jake Wharton神 の書いていることを読めば分かります.

JakeWharton/ThreeTenABP: An adaptation of the JSR-310 backport for Android.

なぜ JSR-310 なのか?

JSR-310 は, java.time.* パッケージとして Java8 に含まれています. これは, Java と Android の両方で Date/Calendar API群をすべて置き換えるものです.
Java6 の開発者であるStepahen Colebourne によって調整され, それにバックポートされました.

なぜ ThreeTenBP を使わないのか?

Android 上で Joda-Time を使う問題のように ThreeTenBP はタイムゾーン情報の読込みにjar リソースを利用しています. これが Android 上では非常に非効率です.
このライブラリでは, タイムゾーン情報を Android標準で使えるようして, 効率的にパースできるローダーを提供しています.

なぜ Joda-Time を使わないのか?

Joda-Time は非常に大きいバイナリサイズと多くのメソッド数をもつ非常に大きいAPIです. また, JSR-310 と Joda-Time の作者は「壊れてはいないが, 設計に欠陥がある」と言っています.
すでに Joda-Time を使っているなら, サイズとメソッド数を除けば, 置き換える理由はほとんどありません. 新しいプロジェクトのために, このライブラリはバイナリサイズとメソッド数だけでなくAPIの数をかなり削減したJava8の標準APIの形 で提供しています.

Joda Time's Memory Issue in Android

Date/Calendar API + JodaTime の機能をJava8 で合成した java.time.* (JSR-310) を 現Android開発向けに適正化し利用できるようにしたものが「TheeTenABP」ということになります.

コードの記述は Java8 の記述と同じなので Java8 Date and Time APIドキュメントや記事が参考にできます.

続・今日から始めるJava8 - JSR-310 Date and Time API - Taste of Tech Topics

13 章 : Date and Time API · Java Study

Java 8 の DateTimeFormatter の曜日等のフォーマットについて - tokuhirom's blog

Javaで日時を扱う(Java8) - Qiita

同梱されている国際化可能そうな日時フォーマットを試してみる.

...
DateTimeFormatter formatter =
    DateTimeFormatter
        .ofLocalizedDateTime(formatStyle, formatStyle)
        .withLocale(Locale.getDefault());
Timber.d(zonedDateTime.format(formatter) + " : " + formatStyle.name());
...

日付と時刻, それぞれ FormatStyle.SHORTからFULLまでの4種類ある.


2016年12月14日水曜日 10時13分36秒 日本標準時 : FULL
2016年12月14日 10:13:36 JST : LONG
2016/12/14 10:13:36 : MEDIUM
2016/12/14 10:13 : SHORT

Wednesday, 14 December 2016 01:13:36 Greenwich Mean Time : FULL
14 December 2016 01:13:36 GMT+00:00 : LONG
14 Dec 2016 01:13:36 : MEDIUM
14/12/2016 01:13 : SHORT

Tuesday, December 13, 2016 8:13:36 PM Eastern Standard Time : FULL
December 13, 2016 8:13:36 PM EST : LONG
Dec 13, 2016 20:13:36 : MEDIUM
12/13/16 20:13 : SHORT

2016年12月14日星期三 香港標準時間上午9時13分36秒 : FULL
2016年12月14日 GMT+08:00上午9時13分36秒 : LONG
2016年12月14日 09:13:36 : MEDIUM
2016/12/14 09:13 : SHORT

2016년 12월 14일 수요일 오전 10시 13분 36초 대한민국 표준시 : FULL
2016년 12월 14일 오전 10시 13분 36초 GMT+09:00 : LONG
2016. 12. 14. 10시 13분 36초 : MEDIUM
16. 12. 14. 10:13 : SHORT

なんか微妙...

FormatStyle.MEDIUM くらいが良さげだが, 曜日が含まれてないし.

別個, 曜日の文字列としては別に


localDateTime.getDayOfWeek()
    .getDisplayName(TextStyle.FULL, Locale.getDefault());

のようにして文字列として取れるっちゃあとれるが並び順やセパレータの件がある.

カスタムで言語別にフォーマットつくるのもなあ.

まとめ

android.text.format.DateUtils で.


DateUtils.formatDateTime(
       context,
       timestamp, 
       FORMAT_SHOW_YEAR | FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_ABBREV_ALL);


2016年12月14日(水) 10:13
Wed, 14 Dec 2016 00:13
Tue, Dec 13, 2016, 20:13
2016年12月14日週三 09:13
2016년 12월 14일 (수) 10:13

結局, これが簡単で自然,

表示言語やタイムゾーンの設定は context から取得してくれるし.

モバイル画面上の表示としてその他海外で自然かどうかは実際知らんけども.

日時を多言語化するというのは思ったより複雑.

モバイル端末というのは, いろいろな制限の中で動いているのだなあと実感.

Date/Calendar のことはもう忘れていいのだよな?

(つづく)


日本語設定では見ることができない本当のAndroidバージョン別のシェア率

Android のバージョン別の利用割合をみるとき,

みますよね, ここ.

ダッシュボード | Android Developers

%e3%82%bf%e3%82%99%e3%83%83%e3%82%b7%e3%83%a5%e3%83%9b%e3%82%99%e3%83%bc%e3%83%88%e3%82%99___android_developers

ところが, ここにアクセスすると,

Dashboards | Android Developers

dashboards___android_developers

当然数字も違いますよね.

URLを見てみると, 微妙に違ったりします.

../dashboards/index.html?hl=ja

../dashboards/index.html?hl=en

パラメータだけでなく, 他の何かも影響してる雰囲気.

../dashboards/index.html

画面の下にあるプルダウンから言語変えてみるのもいいみたいです.

%e3%82%bf%e3%82%99%e3%83%83%e3%82%b7%e3%83%a5%e3%83%9b%e3%82%99%e3%83%bc%e3%83%88%e3%82%99___android_developers

なんだか気持ち悪いので, スクリプトにしておきますね.

version_android

Android バージョンやコードネームなどからのシェアの一覧取得


Android バージョンやコードネームなどからのシェアの一覧取得

Android のバージョンを表す場合,

相手によって言い方を変えなければなりません.

「Android 4.4 はー」

「ロリポップってー」

「minSdk は 19 でー」

「Android M はー」

特に,

会議などでバージョン別のユーザの割合を話しているときには,

営業からプログラマまで言い方がバラバラでいきなり

「ジンジャーブレッドまではもう切り捨ててもいいんじゃね?」

といわれてもすぐにピンとこなかったりします.

いくつかオフィシャルに公開されている一般的な名称の一覧があります.

codenames__tags__and_build_numbers___android_open_source_project

Codenames, Tags, and Build Numbers | Android Open Source Project

%e3%82%bf%e3%82%99%e3%83%83%e3%82%b7%e3%83%a5%e3%83%9b%e3%82%99%e3%83%bc%e3%83%88%e3%82%99___android_developers

ダッシュボード | Android Developers

また, システムの内部的には, Build.VERSION_CODES とよばれる名称が, APIレベルという整数を表します.

build_version_codes___android_developers

Build.VERSION_CODES | Android Developers

android_os_%e3%83%8f%e3%82%99%e3%83%bc%e3%82%b7%e3%82%99%e3%83%a7%e3%83%b3%e3%81%ae%e3%82%b3%e3%83%bc%e3%83%88%e3%82%99%e3%83%8d%e3%83%bc%e3%83%a0%e3%82%92%e5%8f%96%e5%be%97%e3%81%99%e3%82%8b

Android OS バージョンのコードネームを取得する

いちいちめんどくさいのでスクリプトにしておきます.


#!/usr/local/bin/php
<?php
$versions = '
LV VERSION_CODE           VERSION       CODE_NAME 
 1 BASE                   1             (no code name)
 2 BASE_1_1               1.1           (no code name)
 3 CUPCAKE                1.5           Cupcake
 4 DONUT                  1.6           Donut
 5 ECLAIR                 2             Eclair
 6 ECLAIR_0_1             2.0.1         Eclair
 7 ECLAIR_MR1             2.1           Eclair
 8 FROYO                  2.2.x         Froyo
 9 GINGERBREAD            2.3 - 2.3.2   Gingerbread
10 GINGERBREAD_MR1        2.3.3 - 2.3.7 Gingerbread
11 HONEYCOMB              3             Honeycomb
12 HONEYCOMB_MR1          3.1           Honeycomb
13 HONEYCOMB_MR2          3.2.x         Honeycomb
14 ICE_CREAM_SANDWICH     4.0.1 - 4.0.2 Ice Cream Sandwich
15 ICE_CREAM_SANDWICH_MR1 4.0.3 - 4.0.4 Ice Cream Sandwich
16 JELLY_BEAN             4.1.x         Jelly Bean
17 JELLY_BEAN_MR1         4.2.x         Jelly Bean
18 JELLY_BEAN_MR2         4.3.x         Jelly Bean
19 KITKAT                 4.4 - 4.4.4   KitKat
20 KITKAT_WATCH           4.4W          KitKat Watch
21 LOLLIPOP               5             Lollipop
22 LOLLIPOP_MR1           5.1           Lollipop
23 M                      6             Marshmallow
24 N                      7             Nougat
25 N_MR1                  7.1           Nougat
';

$url = 'https://developer.android.com/about/dashboards/index.html';
$versions = explode("\n", trim($versions));

$html  = file_get_contents($url);
preg_match_all('/var VERSION_DATA =(.*?)var VERSION_NAMES =/si',
               $html, $matches);
$json = json_decode(trim($matches[1][0], " \t\n\r\0\x0B[];"), true);

$sum = 100;
foreach ($json['data'] as $data) {
    printf("%5s %5s %s\n", 
           $data['perc'], sprintf('%03.1f', $sum), $versions[$data['api']]);
    $sum -= $data['perc'];
}

ユーザのシェアの数字は月一で更新される公式ページから実行時に取得します.

左から,

「ユーザ割合」
「そのバージョンをminSdkにしたときのカバー率」
「API レベル」
「バージョンコード」
「OSバージョン」
「コードネーム」

としています.


  0.1 100.0  8 FROYO                  2.2.x         Froyo
  1.3  99.9 10 GINGERBREAD_MR1        2.3.3 - 2.3.7 Gingerbread
  1.3  98.6 15 ICE_CREAM_SANDWICH_MR1 4.0.3 - 4.0.4 Ice Cream Sandwich
  4.9  97.3 16 JELLY_BEAN             4.1.x         Jelly Bean
  6.8  92.4 17 JELLY_BEAN_MR1         4.2.x         Jelly Bean
  2.0  85.6 18 JELLY_BEAN_MR2         4.3.x         Jelly Bean
 25.2  83.6 19 KITKAT                 4.4 - 4.4.4   KitKat
 11.3  58.4 21 LOLLIPOP               5             Lollipop
 22.8  47.1 22 LOLLIPOP_MR1           5.1           Lollipop
 24.0  24.3 23 M                      6             Marshmallow
  0.3   0.3 24 N                      7             Nougat

おおまかですが, すばやく一覧で確認できます.

Jelly Bean (Android 4.3) までを切り捨てた場合, minSdk=19 となり, 利用できるのは Android 4.4 以降の kitKat ユーザー で, 全体の 83.6% 程度なのかっ!