我有一个数据库字段,其中包含一个原始日期字段(存储为字符数据),例如
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
。
答案 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 类。希望这可以帮助。
答案 3 :(得分:1)
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类。问题和其他答案使用麻烦的旧遗留日期时间类或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
避免以这种可怕的格式交换日期时间数据。不要假设英语,不要使用诸如日期名称之类的内容来装饰您的输出,也不要使用Eastern Daylight Time
之类的伪时区。
对于时区:以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
要将日期时间值序列化为文本,请仅使用ISO 8601格式。在解析/生成字符串以表示其值时,java.time类默认使用这些格式。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 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)
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