从String中提取TimeZone对象的最佳方法?

时间:2008-09-17 17:37:47

标签: java timezone

我有一个数据库字段,其中包含一个原始日期字段(存储为字符数据),例如

  

2008年9月26日星期五东部夏令时间晚上8:30

我可以使用SimpleDateFormat

轻松解析这个日期
DateFormat dbFormatter = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm aa zzzz");
Date scheduledDate = dbFormatter.parse(rawDate);

我想要做的是从此字符串中提取TimeZone对象。此应用程序运行的JVM中的默认TimeZone是GMT,因此我无法使用上面解析的.getTimezoneOffset()中的Date(因为它将返回默认的TimeZone)。

除了对原始字符串进行标记并查找时区字符串的起始位置(因为我知道格式将始终为EEEE, MMMM dd, yyyy hh:mm aa zzzz)之外,还有一种方法可以使用DateFormat / SimpleDateFormat / Date / Calendar API来提取TimeZone对象 - 它将与我使用DateFormat.parse()解析的字符串具有相同的TimeZone?

Java API中Date vs Calendar的一个问题是,Calendar应该在所有地方替换Date ......但后来他们决定哦,嘿,我们仍然在Date类中使用DateFormat

7 个答案:

答案 0 :(得分:2)

我发现了以下内容:

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

产生以下内容:

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

我实际上发现这有点令人惊讶。但是,我想这表明您的问题的答案是在解析后简单地在格式化程序上调用getTimeZone。

编辑: 以上是与Sun的JDK 1.6一起运行的。

答案 1 :(得分:1)

@Ed Thomas:

我尝试过与你的例子非常相似的东西,但结果却截然不同:

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

输出:

  

默认TimeZone为:东部标准时间

     

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

     

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

     

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

似乎DateFormat.getTimeZone()parse()之前和之后返回相同的TimeZone ...即使我在调用setTimeZone()之前引入了明确的parse()

查看DateFormat和SimpleDateFormat的源代码,似乎getTimeZone()只返回基础Calendar的TimeZone ...默认为默认Locale / TimeZone的Calendar,除非您指定要使用的某个日历

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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

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

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

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

指定Locale以指定日期名称和月份名称的人类语言,以及其他格式问题的文化规范。

f = f.withLocale( Locale.US );

最后,进行解析以获取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]

您可以从ZonedDateTime请求时区,表示为ZoneId个对象。如果您需要有关时区的更多信息,则可以询问ZoneId

ZoneId z = zdt.getZone();

See for yourself in IdeOne.com

ISO 8601

避免以这种可怕的格式交换日期时间数据。不要假设英语,不要使用诸如日期名称之类的内容来装饰您的输出,也不要使用Eastern Daylight Time之类的伪时区。

对于时区:以continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 4 :(得分:0)

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

我对Java时区的了解还不足以让你了解它的最后一部分。

答案 5 :(得分:0)

日期和日历之间的主要区别在于,日期只是一个没有修改方法的值对象。所以它被设计用于在某处存储日期/时间信息。如果使用Calendar对象,则可以在将其设置为使用日期/时间信息执行某些业务逻辑的持久实体后对其进行修改。这非常危险,因为实体无法识别这种变化。 Calendar类专为日期/时间操作而设计,例如添加天或类似的东西。

玩弄你的例子我得到以下内容:

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

}

输出:

  

sun.util.calendar.ZoneInfo [ID = “欧洲/柏林” ...   sun.util.calendar.ZoneInfo [ID = “非洲/亚的斯亚贝巴” ...

这是你想要的结果吗?

答案 6 :(得分:0)

爱德是对的。你需要在解析时间之后在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());

产生

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