WebからService
フェッチ日付文字列を持っているので、それをDate
オブジェクトと比較したい。しかし、どういうわけかアプリケーションがクラッシュします。これは、解析している文字列です:2015-02-05T05:20:02+00:00
onStartCommand()
String datetime = "2015-02-05T05:20:02+00:00";
Date new_date = stringToDate(datetime);
stringToDate()
private Date stringToDate(String s){
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
try{
return df.parse(s);
}catch(ParseException e){
e.printStackTrace();
}
return null;
}
LogCat:
02-06 20:37:02.008: E/AndroidRuntime(28565): FATAL EXCEPTION: main
02-06 20:37:02.008: E/AndroidRuntime(28565): Process: com.dotmav.runescapenotifier, PID: 28565
02-06 20:37:02.008: E/AndroidRuntime(28565): Java.lang.RuntimeException: Unable to start service com.dotmav.runescapenotifier.GEService@384655b5 with Intent { cmp=com.dotmav.runescapenotifier/.GEService }: Java.lang.IllegalArgumentException: Unknown pattern character 'X'
02-06 20:37:02.008: E/AndroidRuntime(28565): at Android.app.ActivityThread.handleServiceArgs(ActivityThread.Java:2881)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Android.app.ActivityThread.access$2100(ActivityThread.Java:144)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1376)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Android.os.Handler.dispatchMessage(Handler.Java:102)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Android.os.Looper.loop(Looper.Java:135)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Android.app.ActivityThread.main(ActivityThread.Java:5221)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Java.lang.reflect.Method.invoke(Native Method)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Java.lang.reflect.Method.invoke(Method.Java:372)
02-06 20:37:02.008: E/AndroidRuntime(28565): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:899)
02-06 20:37:02.008: E/AndroidRuntime(28565): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:694)
02-06 20:37:02.008: E/AndroidRuntime(28565): Caused by: Java.lang.IllegalArgumentException: Unknown pattern character 'X'
02-06 20:37:02.008: E/AndroidRuntime(28565): at Java.text.SimpleDateFormat.validatePatternCharacter(SimpleDateFormat.Java:314)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Java.text.SimpleDateFormat.validatePattern(SimpleDateFormat.Java:303)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Java.text.SimpleDateFormat.<init>(SimpleDateFormat.Java:356)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Java.text.SimpleDateFormat.<init>(SimpleDateFormat.Java:249)
02-06 20:37:02.008: E/AndroidRuntime(28565): at com.dotmav.runescapenotifier.GEService.stringToDate(GEService.Java:68)
02-06 20:37:02.008: E/AndroidRuntime(28565): at com.dotmav.runescapenotifier.GEService.onStartCommand(GEService.Java:44)
02-06 20:37:02.008: E/AndroidRuntime(28565): at Android.app.ActivityThread.handleServiceArgs(ActivityThread.Java:2864)
02-06 20:37:02.008: E/AndroidRuntime(28565): ... 9 more
編集: onDestroy()定期的な更新のアラームを設定...
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + (1000 * 60),
PendingIntent.getService(this, 0, new Intent(this, GEService.class), 0)
);
から「XXX」を削除
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
すべてが正常に機能します。
SimpleDateFormat
コンストラクター内で使用できるシンボルのリストを確認します。これは ドキュメント です
おそらくあなたは"yyyy-MM-dd'T'HH:mm:ss.SSSZ"
を探しています
コードを
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
または
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); // if timezone is required
AndroidバージョンのSimpleDateFormat
はX
パターンをサポートしていないため、XXX
は機能しませんが、代わりにZZZZZ
は同じことを行い、+02:00
(またはローカルタイムゾーンに応じて-02:00
)の形式でタイムゾーンを出力します。
間違った日付フォーマッターを使用しています。
代わりにこれを使用してください:DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Androidとは対照的に、Java 7はXではなくタイムゾーンにZ(Java 6)のように)を使用します。したがって、日付形式には this を使用します。
pre-nougatデバイスで発生するこのエラーについては誰も言及していませんそれの。
この answer は、「X」がNougat +デバイスでのみサポートされていることを正しく述べています。 documentation が"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
を使用することを示唆していることと、なぜこの点を明確にしないのかがわかりません。
私にとって、yyyy-MM-dd'T'HH:mm:ssXXX
は6.0デバイスでテストしようとするまで正常に動作し、クラッシュし始めたため、このトピックの研究につながりました。これをyyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ
に置き換えると、問題が解決し、すべての5.0以降のデバイスで機能します。
ZとXXXは異なるため、次の回避策を実装しました。
// This is a workaround from Z to XXX timezone format
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") {
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {
StringBuffer rfcFormat = super.format(date, toAppendTo, pos);
return rfcFormat.insert(rfcFormat.length() - 2, ":");
}
@Override
public Date parse(String text, ParsePosition pos) {
if (text.length() > 3) {
text = text.substring(0, text.length() - 3) + text.substring(text.length() - 2);
}
return super.parse(text, pos);
}
}
Android SimpleDateFormat はJava 7 SDKとは異なり、ISO 8601を解析するための 'X'をサポートしていません。'Z 'または' ZZZZZ 'スタイルを使用してフォーマットできますタイムゾーンをUTCにプログラムで設定します。utilクラスは次のとおりです。
public class DateUtil {
public static final String iso8601DatePattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ";
public static final DateFormat iso8601DateFormat = new SimpleDateFormat(iso8601DatePattern);
public static final TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");
static {
iso8601DateFormat.setTimeZone(utcTimeZone);
}
public static String formatAsIso8601(Date date) {
return iso8601DateFormat.format(date);
}
}
エラーは、simpleDateFormatが文字Xを認識しないと言っています。ミリ秒を探している場合は、文字Sで表されます。
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
long millisecondsSinceEpoch = OffsetDateTime.parse( "2015-02-05T05:20:02+00:00" ).plusHour( 1 ).toInstant().toEpochMilli() // Warning: Possible loss of data in truncating nanoseconds to milliseconds. But not in this particular case.
他の答えは正しいですが、今では時代遅れです。古い日時クラスはレガシーになりました。代わりにJava.timeクラスを使用してください。
入力文字列は標準ISO 8601形式です。 Java.timeクラスはデフォルトでISO 8601形式を使用するため、直接解析し、フォーマットパターンを定義する必要はありません。
OffsetDateTime
入力には+00:00
を持つoffset-from-UTCが含まれているため、 OffsetDateTime
オブジェクトとして解析できます。
String input = "2015-02-05T05:20:02+00:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input );
1時間または1分後にアラームを設定する場合は、plus
メソッドを呼び出します。
OffsetDateTime minuteLater = odt.plusMinutes( 1 );
OffsetDateTime hourLater = odt.plusHours( 1 );
ミリ秒のカウントを取得するには、Instant
クラスを調べます。 Instant
クラスは、 [〜#〜] utc [〜#〜] のタイムライン上の瞬間を表します nanoseconds の解像度で。ミリ秒を求めるということは、10進数の9桁が3桁の小数点に切り捨てられるため、データ損失の可能性を意味します。
long millisecondsSinceEpoch = odt.toInstant().toEpochMilli(); // Warning: Possible loss of data in truncating nanoseconds to milliseconds.
Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、Java.util.Date
、.Calendar
、 &Java.text.SimpleDateFormat
。
Joda-Time プロジェクトは、現在 メンテナンスモード であり、Java.timeへの移行を推奨しています。
詳細については、 Oracleチュートリアル を参照してください。また、Stack Overflowで多くの例と説明を検索してください。
Java.time機能の多くは、 ThreeTen-Backport のJava 6&7にバックポートされ、さらに Android in ThreeTenABP 。
ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。
SimpleDateFormat
を使用して、適切にフォーマットされたString
出力を生成します。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String formattedNow = simpleDateFormat.format(new Date(System.currentTimeMillis()));
出力:2018-02-27T07:36:47.686Z
簡単なソリューション:
使用 this yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ
代わりに of yyyy-MM-dd'T'HH:mm:ss.SSSXXX
できた.
次のクラスを使用して、パターンが認識しないときに文字列を日付に変換できます。
import Java.text.SimpleDateFormat;
import Java.util.Arrays;
import Java.util.Date;
import Java.util.List;
/**
* StringToDateFormater is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for
* formatting (date → text), parsing (text → date), and normalization.
*
* This class is mainly used for convert the date from string. It should be used only when date pattern doesn't aware of
* it.
*
*/
public class StringToDateFormater extends SimpleDateFormat {
private static final List<String> DATE_SUPPORTED_FORMAT_LIST = Arrays.asList("yyyyMMddHHmmss", "yyyyMMddHHmm",
"yyyyMMddHHmm", "yyyyMMddHH", "yyyyMMdd", "yyyyMMddHHmmssSS");
/**
*
*/
private static final long serialVersionUID = -1732857502488169225L;
/**
* @param pattern
*/
public StringToDateFormater() {
}
@Override
public Date parse(String source) {
Date date = null;
SimpleDateFormat dateFormat = null;
for (String format : DATE_SUPPORTED_FORMAT_LIST) {
dateFormat = new SimpleDateFormat(format);
try {
return dateFormat.parse(source);
} catch (Exception exception) {
}
}
return date;
}
}