Konwertuj ciąg na obiekt kalendarza w Javie

174

Jestem nowy w Javie, zwykle pracuję z PHP.

Próbuję przekonwertować ten ciąg:

Poniedziałek, 14 marca, 16:02:37 GMT 2011

Do obiektu kalendarza, dzięki czemu mogę łatwo pobrać rok i miesiąc w następujący sposób:

String yearAndMonth = cal.get(Calendar.YEAR)+cal.get(Calendar.MONTH);

Czy byłoby złym pomysłem przeanalizowanie go ręcznie? Używasz metody podciągów?

Każda rada pomoże, dzięki!

Doug Molineux
źródło

Odpowiedzi:

396
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
cal.setTime(sdf.parse("Mon Mar 14 16:02:37 GMT 2011"));// all done

Uwaga: ustaw Localezgodnie ze środowiskiem / wymaganiami


Zobacz też

Jigar Joshi
źródło
onlineconversion.com/unix_time.htm . To jest internetowy konwerter znaczników czasu. Wartość, która jest obliczana przez kod Java i ta konwersja online, różni się. Czemu?? Czy możesz przez to przejść. Dzięki :)
Sachin J
6
Pamiętaj, że powoduje to utratę informacji o strefie czasowej. Obiekt Calendar będzie miał domyślną strefę czasową systemu, a nie przeanalizowaną.
Cristian Vrabie,
Nie powinna to być już najlepsza / akceptowana odpowiedź. Ponieważ Java 8 jest już dostępna od ponad 4 lat, odpowiedź powinna zostać zaktualizowana, aby wspomnieć java.time. To pytanie / odpowiedź jest dość widoczne w Google.
Scolytus
18

tl; dr

Nowoczesne podejście wykorzystuje klasy java.time .

YearMonth.from(
    ZonedDateTime.parse( 
        "Mon Mar 14 16:02:37 GMT 2011" , 
        DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" )
     )
).toString()

2011-03

Unikaj starszych klas daty i godziny

Współczesnym sposobem są klasy java.time. Stare klasy data-czas, takie jak Calendar, okazały się źle zaprojektowane, zagmatwane i kłopotliwe.

Zdefiniuj niestandardowy program formatujący, aby dopasować dane wejściowe ciągu.

String input = "Mon Mar 14 16:02:37 GMT 2011";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" );

Analizuj jako plik ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.parse( input , f );

Interesuje Cię rok i miesiąc. W tym celu klasy java.time zawierają YearMonthklasy.

YearMonth ym = YearMonth.from( zdt );

W razie potrzeby możesz zapytać o numer roku i miesiąca.

int year = ym.getYear();
int month = ym.getMonthValue();

Ale toStringmetoda generuje ciąg w standardowym formacie ISO 8601 .

String output = ym.toString();

Połącz to wszystko razem.

String input = "Mon Mar 14 16:02:37 GMT 2011";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "E MMM d HH:mm:ss z uuuu" );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
YearMonth ym = YearMonth.from( zdt );
int year = ym.getYear();
int month = ym.getMonthValue();

Zrzuć na konsolę.

System.out.println( "input: " + input );
System.out.println( "zdt: " + zdt );
System.out.println( "ym: " + ym );

wejście: poniedziałek, 14 marca, 16:02:37 GMT 2011

zdt: 2011-03-14T16: 02: 37Z [GMT]

ym: 2011-03

Kod na żywo

Zobacz ten kod działający w IdeOne.com .

Konwersja

Jeśli musisz mieć Calendarobiekt, możesz przekonwertować go na a GregorianCalendarprzy użyciu nowych metod dodanych do starych klas.

GregorianCalendar gc = GregorianCalendar.from( zdt );

Informacje o java.time

Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do java.time.

Aby dowiedzieć się więcej, zobacz samouczek Oracle . Wyszukaj wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Skąd wziąć klasy java.time?

  • Java SE 8 i SE 9 i nowsze
    • Wbudowany.
    • Część standardowego interfejsu API języka Java z dołączoną implementacją.
    • Java 9 dodaje kilka drobnych funkcji i poprawek.
  • Java SE 6 i SE 7
  • Android

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .

Basil Bourque
źródło
14

Cóż, myślę, że byłoby złym pomysłem replikowanie kodu, który jest już obecny w klasach takich jak SimpleDateFormat.

Z drugiej strony, osobiście sugerowałbym unikanie Calendari Datecałkowicie, jeśli możesz, i używanie zamiast tego Joda Time , jako znacznie lepiej zaprojektowanego API daty i czasu. Na przykład musisz mieć świadomość, że nieSimpleDateFormat jest to bezpieczne dla wątków, więc za każdym razem potrzebujesz lokalnych ustawień wątku, synchronizacji lub nowego wystąpienia. Parsery i elementy formatujące Joda bezpieczne dla wątków.

Jon Skeet
źródło
Dzięki za wkład, na pewno przyjrzę się w przyszłości używaniu Jody, wygląda na to, że może być bardzo przydatny
Doug Molineux
@Jon Skeet Joda nie będzie deserializować w systemie Android. Joda jest mało warta, chyba że nie musisz oszczędzać daty i czasu.
Frank Zappa,
@FrankZappa: Nie zgadzam się z tym - możesz wykonać wszystkie obliczenia daty / czasu w Joda Time, ale potem przekonwertować je na inne typy (może tylko ciągi znaków dla uproszczenia) w celu serializacji.
Jon Skeet
Przepraszamy, musiałem głosować przeciw, odpowiedź jest zbyt stara, nieaktualna, aby była odpowiedzią o najwyższym rankingu. Dzisiaj java.timejest droga, Basil Bourque udzielił doskonałej odpowiedzi.
Scolytus
2
@Scolytus: Najlepsza (i zaakceptowana) odpowiedź ma 332 głosy w porównaniu z 10 na tę odpowiedź. Myślę, że jeśli kręcić downvoting co 7 + -letni odpowiedź, że ma lepsze rozwiązanie teraz będziesz zabraknie downvotes ... (zgadzam się, że odpowiedź Bazylego jest dobry, a ja upvoted że.)
Jon Skeet
10

Nie trzeba tworzyć nowego kalendarza, SimpleDateFormat używa już kalendarza pod spodem.

SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.EN_US);
Date date = sdf.parse("Mon Mar 14 16:02:37 GMT 2011"));// all done
Calendar cal = sdf.getCalendar();

(Jeszcze nie mogę komentować, dlatego utworzyłem nową odpowiedź)

GoGoris
źródło
1
Twoje rozwiązanie wygląda elegancko, ale ma dwie wady: 1. JavaDoc nie gwarantuje, że zachowanie jest zgodne z oczekiwaniami. 2. Przynajmniej dla Javy 6 w linii 1353 znajdziesz ścieżkę, w której klonowany jest obiekt kalendarza. W takim razie! Date.equals (cal.getTime ()).
niels
5

SimpleDateFormatjest świetny, pamiętaj tylko, że HHróżni się od hhpracy z godzinami. HHzwróci 24-godzinne godziny, a hh zwróci 12-godzinne godziny.

Na przykład poniższe zwróci 12-godzinny czas:

SimpleDateFormat sdf = new SimpleDateFormat("hh:mm aa");

Chociaż to zwróci 24-godzinny czas:

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
Philip
źródło
4

Przeanalizuj czas ze Zstrefą czasową, we wzorcu dotyczy strefy czasowej

String aTime = "2017-10-25T11:39:00+09:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
try {
    Calendar cal = Calendar.getInstance();
    cal.setTime(sdf.parse(aTime));
    Log.i(TAG, "time = " + cal.getTimeInMillis()); 
} catch (ParseException e) {
    e.printStackTrace();
}

Wyjście: zwraca czas UTC

1508899140000

wprowadź opis obrazu tutaj

Jeśli nie ustawimy strefy czasowej według wzoru yyyy-MM-dd'T'HH:mm:ss. SimpleDateFormatużyje ustawionej strefy czasowejSetting

Phan Van Linh
źródło
3

Tak, samodzielne analizowanie tego byłoby złą praktyką. Spójrz na SimpleDateFormat , zamieni ciąg znaków w datę i możesz ustawić datę w instancji kalendarza.

John Vint
źródło
1

Prosta metoda:

public Calendar stringToCalendar(String date, String pattern) throws ParseException {
    String DEFAULT_LOCALE_NAME = "pt";
    String DEFAULT_COUNTRY = "BR";
    Locale DEFAULT_LOCALE = new Locale(DEFAULT_LOCALE_NAME, DEFAULT_COUNTRY);
    SimpleDateFormat format = new SimpleDateFormat(pattern, LocaleUtils.DEFAULT_LOCALE);
    Date d = format.parse(date);
    Calendar c = getCalendar();
    c.setTime(d);
    return c;
}
Alberto Cerqueira
źródło