简体   繁体   English

从字符串中提取TimeZone对象的最佳方法?

[英]Best way to extract TimeZone object from a String?

I have a database field that contains a raw date field (stored as character data), such as 我有一个数据库字段,其中包含原始日期字段(存储为字符数据),例如

Friday, September 26, 2008 8:30 PM Eastern Daylight Time 美国东部时间2008年9月26日,星期五,晚上8:30

I can parse this as a Date easily, with SimpleDateFormat 我可以使用SimpleDateFormat轻松将其解析为Date

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

What I'd like to do is extract a TimeZone object from this string. 我想做的是从此字符串中提取一个TimeZone对象。 The default TimeZone in the JVM that this application runs in is GMT, so I can't use .getTimezoneOffset() from the Date parsed above (because it will return the default TimeZone). 运行此应用程序的JVM中的默认TimeZone是GMT,所以我不能从上面解析的Date使用.getTimezoneOffset() (因为它将返回默认的TimeZone)。

Besides tokenizing the raw string and finding the start position of the Timezone string (since I know the format will always be EEEE, MMMM dd, yyyy hh:mm aa zzzz ) is there a way using the DateFormat/SimpleDateFormat/Date/Calendar API to extract a TimeZone object - which will have the same TimeZone as the String I've parsed apart with DateFormat.parse() ? 除了标记原始字符串并找到时区字符串的开始位置(因为我知道格式将始终是EEEE, MMMM dd, yyyy hh:mm aa zzzz )之外,还有一种方法可以使用DateFormat / SimpleDateFormat / Date / Calendar API来提取一个TimeZone对象-与使用DateFormat.parse()解析过的String具有相同的TimeZone吗?

One thing that bugs me about Date vs Calendar in the Java API is that Calendar is supposed to replace Date in all places... but then they decided, oh hey let's still use Date 's in the DateFormat classes. 关于Java API中的Date vs Calendar ,令我烦恼的一件事是Calendar应该在所有地方替换Date ……但是他们决定,哦,还是让我们在DateFormat类中使用Date

I found that the following: 我发现以下内容:

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

Produces the following: 产生以下内容:

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 actually found this to be somewhat surprising. 我实际上发现这有些令人惊讶。 But, I guess that shows that the answer to your question is to simply call getTimeZone on the formatter after you've parsed. 但是,我想这表明您的问题的答案是在解析后仅在格式化程序上调用getTimeZone。

Edit: The above was run with Sun's JDK 1.6. 编辑:上面是与Sun的JDK 1.6一起运行的。

tl;dr 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 java.time

The modern way is with the java.time classes. 现代方法是使用java.time类。 The Question and other Answers use the troublesome old legacy date-time classes or the the Joda-Time project, both of which are now supplanted by the java.time classes. “问题”和“其他答案”使用麻烦的旧旧日期时间类或Joda-Time项目,现在这两个类都已被java.time类取代。

Define a DateTimeFormatter object with a formatting pattern to match your data. 使用格式化模式定义DateTimeFormatter对象以匹配您的数据。

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

Assign a Locale to specify the human language of the name-of-day and name of month, as well as the cultural norms for other formatting issues. 分配Locale以指定日期名称和月份名称的人类语言,以及其他格式问题的文化规范。

f = f.withLocale( Locale.US );

Lastly, do the parsing to get a ZonedDateTime object. 最后,执行解析以获取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] zdt.toString():2008-09-26T20:30-04:00 [美国/纽约]

You can ask for the time zone from the ZonedDateTime , represented as a ZoneId object. 您可以从ZonedDateTime询问时区,表示为ZoneId对象。 You can then interrogate the ZoneId if you need more info about the time zone. 然后,如果您需要有关时区的更多信息,则可以询问ZoneId

ZoneId z = zdt.getZone();

See for yourself in IdeOne.com . 在IdeOne.com上自己看看

ISO 8601 ISO 8601

Avoid exchanging date-time data in this kind of terrible format. 避免以这种糟糕的格式交换日期时间数据。 Do not assume English, do not accessorize your output with things like the name-of-day, and never use pseudo-time-zones such as Eastern Daylight Time . 不要假设英语,不要用日名之类的东西来为输出提供辅助,也不要使用伪时区(例如Eastern Daylight Time

For time zones: Specify a proper time zone name in the format of continent/region , such as America/Montreal , Africa/Casablanca , or Pacific/Auckland . 对于时区:以continent/region的格式指定正确的时区名称 ,例如America/MontrealAfrica/CasablancaPacific/Auckland Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!). 切勿使用ESTIST等3-4个字母的缩写,因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。

For serializing date-time values to text, use only the ISO 8601 formats. 要将日期时间值序列化为文本,请仅使用ISO 8601格式。 The java.time classes use these formats by default when parsing/generating strings to represent their value. 解析/生成字符串以表示其值时,java.time类默认使用这些格式。


About java.time 关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于Java 8及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat . 这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to java.time. 现在处于维护模式Joda-Time项目建议迁移到java.time。

To learn more, see the Oracle Tutorial . 要了解更多信息,请参见Oracle教程 And search Stack Overflow for many examples and explanations. 并在Stack Overflow中搜索许多示例和说明。 Specification is JSR 310 . 规格为JSR 310

Where to obtain the java.time classes? 在哪里获取java.time类?

  • Java SE 8 and SE 9 and later Java SE 8SE 9及更高版本
    • Built-in. 内置的
    • Part of the standard Java API with a bundled implementation. 标准Java API的一部分,具有捆绑的实现。
    • Java 9 adds some minor features and fixes. Java 9添加了一些次要功能和修复。
  • Java SE 6 and SE 7 Java SE 6SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport . java.time的许多功能在ThreeTen- Backport中都被反向移植到Java 6和7。
  • Android 安卓系统

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目使用其他类扩展了java.time。 This project is a proving ground for possible future additions to java.time. 该项目为将来可能在java.time中添加内容提供了一个试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more . 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

@Ed Thomas: @Ed Thomas:

I've tried something very similar to your example and I get very different results: 我尝试了与您的示例非常相似的方法,但结果却截然不同:

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: 输出:

The default TimeZone is: Eastern Standard Time 默认的时区为:东部标准时间

DateFormat timezone before parse: Eastern Standard Time 解析前的DateFormat时区:东部标准时间

Parsed [Friday, September 26, 2008 8:30 PM Pacific Standard Time] to Date: Sat Sep 27 00:30:00 EDT 2008 解析时间:[太平洋标准时间2008年9月26日,星期五,晚上8:30]至日期:2008 EDT 2008年9月27日,星期六:00:30:00

DateFormat timezone after parse: Eastern Standard Time 解析后的DateFormat时区:东部标准时间

Seems like DateFormat.getTimeZone() returns the same TimeZone before and after the parse() ... even if I throw in an explicit setTimeZone() before calling parse() . 好像DateFormat.getTimeZone()parse()之前和之后都返回相同的TimeZone ...,即使我在调用parse()之前抛出了显式的setTimeZone() parse()

Looking at the source for DateFormat and SimpleDateFormat, seems like getTimeZone() just returns the TimeZone of the underlying Calendar... which will default to the Calendar of the default Locale/TimeZone unless you specify a certain one to use. 查看DateFormat和SimpleDateFormat的源代码,好像getTimeZone()只是返回基础Calendar的TimeZone ...,除非您指定要使用的特定日历,否则它将默认为默认Locale / TimeZone的Calendar。

I recommend checking out the Joda Time date and time API . 我建议您查看Joda Time日期和时间API I have recently been converted to a believer in it as it tends to be highly superior to the built-in support for dates and times in Java. 我最近被转换为对此的信奉者,因为它往往比Java中对日期和时间的内置支持要优越得多。 In particular, you should check out the DateTimeZone class. 特别是,您应该检出DateTimeZone类。 Hope this helps. 希望这可以帮助。

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

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

Well as a partial solution you could use a RegEx match to get the timezone since you will always have the same text before it. 作为部分解决方案,您可以使用RegEx匹配来获取时区,因为您之前总是会有相同的文本。 AM or PM. 上午或下午。

I don't know enough about Java timezones to get you the last part of it. 我对Java时区了解不足,无法完全了解它。

The main difference between Date and Calendar is, that Date is just a value object with no methods to modify it. 日期和日历之间的主要区别在于,日期只是一个值对象,没有修改它的方法。 So it is designed for storing a date/time information somewhere. 因此,它旨在将日期/时间信息存储在某个地方。 If you use a Calendar object, you could modify it after it is set to a persistent entity that performs some business logic with the date/time information. 如果使用Calendar对象,则可以在将其设置为执行带有日期/时间信息的某些业务逻辑的持久实体后,对其进行修改。 This is very dangerous, because the entity has no way to recognize this change. 这非常危险,因为实体无法识别此更改。 The Calendar class is designed for operations on date/time, like adding days or something like that. Calendar类设计用于按日期/时间进行操作,例如添加天数之类。

Playing around with your example I get the following: 玩一下您的示例,我得到以下信息:

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"... sun.util.calendar.ZoneInfo[id="Africa/Addis_Ababa"... sun.util.calendar.ZoneInfo [id =“欧洲/柏林” ... sun.util.calendar.ZoneInfo [id =“ Africa / Addis_Ababa” ...

Is this the result you wanted? 这是您想要的结果吗?

Ed has it right. 埃德说得对。 you want the timeZone on the DateFormat object after the time has been parsed. 您需要在解析时间后在DateFormat对象上使用timeZone。

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

produces 产生

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从Java中的邮件日期标题中提取时区的最佳方法? - Best way to extract a timezone from a mail Date header in Java? Java从字符串中提取部分的最佳方法 - Java Best way to extract parts from a string 从给定的字符串中提取字符串的一部分的最佳方法是什么? - what is the best way to extract a part of a string from a given string? 从字符串中获取 JSON 对象的最佳方法 - Best way to get the JSON object from a string 如何从Java中的BufferedReader对象中提取整个内容的最佳方法是什么? - How is the best way to extract the entire content from a BufferedReader object in Java? 从 Java 中的字符串中提取第一个单词的最佳方法是什么? - What is the best way to extract the first word from a string in Java? 从Java中的字符串中提取此int的最佳方法是什么? - What is the best way to extract this int from a string in Java? 从尊重时区的日历对象中获取格式化字符串的最简单方法是什么? - What is the easiest way to get a formatted string from a calendar object which respects timezone? 从ISO8601日期时间字符串中提取时区 - Extract timezone from ISO8601 date time string 从可以采用许多 forms 并从 Java 中的 a.properties 文件加载的字符串中提取值的最佳方法 - Best Way to Extract Values from a String that can take many forms and is Loaded from a .properties file in Java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM