タイムゾーン調整の有無にかかわらず、日付文字列を読み込んでいます:yyyyMMddHHmmsszまたはyyyyMMddHHmmss。文字列にゾーンがない場合は、GMTとして扱います。でオプションのセクションを作成する方法SimpleDateFormatがわかりませんが、何かが足りない可能性があります。でこれを行う方法はありますSimpleDateFormatか、それともこれを処理するために新しいコンクリートを書く必要がありDateFormatますか?
7 に答える
JSR-310はJava8とともに提供されており、コンポーネントがオプションになっている場合に時間値を解析するための拡張サポートを提供します。ゾーンをオプションにするだけでなく、時間コンポーネントをオプションにして、指定された文字列の正しい時間単位を返すこともできます。
次のテストケースを検討してください。
public class DateFormatTest {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"yyyy-MM-dd[[ ]['T']HH:mm[:ss][XXX]]");
private TemporalAccessor parse(String v) {
return formatter.parseBest(v,
ZonedDateTime::from,
LocalDateTime::from,
LocalDate::from);
}
@Test public void testDateTime1() {
assertEquals(LocalDateTime.of(2014, 9, 23, 14, 20, 59),
parse("2014-09-23T14:20:59"));
}
@Test public void testDateTime2() {
assertEquals(LocalDateTime.of(2014, 9, 23, 14, 20),
parse("2014-09-23 14:20"));
}
@Test public void testDateOnly() {
assertEquals(LocalDate.of(2014, 9, 23), parse("2014-09-23"));
}
@Test public void testZonedDateTime() {
assertEquals(ZonedDateTime.of(2014, 9, 23, 14, 20, 59, 0,
ZoneOffset.ofHoursMinutes(10, 30)),
parse("2014-09-23T14:20:59+10:30"));
}
}
ここで、のDateTimeFormatterパターンは、"yyyy-MM-dd[[ ]['T']HH:mm[:ss][XXX]]"入れ子にすることもできる角括弧内のオプションを許可します。パターンは、 DateTimeFormatterBuilderから構築することもできます。これは、上記のパターンがここに示されています。
private final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.optionalStart()
.optionalStart()
.appendLiteral(' ')
.optionalEnd()
.optionalStart()
.appendLiteral('T')
.optionalEnd()
.appendOptional(DateTimeFormatter.ISO_TIME)
.toFormatter();
これは、次のような式に変換されます。
yyyy-MM-dd[[' ']['T']HH:mm[':'ss[.SSS]]].
オプションの値はネストでき、開いたままの場合は最後に自動的に閉じられます。ただし、オプションの部分に排他的論理和を提供する方法はないため、上記の形式では実際には次の値が非常に細かく解析されることに注意してください。
2018-03-08 T11:12
既存のフォーマッターを現在のフォーマットの一部として再利用できる非常に優れた機能に注意してください。
私はこれが古い投稿であることを知っていますが、記録のためだけに...
ApacheDateUtilsクラスはそれを支援します。
String[] acceptedFormats = {"dd/MM/yyyy","dd/MM/yyyy HH:mm","dd/MM/yyyy HH:mm:ss"};
Date date1 = DateUtils.parseDate("12/07/2012", acceptedFormats);
Date date2 = DateUtils.parseDate("12/07/2012 23:59:59", acceptedFormats);
MavenリポジトリーのApacheCommonsLangライブラリーへのリンク。最新バージョンを確認することをお勧めします:http:
//mvnrepository.com/artifact/org.apache.commons/commons-lang3
Maven v3.4
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
Gradle v3.4
'org.apache.commons:commons-lang3:3.4'
2つのSimpleDateFormatを作成します。1つはタイムゾーンあり、もう1つはタイムゾーンなしです。文字列の長さを調べて、使用する文字列を決定できます。
2つの異なるSDFに委任するDateFormatが必要なようです。
DateFormat df = new DateFormat() {
static final String FORMAT1 = "yyyyMMddHHmmss";
static final String FORMAT2 = "yyyyMMddHHmmssz";
final SimpleDateFormat sdf1 = new SimpleDateFormat(FORMAT1);
final SimpleDateFormat sdf2 = new SimpleDateFormat(FORMAT2);
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
throw new UnsupportedOperationException();
}
@Override
public Date parse(String source, ParsePosition pos) {
if (source.length() - pos.getIndex() == FORMAT1.length())
return sdf1.parse(source, pos);
return sdf2.parse(source, pos);
}
};
System.out.println(df.parse("20110102030405"));
System.out.println(df.parse("20110102030405PST"));
Joda Datetimeを使用できる場合は、「yyyy-MM-dd [hh:mm:ss]」などのフォーマッターのオプション部分をサポートします。
private DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.append(DateTimeFormat.forPattern("yyyy-MM-dd"))
.appendOptional(
new DateTimeFormatterBuilder()
.appendLiteral(' ')
.append(DateTimeFormat.forPattern("HH:mm:ss"))
.toParser()
.toFormatter();
最初に成功した解析でループを解除DateFormatする操作を使用して、潜在的なオブジェクトのリストをループします。try-catch
あなたは2つの異なるSimpleDateFormatsのように作成することができます
public PWMDateTimeFormatter(String aPatternStr)
{
_formatter = DateTimeFormat.forPattern(aPatternStr);
}
public PWMDateTimeFormatter(String aPatternStr, TimeZone aZone)
{
_formatter = DateTimeFormat.forPattern(aPatternStr).withZone(XXDateTime._getTimeZone(aZone));
}
SimpleDateFormatを拡張することで、同様の問題を少し前に解決しました。以下に、私のソリューションのアイデアを示すための大まかな実装を示します。完全ではない/最適化されていない可能性があります。
public class MySimpleDateFormat extends SimpleDateFormat {
private static final long serialVersionUID = 1L;
private static String FORMAT = "
private static int FORMAT_LEN = "yyyyMMddHHmmss".length();
private static String TZ_ID = "GMT";
public MySimpleDateFormat() {
this(TimeZone.getTimeZone(TZ_ID));
}
public MySimpleDateFormat(TimeZone tz) {
super(FORMAT);
setTimeZone(tz);
}
@Override
public Date parse(String source, ParsePosition pos) {
// TODO: args validation
int offset = pos.getIndex() + FORMAT_LEN;
Date result;
if (offset < source.length()) {
// there maybe is a timezone
result = super.parse(source, pos);
if (result != null) {
return result;
}
if (pos.getErrorIndex() >= offset) {
// there isn't a TZ after all
String part0 = source.substring(0, offset);
String part1 = source.substring(offset);
ParsePosition anotherPos = new ParsePosition(pos.getIndex());
result = super.parse(part0 + TZ_ID + part1, anotherPos);
if(result == null) {
pos.setErrorIndex(anotherPos.getErrorIndex());
} else {
// check SimpleDateFormat#parse javadoc to implement correctly the pos updates
pos.setErrorIndex(-1);
pos.setIndex(offset);
}
return result;
}
// there's something wrong with the first FORMAT_LEN chars
return null;
}
result = super.parse(source + TZ_ID, pos);
if(result != null) {
pos.setIndex(pos.getIndex() - TZ_ID.length());
}
return result;
}
public static void main(String [] args) {
ParsePosition pos = new ParsePosition(0);
MySimpleDateFormat mySdf = new MySimpleDateFormat();
System.out.println(mySdf.parse("20120622131415", pos) + " -- " + pos);
pos = new ParsePosition(0);
System.out.println(mySdf.parse("20120622131415GMT", pos) + " -- " + pos);
pos = new ParsePosition(0);
System.out.println(mySdf.parse("20120622131415xxx", pos) + " -- " + pos);
pos = new ParsePosition(0);
System.out.println(mySdf.parse("20120x22131415xxx", pos) + " -- " + pos);
}
}
要点は、入力文字列をチェックし、TZフィールドが欠落していることを何らかの形で「推測」し、欠落している場合はそれを追加しSimpleDateFormat#parse(String, ParsePosition)て、残りを実行する必要があるということです。上記の実装は、javadocのコントラクトに従ってParsePositionを更新していません。SimpleDateFormat#parse(String, ParsePosition)
許可される形式は1つだけなので、クラスには単一のデフォルトctorがあります。
メソッドMySimpleDateFormat#parse(String, ParsePosition)はによって呼び出されるSimpleDateFormat#parse(String)ため、両方のケースをカバーするだけで十分です。
main()を実行すると、これが出力になります(予想どおり)
Fri Jun 22 14:14:15 BST 2012 -- java.text.ParsePosition[index=14,errorIndex=-1]
Fri Jun 22 14:14:15 BST 2012 -- java.text.ParsePosition[index=17,errorIndex=-1]
Fri Jun 22 14:14:15 BST 2012 -- java.text.ParsePosition[index=14,errorIndex=-1]
null -- java.text.ParsePosition[index=0,errorIndex=5]