wake-up-neo.com

Java SimpleDateFormat für Zeitzonen mit Doppelpunkt-Trennzeichen?

Ich habe ein Datum im folgenden Format: 2010-03-01T00:00:00-08:00

Ich habe die folgenden SimpleDateFormats darauf geworfen, um sie zu analysieren:

private static final SimpleDateFormat[] FORMATS = {
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"), //ISO8601 long RFC822 zone
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"), //ISO8601 long long form zone
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"), //ignore timezone
        new SimpleDateFormat("yyyyMMddHHmmssZ"), //ISO8601 short
        new SimpleDateFormat("yyyyMMddHHmm"),
        new SimpleDateFormat("yyyyMMdd"), //birthdate from NIST IHE C32 sample
        new SimpleDateFormat("yyyyMM"),
        new SimpleDateFormat("yyyy") //just the year
    };

Ich habe eine bequeme Methode, die diese Formate wie folgt verwendet:

public static Date figureOutTheDamnDate(String wtf) {
    if (wtf == null) {
        return null;
    }
    Date retval = null;
    for (SimpleDateFormat sdf : FORMATS) {
        try {
            sdf.setLenient(false)
            retval = sdf.parse(wtf);
            System.out.println("Date:" + wtf + " hit on pattern:" + sdf.toPattern());
            break;
        } catch (ParseException ex) {
            retval = null;
            continue;
        }
    }

    return retval;
}

Es scheint das Muster yyyyMMddHHmm zu treffen, gibt aber das Datum als Thu Dec 03 00:01:00 PST 2009 zurück.

Was ist das richtige Muster, um dieses Datum zu analysieren? 

UPDATE: Ich brauche keine Zeitzonenanalyse. Ich rechne nicht damit, zeitbezogene Probleme zwischen den Zonen zu verschieben, aber wie soll ich das Zonenformat "-08: 00" erhalten?

Gerätetest:

@Test
public void test_date_parser() {
    System.out.println("\ntest_date_parser");
    //month is zero based, are you effing kidding me
    Calendar d = new GregorianCalendar(2000, 3, 6, 13, 00, 00);
    assertEquals(d.getTime(), MyClass.figureOutTheDamnDate("200004061300"));
    assertEquals(new GregorianCalendar(1950, 0, 1).getTime(), MyClass.figureOutTheDamnDate("1950"));
    assertEquals(new GregorianCalendar(1997, 0, 1).getTime(),  MyClass.figureOutTheDamnDate("199701"));
    assertEquals(new GregorianCalendar(2010, 1, 25, 15, 19, 44).getTime(),   MyClass.figureOutTheDamnDate("20100225151944-0800"));

    //my machine happens to be in GMT-0800
    assertEquals(new GregorianCalendar(2010, 1, 15, 13, 15, 00).getTime(),MyClass.figureOutTheDamnDate("2010-02-15T13:15:00-05:00"));
    assertEquals(new GregorianCalendar(2010, 1, 15, 18, 15, 00).getTime(), MyClass.figureOutTheDamnDate("2010-02-15T18:15:00-05:00"));

    assertEquals(new GregorianCalendar(2010, 2, 1).getTime(), MyClass.figureOutTheDamnDate("2010-03-01T00:00:00-08:00"));
    assertEquals(new GregorianCalendar(2010, 2, 1, 17, 0, 0).getTime(), MyClass.figureOutTheDamnDate("2010-03-01T17:00:00-05:00"));
}

Ausgabe vom Komponententest:

test_date_parser
Date:200004061300 hit on pattern:yyyyMMddHHmm
Date:1950 hit on pattern:yyyy
Date:199701 hit on pattern:yyyyMM
Date:20100225151944-0800 hit on pattern:yyyyMMddHHmmssZ
Date:2010-02-15T13:15:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-02-15T18:15:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-03-01T00:00:00-08:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-03-01T17:00:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
58
Freiheit

JodaTime 's DateTimeFormat um zu retten:

String dateString = "2010-03-01T00:00:00-08:00";
String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";
DateTimeFormatter dtf = DateTimeFormat.forPattern(pattern);
DateTime dateTime = dtf.parseDateTime(dateString);
System.out.println(dateTime); // 2010-03-01T04:00:00.000-04:00

(Zeit- und Zeitzonenunterschied in toString() liegt nur daran, dass ich bei GMT-4 bin und das Gebietsschema nicht explizit gesetzt habe.)

Wenn Sie Java.util.Date beenden möchten, verwenden Sie einfach DateTime#toDate():

Date date = dateTime.toDate();

Warten auf JDK7 ( JSR-310 ) In JSR-310 heißt die Referenzimplementierung ThreeTen (hoffentlich wird es in Java 8 erstellt), wenn Sie einen besseren Formatierer in der Standard-Java SE-API wünschen. Die aktuelle Variable SimpleDateFormat frisst den Doppelpunkt in der Zeitzonen-Notation nicht.

Update: Laut Update benötigen Sie anscheinend keine Zeitzone. Dies sollte mit SimpleDateFormat funktionieren. Lassen Sie es (die Z) im Muster einfach weg.

String dateString = "2010-03-01T00:00:00-08:00";
String pattern = "yyyy-MM-dd'T'HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
Date date = sdf.parse(dateString);
System.out.println(date); // Mon Mar 01 00:00:00 BOT 2010

(was laut meiner Zeitzone korrekt ist)

56
BalusC

wenn Sie Java 7 verwendet haben, könnten Sie das folgende Datums-/Zeitmuster verwenden. Anscheinend wird dieses Muster in der früheren Java-Version nicht unterstützt.

String dateTimeString  = "2010-03-01T00:00:00-08:00";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
Date date = df.parse(dateTimeString);

Weitere Informationen finden Sie in der SimpleDateFormat-Dokumentation .

33
YouEyeK

Hier ist ein Ausschnitt, den ich verwendet habe - mit einfacher SimpleDateFormat. Hoffe, dass jemand anderes davon profitieren kann:

public static void main(String[] args) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") {
        public StringBuffer format(Date date, StringBuffer toAppendTo, Java.text.FieldPosition pos) {
            StringBuffer toFix = super.format(date, toAppendTo, pos);
            return toFix.insert(toFix.length()-2, ':');
        };
    };
    // Usage:
    System.out.println(dateFormat.format(new Date()));
}

Ausgabe:

- Usual Output.........: 2013-06-14T10:54:07-0200
- This snippet's Output: 2013-06-14T10:54:07-02:00
29
acdcjunior

Versuchen Sie es mit seiner Arbeit für mich:

Date date = javax.xml.bind.DatatypeConverter.parseDateTime("2013-06-01T12:45:01+04:00").getTime();

In Java 8:

OffsetDateTime dt = OffsetDateTime.parse("2010-03-01T00:00:00-08:00");
13
Rustam

Wenn Sie JDK 1.7 oder höher verwenden können, versuchen Sie Folgendes:

public class DateUtil {
    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");

    public static String format(Date date) {
        return dateFormat.format(date);
    }

    public static Date parse(String dateString) throws AquariusException {
        try {
            return dateFormat.parse(dateString);
        } catch (ParseException e) {
            throw new AquariusException(e);
        }
    }
}

document: https://docs.Oracle.com/javase/7/docs/api/Java/text/SimpleDateFormat.html unterstützt ein neues Zeitzonenformat "XXX" (z )

Während JDK 1.6 nur andere Formate für die Zeitzone unterstützt, die "z" (z. B. NZST) sind, "zzzz" (z. B. Neuseeland Standardzeit), "Z" (z. B. +1200) usw.

9
Willie Z

tl; dr

OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" )

Einzelheiten

Das Antwort von BalusC ist korrekt, aber jetzt veraltet ab Java 8.

Java.time

Das Java.time Framework ist der Nachfolger sowohl der Joda-Time-Bibliothek als auch der alten problematischen Datums-/Zeitklassen, die mit den frühesten Versionen von Java (Java.util) gebündelt sind. Date/.Calendar & Java.text.SimpleDateFormat).

ISO 8601

Ihr eingegebener Datenstring entspricht zufällig dem ISO 8601 Standard.

Die Java.time-Klassen verwenden standardmäßig ISO 8601-Formate, wenn sie Textdarstellungen von Datums-/Zeitwerten analysieren/generieren. Es muss also kein Formatierungsmuster definiert werden.

OffsetDateTime

Die OffsetDateTime -Klasse repräsentiert einen Moment auf der Zeitlinie, der an ein bestimmtes Offset-von-UTC angepasst ist. In Ihrer Eingabe liegt der Versatz 8 Stunden hinter UTC, was häufig an der Westküste Nordamerikas verwendet wird.

OffsetDateTime odt = OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" );

Sie möchten anscheinend nur das Datum. Verwenden Sie in diesem Fall die Klasse LocalDate . Denken Sie jedoch daran, dass Sie Daten, (a) die Uhrzeit und (b) die Zeitzone verwerfen. In Wirklichkeit hat ein Datum ohne den Kontext einer Zeitzone keine Bedeutung. Für jeden Moment variiert das Datum auf der ganzen Welt. Zum Beispiel ist kurz nach Mitternacht in Paris immer noch „gestern“ in Montréal. Also, während ich vorschlage, bei Datums- und Zeitwerten zu bleiben, können Sie leicht in ein LocalDate konvertieren, wenn Sie darauf bestehen.

LocalDate localDate = odt.toLocalDate();

Zeitzone

Wenn Sie die beabsichtigte Zeitzone kennen, wenden Sie diese an. Eine Zeitzone ist ein Versatz plus die Regeln zur Behandlung von Anomalien wie Sommerzeit (DST) . Wenn Sie ein ZoneId anwenden, erhalten Sie ein ZonedDateTime -Objekt.

ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId );

Strings generieren

Rufen Sie toString auf, um eine Zeichenfolge im ISO 8601-Format zu generieren.

String output = odt.toString();

Wenn Sie Zeichenfolgen in anderen Formaten benötigen, durchsuchen Sie Stack Overflow nach dem Paket Java.util.format .

Umwandlung in Java.util.Date

Am besten vermeiden Java.util.Date , aber wenn Sie müssen, können Sie konvertieren. Rufen Sie die neuen Methoden auf, die den alten Klassen hinzugefügt wurden, z. B. Java.util.Date.from wo Sie ein Instant übergeben. Ein Instant ist ein Moment auf der Timeline in UTC . Wir können ein Instant aus unserem OffsetDateTime extrahieren.

Java.util.Date utilDate = Java.util.Date( odt.toInstant() );

About Java.time

Das Java.time Framework ist in Java 8 und höher. Diese Klassen ersetzen das lästige alte Legacy Datum-Zeit-Klassen wie Java.util.Date , Calendar , & SimpleDateFormat .

Das Joda-Time -Projekt, das sich jetzt im Wartungsmodus befindet, rät zur Migration in die Java.time -Klassen.

Weitere Informationen finden Sie im Oracle Tutorial . Durchsuchen Sie Stack Overflow nach vielen Beispielen und Erklärungen. Spezifikation ist JSR 31 .

Sie können Java.time Objekte direkt mit Ihrer Datenbank austauschen. Verwenden Sie einen JDBC-Treiber , der JDBC 4.2 oder höher entspricht. Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für Java.sql.* Klassen.

Woher bekommen Sie die Java.time-Klassen?

Das Projekt ThreeTen-Extra erweitert Java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von Java.time. Hier finden Sie möglicherweise einige nützliche Klassen wie Interval , YearWeek , YearQuarter und mehr .

7
Basil Bourque

Vielen Dank acdcjunior für Ihre Lösung. Hier ist eine etwas optimierte Version für Formatierung und Analyse :

public static final SimpleDateFormat XML_SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.FRANCE)
{
    private static final long serialVersionUID = -8275126788734707527L;

    public StringBuffer format(Date date, StringBuffer toAppendTo, Java.text.FieldPosition pos)
    {            
        final StringBuffer buf = super.format(date, toAppendTo, pos);
        buf.insert(buf.length() - 2, ':');
        return buf;
    };

    public Date parse(String source) throws Java.text.ParseException {
        final int split = source.length() - 2;
        return super.parse(source.substring(0, split - 1) + source.substring(split)); // replace ":" du TimeZone
    };
};
4
Bludwarf

Sie können X in Java 7 verwenden.

https://docs.Oracle.com/javase/7/docs/api/Java/text/SimpleDateFormat.html

static final SimpleDateFormat DATE_TIME_FORMAT = 
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

static final SimpleDateFormat JSON_DATE_TIME_FORMAT = 
        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");

private String stringDate = "2016-12-01 22:05:30";
private String requiredDate = "2016-12-01T22:05:30+03:00";

@Test
public void parseDateToBinBankFormat() throws ParseException {
    Date date = DATE_TIME_FORMAT.parse(stringDate);
    String jsonDate = JSON_DATE_TIME_FORMAT.format(date);

    System.out.println(jsonDate);
    Assert.assertEquals(jsonDate, requiredDate);
}
2
bigspawn

Versuchen Sie es mit setLenient(false)

Nachtrag: Es sieht so aus, als würden Sie verschieden formatierte Date-Zeichenfolgen erkennen. Wenn Sie einen Eintrag machen müssen, möchten Sie vielleicht dieses Beispiel betrachten, das InputVerifier erweitert.

1
trashgod

Da hier ein Beispiel für Apache FastDateFormat fehlt (klicken Sie hier für die Dokumentationen der Versionen: 2.6 und 3.5 ), füge ich eine für diejenigen hinzu, die es benötigen. Der Schlüssel hier ist das Muster ZZ (2 Hauptstadt Zs).

import Java.text.ParseException
import Java.util.Date;
import org.Apache.commons.lang3.time.FastDateFormat;
public class DateFormatTest throws ParseException {
    public static void main(String[] args) {
        String stringDateFormat = "yyyy-MM-dd'T'HH:mm:ssZZ";
        FastDateFormat fastDateFormat = FastDateFormat.getInstance(stringDateFormat);
        System.out.println("Date formatted into String:");
        System.out.println(fastDateFormat.format(new Date()));
        String stringFormattedDate = "2016-11-22T14:30:14+05:30";
        System.out.println("String parsed into Date:");
        System.out.println(fastDateFormat.parse(stringFormattedDate));
    }
}

Hier ist die Ausgabe des Codes:

Date formatted into String:
2016-11-22T14:52:17+05:30
String parsed into Date:
Tue Nov 22 14:30:14 IST 2016

Hinweis: Der obige Code ist von Apache Commons 'lang3. Die Klasse org.Apache.commons.lang.time.FastDateFormat unterstützt keine Analyse und unterstützt nur die Formatierung. Beispielsweise die Ausgabe des folgenden Codes:

import Java.text.ParseException;
import Java.util.Date;
import org.Apache.commons.lang.time.FastDateFormat;
public class DateFormatTest {
    public static void main(String[] args) throws ParseException {
        String stringDateFormat = "yyyy-MM-dd'T'HH:mm:ssZZ";
        FastDateFormat fastDateFormat = FastDateFormat.getInstance(stringDateFormat);
        System.out.println("Date formatted into String:");
        System.out.println(fastDateFormat.format(new Date()));
        String stringFormattedDate = "2016-11-22T14:30:14+05:30";
        System.out.println("String parsed into Date:");
        System.out.println(fastDateFormat.parseObject(stringFormattedDate));
    }
}

wird das sein:

Date formatted into String:
2016-11-22T14:55:56+05:30
String parsed into Date:
Exception in thread "main" Java.text.ParseException: Format.parseObject(String) failed
    at Java.text.Format.parseObject(Format.Java:228)
    at DateFormatTest.main(DateFormatTest.Java:12)
1
Abhishek Oza

Wenn die Datumszeichenfolge wie 2018-07-20T12: 18: 29.802Z .__ 

SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
0
HimalayanCoder