2008-09-17 8 views
8

Mam pole bazy danych zawierający datę surowego pole (przechowywane jako danych znakowych), takich jakNajlepszy sposób na wydobycie obiektu strefy czasowej z ciągu?

piątek, 26 września 2008 20:30 Eastern Daylight Time

mogę analizować Data tego jak łatwo z SimpleDateFormat

DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz"); 
Date scheduledDate = dbFormatter.parse(rawDate); 

Co chciałbym zrobić to wyodrębnić obiekt TimeZone z tego łańcucha. Domyślna strefa czasowa w JVM, w której działa ta aplikacja, to GMT, więc nie mogę użyć .getTimezoneOffset() z powyższej analizy (ponieważ zwróci ona domyślną strefę czasową).

Poza tokenizacją nieprzetworzonego łańcucha i znalezieniem początkowej pozycji łańcucha strefy czasowej (ponieważ wiem, że format zawsze będzie EEEE, MMMM dd, yyyy hh:mm aa zzzz) jest sposób użycia DateFormat/SimpleDateFormat/Date/Calendar API do wyodrębnienia obiektu strefy czasowej - który będzie miał ten sam Strefę Czasową co Ciąg, który osobno odłączyłem z DateFormat.parse()?

Jedną rzeczą, która mi o błędy Date vs Calendar w Java API jest Calendar ma zastąpić Date we wszystkich miejscach ... ale potem zdecydował, oh hej niech nadal korzystać Date JEST W DateFormat klas.

+0

czy masz rozwiązanie tego problemu? – Chin2

+0

Odnośnie ostatniego akapitu, klasy "Date" i "Kalendarz" to krwawy bałagan: źle zaprojektowane, mylące i kłopotliwe. Unikaj ich. Zamiast tego należy użyć klas [java.time] (http://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html). –

Odpowiedz

0

Cóż, jako częściowe rozwiązanie można użyć dopasowania RegEx, aby uzyskać strefę czasową, ponieważ zawsze będziesz miał ten sam tekst przed nim. Rano albo wieczorem.

Nie wiem wystarczająco dużo o strefach czasowych Java, aby uzyskać ostatnią część tego.

2

znalazłem, że:

 DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz"); 
     dbFormatter.setTimeZone(TimeZone.getTimeZone("America/Chicago")); 
     Date scheduledDate = dbFormatter.parse("Friday, September 26, 2008 8:30 PM Eastern Daylight Time"); 
     System.out.println(scheduledDate); 
     System.out.println(dbFormatter.format(scheduledDate)); 
     TimeZone tz = dbFormatter.getTimeZone(); 
     System.out.println(tz.getDisplayName()); 
     dbFormatter.setTimeZone(TimeZone.getTimeZone("America/Chicago")); 
     System.out.println(dbFormatter.format(scheduledDate)); 

wywołuje następujące:

Fri Sep 26 20:30:00 CDT 2008 
Friday, September 26, 2008 08:30 PM Eastern Standard Time 
Eastern Standard Time 
Friday, September 26, 2008 08:30 PM Central Daylight Time 

I rzeczywiście okazało się, że nieco zaskakujące. Ale myślę, że to pokazuje, że odpowiedzią na twoje pytanie jest po prostu wywołanie getTimeZone na formatatorze po tym, jak sparsujesz.

Edytuj: Powyższe zostało uruchomione z JDK 1.6 Sun's.

+0

Byłem również zaskoczony tym i natknąłem się na problemy z przesuwaniem strefy czasowej z powodu wcześniejszej utworzenia daty. – 18Rabbit

+0

Po prostu ciekawy - jaki jest wynik TimeZone.getDefault() na twoim komputerze? –

0

Główna różnica między datą a kalendarzem polega na tym, że data jest tylko obiektem wartości bez żadnych metod jego modyfikacji. Dlatego jest przeznaczony do przechowywania informacji o dacie/czasie gdzieś. Jeśli używasz obiektu kalendarza, możesz go zmodyfikować po ustawieniu go na trwały obiekt, który wykonuje pewną logikę biznesową z informacją o dacie/godzinie. Jest to bardzo niebezpieczne, ponieważ podmiot nie ma możliwości rozpoznania tej zmiany. Klasa Kalendarz jest przeznaczona do operacji w dniu/godzinie, takich jak dodawanie dni lub coś w tym stylu.

zabawy z Twojego przykład uzyskać następujące:

import java.text.DateFormat; 
import java.text.ParseException; 
import java.text.SimpleDateFormat; 

public class TimeZoneExtracter { 

    public static final void main(String[] args) throws ParseException { 
     DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz"); 
     System.out.println(dbFormatter.getTimeZone()); 
     dbFormatter.parse("Fr, September 26, 2008 8:30 PM Eastern Daylight Time"); 
     System.out.println(dbFormatter.getTimeZone()); 
    } 

} 

wyjściowa:

sun.util.calendar.ZoneInfo [id = "Europe/Berlin" ... słoneczny. util.calendar.ZoneInfo [id = "Africa/Addis_Ababa" ...

Czy jest to oczekiwany rezultat?

1

@Ed Thomas:

Próbowałem coś bardzo podobnego do przykładu i uzyskać bardzo różne wyniki:

String testString = "Friday, September 26, 2008 8:30 PM Pacific Standard Time"; 
DateFormat df = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz"); 

System.out.println("The default TimeZone is: " + TimeZone.getDefault().getDisplayName()); 

System.out.println("DateFormat timezone before parse: " + df.getTimeZone().getDisplayName()); 

Date date = df.parse(testString); 

System.out.println("Parsed [" + testString + "] to Date: " + date); 

System.out.println("DateFormat timezone after parse: " + df.getTimeZone().getDisplayName()); 

wyjściowa:

Domyślna strefa czasowa jest: Eastern Czas standardowy

Strefa czasowa DateFormat przed analizą: Eastern Standard Time

Parsed [piątek, 26 września 2008 20:30 Pacific Standard Time] to Date: Sat 27 września 2008 00:30:00 CEST

DateFormat stref czasowych po parse: Eastern Standard Time

Wydaje się, że DateFormat.getTimeZone() zwraca ten sam strefa czasowa przed i po parse() ... nawet jeśli wrzucam jednoznaczne setTimeZone() przed wywołaniem parse().

Patrząc na źródło dla DateFormat i SimpleDateFormat, wygląda na to, że getTimeZone() po prostu zwraca Strefę Czasową Podstawowego Kalendarza ..., która domyślnie jest ustawiona na Kalendarz domyślnego Locale/Strefy Czasowej, chyba że podasz konkretną, której chcesz użyć.

+0

Jaką używasz JVM? –

+0

Wersja Java "1.4.2_14" Środowisko wykonawcze Java (TM) 2, wersja standardowa (wersja 1.4.2_14-b05) Klient wirtualny Java HotSpot (TM) VM (wersja 1.4.2_14-b05, tryb mieszany) –

0

Ed ma rację. chcesz czas Streone w obiekcie DateFormat po przeanalizowaniu czasu.

String rawDate = "Friday, September 26, 2008 8:30 PM Eastern Daylight Time"; 
DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz"); 
Date scheduledDate = dbFormatter.parse(rawDate); 

System.out.println(rawDate); 
System.out.println(scheduledDate); 
System.out.println(dbFormatter.getTimeZone().getDisplayName()); 

produkuje

Friday, September 26, 2008 8:30 PM Eastern Daylight Time 
Fri Sep 26 20:30:00 CDT 2008 
Eastern Standard Time 
+2

Może chcesz przetestować z czymś innym niż "Eastern Daylight Time" w terminie String - dbFormatter.getTimeZone() właśnie zwraca domyślną strefę czasową. –

0

tl; dr

ZonedDateTime.parse( 
    "Friday, September 26, 2008 8:30 PM Eastern Daylight Time" , 
    DateTimeFormatter.ofPattern("EEEE, MMMM d, uuuu h:m a zzzz") 
).getZone() 

java.time

Nowoczesny sposób jest z klasami java.time. Pytanie i inne odpowiedzi wykorzystują kłopotliwe, stare, stare klasy czasu i czasu lub projekt Joda-Time, które są teraz wypierane przez klasy java.time.

Zdefiniuj obiekt DateTimeFormatter za pomocą wzoru formatowania dopasowanego do danych.

DateTimeFormatter f = DateTimeFormatter.ofPattern("EEEE, MMMM d, uuuu h:m a zzzz"); 

Przypisywanie Locale określić język ludzki dnia name-of-a nazwą miesiąca, jak również normy kulturowe dotyczące innych kwestii formatowania.

f = f.withLocale(Locale.US); 

Wreszcie zrobić parsowania dostać ZonedDateTime obiekt.

String input = "Friday, September 26, 2008 8:30 PM Eastern Daylight Time" ; 
ZonedDateTime zdt = ZonedDateTime.parse(input , f); 

zdt.toString(): 2008-09-26T20: 30-04: 00 [Ameryka/New_York]

Można prosić o strefie czasowej od ZonedDateTime reprezentowanym jako obiekt ZoneId. Następnie możesz przesłuchać numer ZoneId, jeśli potrzebujesz więcej informacji o strefie czasowej.

ZoneId z = zdt.getZone(); 

See for yourself in IdeOne.com.

ISO 8601

Unikać wymiany danych daty i czasu w tego rodzaju strasznym formacie. Nie zakładaj języka angielskiego, nie dodawaj do niego swoich danych, takich jak nazwa dnia, i nigdy nie używaj pseudo-stref czasowych, takich jak Eastern Daylight Time.

Dla stref czasowych: Określ proper time zone name w formacie continent/region, takich jak America/Montreal, Africa/Casablanca lub Pacific/Auckland. Nigdy nie używaj skrótu 3-4-literowego, takiego jak EST lub IST, ponieważ nie są one prawdziwymi strefami czasowymi, nie są ustandaryzowane, a nawet unikalne (!).

Do serializowania wartości daty i czasu do tekstu należy używać tylko formatów ISO 8601. Klasy java.time używają tych formatów domyślnie podczas analizowania/generowania ciągów znaków w celu przedstawienia ich wartości.


O java.time

Ramy java.time jest wbudowana w Java 8 i późniejszych. Klasy te zastępują kłopotliwe stare klasy z datami, takie jak java.util.Date, Calendar, & SimpleDateFormat.

Projekt Joda-Time, teraz w maintenance mode, zaleca migrację do java.time. Aby uzyskać więcej informacji, zobacz

. I wyszukaj Stack Overflow dla wielu przykładów i objaśnień. Specyfikacja to JSR 310.

Gdzie można uzyskać lekcje java.time?

  • Java SE 8 i SE 9 a później
    • wbudowanej.
    • Część standardowego interfejsu API języka Java z pakietem implementacji.
    • Java 9 dodaje kilka drobnych funkcji i poprawek.
  • Java SE 6 i SE 7
    • Znaczna część funkcjonalności java.time jest back-przeniesiony do Java 6 & 7 w ThreeTen-Backport.
  • Android
    • Projekt ThreeTenABP dostosowuje ThreeTen-backportu (wymienione powyżej) Androida szczegółowo.
    • Zobacz How to use….

Projekt ThreeTen-Extra rozciąga java.time z dodatkowych zajęć. Ten projekt jest poligonem wskazującym na możliwe przyszłe dodatki do java.time. Możesz znaleźć tutaj kilka użytecznych klas, takich jak Interval, YearWeek, YearQuarter i more.