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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/85701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:59:39  来源:igfitidea点击:

Best way to extract TimeZone object from a String?

javatimezone

提问by matt b

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. The default TimeZone in the JVM that this application runs in is GMT, so I can't use .getTimezoneOffset()from the Dateparsed above (because it will return the default TimeZone).

我想做的是从这个字符串中提取一个 TimeZone 对象。在JVM中的默认时区,该应用程序运行在格林威治时间,所以我不能使用.getTimezoneOffset()Date上述分析(因为它会返回默认时区)。

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 对象 - 它将具有相同的 TimeZone作为我解析的字符串DateFormat.parse()

One thing that bugs me about Datevs Calendarin the Java API is that Calendaris supposed to replace Datein all places... but then they decided, oh hey let's still use Date's in the DateFormatclasses.

Java API 中的Datevs令我感到困扰的一件事Calendar是,Calendar它应该Date在所有地方替换...但后来他们决定,哦,嘿,让我们仍然DateDateFormat类中使用's 。

回答by Ed Thomas

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 运行的。

回答by matt b

@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

Parsed [Friday, September 26, 2008 8:30 PM Pacific Standard Time] to Date: Sat Sep 27 00:30:00 EDT 2008

DateFormat timezone after parse: Eastern Standard Time

默认时区为:东部标准时间

解析前的 DateFormat 时区:东部标准时间

解析 [太平洋标准时间 2008 年 9 月 26 日星期五晚上 8:30] 到日期:2008 年 9 月 27 日星期六 00:30:00 EDT

解析后的 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即使我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()只是返回底层日历的时区...除非您指定要使用的某个特定时区,否则默认为默认区域设置/时区的日历。

回答by Aaron

I recommend checking out the Joda Time date and 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. In particular, you should check out the DateTimeZoneclass. Hope this helps.

我建议查看Joda Time date and time API。我最近已经转变为它的信徒,因为它往往比 Java 中对日期和时间的内置支持更加优越。特别是,您应该查看DateTimeZone类。希望这可以帮助。

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

回答by Basil Bourque

tl;dr

tl;博士

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

时间

The modern way is with the java.time classes. 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.

现代方法是使用 java.time 类。问题和其他答案使用麻烦的旧的遗留日期时间类或 Joda-Time 项目,现在这两个类都被 java.time 类所取代。

Define a DateTimeFormatterobject with a formatting pattern to match your data.

DateTimeFormatter使用格式模式定义对象以匹配您的数据。

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

Assign a Localeto specify the human language of the name-of-day and name of month, as well as the cultural norms for other formatting issues.

分配 aLocale以指定日名和月名的人类语言,以及其他格式问题的文化规范。

f = f.withLocale( Locale.US );

Lastly, do the parsing to get a ZonedDateTimeobject.

最后,进行解析以获取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 ZoneIdobject. You can then interrogate the ZoneIdif you need more info about the time zone.

您可以从ZonedDateTime, 中请求时区,表示为一个ZoneId对象。然后,您可以询问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 terribleformat. 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 namein the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as ESTor ISTas they are not true time zones, not standardized, and not even unique(!).

对于时区:以、、 或等格式指定正确的时区名称。永远不要使用 3-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/regionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST

For serializing date-time values to text, use only the ISO 8601formats. The java.time classes use these formats by default when parsing/generating strings to represent their value.

要将日期时间值序列化为文本,请仅使用ISO 8601格式。java.time 类在解析/生成字符串以表示它们的值时默认使用这些格式。



About java.time

关于 java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to java.time.

现在处于维护模式Joda-Time项目建议迁移到 java.time。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

回答by Mike Pone

Ed has it right. you want the timeZone on the DateFormat object after the time has been parsed.

埃德说得对。在解析时间后,您需要 DateFormat 对象上的时区。

 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

回答by Roland Schneider

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. 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.

Date 和 Calendar 之间的主要区别在于,Date 只是一个值对象,没有方法可以修改它。所以它被设计用于在某处存储日期/时间信息。如果您使用 Calendar 对象,则可以在将其设置为使用日期/时间信息执行某些业务逻辑的持久实体后对其进行修改。这是非常危险的,因为实体无法识别这种变化。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?

这是你想要的结果吗?

回答by Mitchel Sellers

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. AM or PM.

作为部分解决方案,您可以使用 RegEx 匹配来获取时区,因为在它之前总是有相同的文本。上午或下午。

I don't know enough about Java timezones to get you the last part of it.

我对 Java 时区的了解不够,无法让您了解它的最后一部分。