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

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

Best way to extract TimeZone object from a String?

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

Friday, September 26, 2008 8:30 PM Eastern Daylight Time

我可以使用SimpleDateFormat轻松将其解析为Date

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

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

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

关于Java API中的DateCalendar的一件令我烦恼的事情是,应该在所有位置替换Date ...但是他们决定,哦,还是让我们继续使用DateDateFormat类中。


我发现以下内容:

1
2
3
4
5
6
7
8
9
        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));

产生以下内容:

1
2
3
4
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一起运行的。


TL;博士

1
2
3
4
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对象以匹配您的数据。

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

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

1
f = f.withLocale( Locale.US );

最后,进行解析以获得ZonedDateTime对象。

1
2
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

1
ZoneId z = zdt.getZone();

在IdeOne.com上自行查看。

ISO 8601

避免以这种糟糕的格式交换日期时间数据。不要假设英语,不要使用诸如" day-of-day"之类的名称来为输出添加内容,也不要使用诸如Eastern Daylight Time之类的伪时区。

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

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

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧式传统日期时间类,例如java.util.DateCalendarSimpleDateFormat

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

要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。

在哪里获取java.time类?

  • Java SE 8和SE 9及更高版本

    • 内置。
    • 标准Java API的一部分,具有捆绑的实现。
    • Java 9添加了一些次要功能和修复。
  • Java SE 6和SE 7

    • java.time的许多功能在ThreeTen-Backport中都被反向移植到Java 6和7。
  • Android的

    • ThreeTenABP项目专门针对Android改编了ThreeTen-Backport(如上所述)。
    • 请参阅如何使用…。

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuarter等。


我建议您查看Joda Time日期和时间API。我最近被转换为对此的信奉者,因为它往往比Java中对日期和时间的内置支持要优越得多。特别是,您应该检出DateTimeZone类。希望这可以帮助。

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

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


@Ed Thomas:

我尝试了与您的示例非常相似的方法,但结果却截然不同:

1
2
3
4
5
6
7
8
9
10
11
12
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());

输出:

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.getTimeZone()parse()之前和之后返回相同的TimeZone ...,即使我在调用parse()之前抛出了明确的setTimeZone()

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


埃德说得对。您需要在解析时间后在DateFormat对象上使用timeZone。

1
2
3
4
5
6
7
 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());

产生

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

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

玩一下您的示例,我得到以下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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="Europe/Berlin"...
sun.util.calendar.ZoneInfo[id="Africa/Addis_Ababa"...

这是您想要的结果吗?


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

我对Java时区了解不足,无法完全了解它。


推荐阅读

    linux操作数据库命令?

    linux操作数据库命令?,地址,服务,系统,密码,数据库,工具,名字,首页,命令,参

    linux输出字符串命令?

    linux输出字符串命令?,标准,基础,字符串,资料,简介,商业,数字,系统,命令,汉

    linux数据库升级命令?

    linux数据库升级命令?,系统,信息,时间,最新,网络,名字,地址,管理,简介,传播,l

    数据库导出linux命令?

    数据库导出linux命令?,密码,数据,数据库,情况,地址,系统,工具,网上,名字,命

    字符串查找命令linux?

    字符串查找命令linux?,系统,字符串,工具,信息,文件,命令,字符,选项,文本,范

    linux恢复数据库命令?

    linux恢复数据库命令?,工具,系统,软件,数据,盘中,密码,命令,备份,数据库,文

    linux命令替换字符串?

    linux命令替换字符串?,字符串,文件,批量,首次,数据,命令,内容,方法,用字,结

    linux命令大全数据库?

    linux命令大全数据库?,服务,系统,平台,状态,软件,通用,环境,数据,神州,地址,

    linux上数据库的命令?

    linux上数据库的命令?,服务,系统,信息,地址,命令,密码,工具,管理,数据,单位,

    linux命令dm数据库?

    linux命令dm数据库?,地址,软件,时间,设备,名字,服务,位置,名称,公司,命令,lin

    linux拼接字符串命令?

    linux拼接字符串命令?,系统,工作,代码,工具,名称,信息,地址,时间,数据,命令,l

    linux使用命令的方法?

    linux使用命令的方法?,系统,信息,工具,标准,数据,命令,左下角,目录,文件夹,

    linux无效对象的命令?

    linux无效对象的命令?,软件,系统,单位,网络,管理,术语,检测,电脑,环境,风险,l

    linux下抓取字段命令?

    linux下抓取字段命令?,数据,系统,命令,单位,报告,工具,字符串,文件,范本,样

    linux数据库查找命令?

    linux数据库查找命令?,位置,名称,状态,服务,软件,信息,系统,命令,名字,密码,

    添加字符串命令linux?

    添加字符串命令linux?,情况,名称,文件,位置,名字,地方,连续,信息,命令,内容,L

    linux数据库同步命令?

    linux数据库同步命令?,信息,系统,汽车,车辆,服务,工作,通信,一致,分析,数据,D

    linux提取字段串命令?

    linux提取字段串命令?,数字,字符串,状态,工具,命令,文件,范本,样式,正则,字

    linux建立数据库命令?

    linux建立数据库命令?,软件,系统,工作,数据,密码,工具,数据库,一致,网络,服

    linux命令进数据库?

    linux命令进数据库?,地址,系统,名字,服务,密码,命令,读法,数据库,操作系统,