2008-09-17 30 views
8

Tôi có một lĩnh vực cơ sở dữ liệu có chứa một trường ngày liệu (được lưu trữ dưới dạng dữ liệu nhân vật), chẳng hạn nhưCách tốt nhất để trích xuất đối tượng TimeZone từ một chuỗi?

Thứ sáu 26 tháng 9, 2008 8:30 Đông Ánh sáng ban ngày Thời gian

tôi có thể phân tích cú pháp đây là một ngày dễ dàng, với SimpleDateFormat

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

Điều tôi muốn làm là trích xuất một đối tượng TimeZone từ chuỗi này. TimeZone mặc định trong JVM mà ứng dụng này chạy là GMT, vì vậy tôi không thể sử dụng .getTimezoneOffset() từ số Date được phân tích cú pháp ở trên (vì nó sẽ trả về TimeZone mặc định).

Bên cạnh việc mã hóa chuỗi thô và tìm vị trí bắt đầu của chuỗi múi giờ (vì tôi biết định dạng sẽ luôn là EEEE, MMMM dd, yyyy hh:mm aa zzzz) là có cách sử dụng API DateFormat/SimpleDateFormat/Date/Calendar để trích xuất đối tượng TimeZone - sẽ có cùng một TimeZone dưới dạng Chuỗi Tôi đã phân tích cú pháp ngoài với DateFormat.parse()?

Một điều mà làm tôi phát cáu về Date vs Calendar trong API Java là Calendar là nghĩa vụ phải thay thế Date ở mọi nơi ... nhưng sau đó họ đã quyết định, oh hey hãy vẫn sử dụng Date 's trong DateFormat lớp.

+0

bạn có giải pháp cho vấn đề này không? – Chin2

+0

Về đoạn cuối, các lớp 'Ngày' &' Lịch' là một mớ hỗn độn đẫm máu: kém thiết kế, khó hiểu và phiền hà. Tránh chúng. Sử dụng các lớp [java.time] (http://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) để thay thế. –

Trả lời

0

Cũng như một giải pháp một phần, bạn có thể sử dụng đối sánh RegEx để nhận múi giờ vì bạn sẽ luôn có cùng văn bản trước đó. AM hoặc PM.

Tôi không biết đủ về múi giờ Java để giúp bạn có được phần cuối cùng của nó.

2

tôi thấy rằng sau:

 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)); 

Tạo điều sau đây:

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 

Tôi thực sự thấy điều này là hơi ngạc nhiên. Nhưng, tôi đoán rằng cho thấy câu trả lời cho câu hỏi của bạn là chỉ cần gọi getTimeZone trên trình định dạng sau khi bạn đã phân tích cú pháp.

Chỉnh sửa: Ở trên đã được chạy với JDK 1.6 của Sun.

+0

Tôi cũng rất ngạc nhiên bởi điều này và đã gặp phải các vấn đề với trượt TimeZone do sự khởi tạo ngày trước đó. – 18Rabbit

+0

Chỉ cần tò mò - kết quả của TimeZone.getDefault() trên máy của bạn là gì? –

0

Sự khác biệt chính giữa Ngày và Lịch là, ngày đó chỉ là một đối tượng giá trị không có phương pháp sửa đổi nó. Vì vậy, nó được thiết kế để lưu trữ thông tin ngày/giờ ở đâu đó. Nếu bạn sử dụng một đối tượng Lịch, bạn có thể sửa đổi nó sau khi nó được đặt thành một thực thể liên tục thực hiện một số logic nghiệp vụ với thông tin ngày/giờ. Điều này rất nguy hiểm, bởi vì thực thể không có cách nào để nhận ra sự thay đổi này. Lớp Lịch được thiết kế cho các hoạt động vào ngày/giờ, như thêm ngày hoặc tương tự như vậy.

Chơi xung quanh với ví dụ của bạn tôi nhận được như sau:

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()); 
    } 

} 

Output:

sun.util.calendar.ZoneInfo [id = "Europe/Berlin" ... mặt trời. util.calendar.ZoneInfo [id = "Châu Phi/Addis_Ababa" ...

Đây có phải là kết quả bạn muốn không?

1

@Ed Thomas:

Tôi đã thử một cái gì đó rất giống với ví dụ của bạn và tôi nhận được kết quả rất khác nhau:

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()); 

Output:

Các TimeZone mặc định là: Đông Giờ chuẩn

DateFormat múi giờ trước khi phân tích cú pháp: Giờ chuẩn miền Đông

phân tích cú pháp [Thứ sáu Tháng 9 26, PM Thời gian 2008 08:30 chuẩn Thái Bình Dương] to Date: Sat 27 Tháng 9 00:30:00 EDT 2008

DateFormat múi giờ sau khi phân tích cú pháp: Giờ chuẩn Đông

Có vẻ như DateFormat.getTimeZone() trả về cùng một TimeZone trước và sau parse() ... ngay cả khi tôi ném vào một số setTimeZone() rõ ràng trước khi gọi parse().

Nhìn vào nguồn cho DateFormat và SimpleDateFormat, có vẻ như getTimeZone() chỉ trả về TimeZone của Lịch bên dưới ... mặc định là Lịch mặc định Locale/TimeZone trừ khi bạn chỉ định một số nhất định để sử dụng.

+0

Bạn đang sử dụng JVM nào? –

+0

Phiên bản java "1.4.2_14" Môi trường chạy thử Java (TM) 2, Phiên bản tiêu chuẩn (xây dựng 1.4.2_14-b05) Máy khách Java HotSpot (TM) (xây dựng 1.4.2_14-b05, chế độ hỗn hợp) –

0

Ed có quyền. bạn muốn timeZone trên đối tượng DateFormat sau khi thời gian được phân tích cú pháp.

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()); 

sản xuất

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

Bạn có thể muốn để thử nghiệm với một cái gì đó khác với "Giờ ban ngày miền đông" trong ngày String - dbFormatter.getTimeZone() chỉ trả lại múi giờ mặc định (của bạn). –

1

tôi khuyên bạn nên xem ngày Joda Thời gian và thời gian API. Gần đây tôi đã được chuyển đổi thành một người tin tưởng vào nó vì nó có xu hướng cao hơn rất nhiều so với sự hỗ trợ được xây dựng sẵn trong ngày và giờ trong Java. Đặc biệt, bạn nên xem lớp DateTimeZone. Hi vọng điêu nay co ich.

http://joda-time.sourceforge.net/

http://joda-time.sourceforge.net/api-release/index.html

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

Cách hiện đại với các lớp java.time. Câu hỏi và các câu trả lời khác sử dụng các lớp thời gian cũ di sản phiền hà hoặc dự án Joda-Time, cả hai đều được thay thế bởi các lớp java.time.

Xác định đối tượng DateTimeFormatter với mẫu định dạng để khớp với dữ liệu của bạn.

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

chỉ định ngôn ngữ của con người tên và ngày tháng, cũng như định mức văn hóa cho các vấn đề định dạng khác.

f = f.withLocale(Locale.US); 

Cuối cùng, thực hiện phân tích cú pháp để nhận đối tượng ZonedDateTime.

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 [America/New_York]

Bạn có thể yêu cầu các múi giờ từ ZonedDateTime, biểu diễn dưới dạng một đối tượng ZoneId. Sau đó, bạn có thể thẩm vấn ZoneId nếu bạn cần thêm thông tin về múi giờ.

ZoneId z = zdt.getZone(); 

See for yourself in IdeOne.com.

ISO 8601

Tránh trao đổi dữ liệu ngày-thời gian trong loại dạng khủng khiếp. Không giả sử tiếng Anh, không truy cập đầu ra của bạn với những thứ như tên trong ngày và không bao giờ sử dụng các múi giờ giả như Eastern Daylight Time.

Đối với múi giờ: Chỉ định proper time zone name trong định dạng của continent/region, chẳng hạn như America/Montreal, Africa/Casablanca, hoặc Pacific/Auckland. Không bao giờ sử dụng từ viết tắt 3-4 ký tự như EST hoặc IST vì chúng không phải là múi giờ thực, không được chuẩn hóa và không phải là duy nhất (!).

Để tuần tự hóa các giá trị ngày giờ thành văn bản, chỉ sử dụng các định dạng ISO 8601. Các lớp java.time sử dụng các định dạng này theo mặc định khi phân tích cú pháp/tạo chuỗi để biểu diễn giá trị của chúng.


Về java.time

Khung java.time được xây dựng vào Java 8 và sau đó. Các lớp này thay thế các lớp học ngày giờ legacy phiền hà cũ như java.util.Date, Calendar, & SimpleDateFormat.

Dự án Joda-Time, hiện đang ở maintenance mode, khuyên di chuyển sang java.time.

Để tìm hiểu thêm, hãy xem Oracle Tutorial. Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310.

Nơi lấy các lớp java.time?

  • Java SE 8SE 9 và sau
    • Built-in.
    • Một phần của API Java chuẩn với gói được triển khai.
    • Java 9 thêm một số tính năng và bản sửa lỗi nhỏ.
  • Java SE 6SE 7
    • Hầu hết các chức năng java.time được back-chuyển đến Java 6 & 7 trong ThreeTen-Backport.
  • Android

Dự án mở rộng ThreeTen-Extra java.time với các lớp bổ sung. Dự án này là một nền tảng chứng minh cho những bổ sung có thể có trong tương lai vào java.time. Bạn có thể tìm thấy một số lớp học hữu ích tại đây như Interval, YearWeek, YearQuartermore.

Các vấn đề liên quan