对于自定义时区,没有Java(GMT + 00:00)的时区偏移的SimpleDateFormat

时间:2011-11-22 13:19:14

标签: java timezone simpledateformat

是否可以使用SimpleDateFormat类格式化Java中的日期时间,以便为时区提供日期时间而不是后面的+0000。

修改

我们正在更改Java中的默认时区,如下所示:

SimpleTimeZone tz = new SimpleTimeZone(0, "Out Timezone");        
TimeZone.setDefault(tz);

不幸的是,我无法删除此代码。我会猜测整个系统停止工作。我认为最初的作者把这个用于解决某些节能问题。

考虑到这一点,我想将日期格式化为:

2011-12-27 09:00 GMT

2011-12-27 09:00 BST

我只能将SimpleDateFormat输出为:

2011-12-27 09:00:00 GMT + 00:00

使用格式字符串 yyyy-MM-dd HH:mm:ss z

我无法看到简单时区对冬令时(GMT)ID或夏令时ID(BST)的任何引用。

有什么想法吗?

由于

Andez

5 个答案:

答案 0 :(得分:5)

这个问题和答案现在已经过时了。它们使用旧的日期时间类,这些类已经过了Java 8及更高版本中内置的java.time框架。旧班设计糟糕,令人困惑,麻烦; 避免使用

避免3-4个字母区域代码

避免使用BST等3-4个字母代码。它们既不标准也不独特。它们实际上并不代表时区。而且它们对夏令时(DST)的问题更加困惑。

相反,请使用proper time zones。大多数是continent/region格式,例如Europe/London

避免设置默认时区

只应在最极端的情况下调用java.util.TimeZone.setDefault。此调用会在运行时期间立即影响JVM中所有应用程序的所有线程中运行的所有代码。

相反,在所有日期时间代码中,指定所需/预期的时区。如果省略,Java将通过隐式依赖JVM的当前默认时区来回退。如上所述,此默认值可在运行时期间随时更改!相反,明确指定。如果您定期将所需/预期时区指定为传递参数,那么当前默认时区是没有实际意义的,无关紧要。

java.time

java.time框架内置于Java 8及更高版本中。见Tutorial。由JSR 310定义。灵感来自非常成功的Joda-Time库。

Instant

Instant是UTC时间轴上的一个时刻。

以下示例显示了java.time类如果采用标准ISO 8601格式,默认情况下如何解析/生成字符串,而无需指定解析模式。使用DateTimeFormatter类指定其他非标准模式。

Instant instant = Instant.parse( "2011-12-27T09:00:00Z" );

ZonedDateTime

根据需要应用时区,生成ZonedDateTime

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( zoneId );

生成字符串

您可以使用DateTimeFormatter生成ZonedDateTime对象的文本表示。您可以指定自定义模式。或者,正如我所建议的那样,让java.time本地化为您服务。

DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM );

最好指定期望/期望Locale的原因与时区相同... JVM的当前默认值可随时由JVM中运行的任何应用程序的任何线程中的任何代码更改。 Locale确定(a)用于日期名称的人类语言。月份,以及(b)逗号与期间等文化规范以及诸如月份,日期或年份等部分的顺序。

formatter = formatter.withLocale( Locale.CANADA_FRENCH );
String output = zdt.format( formatter );

关于 java.time

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

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

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

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

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

答案 1 :(得分:3)

我认为您使用的是正确的模式以满足您的要求,但是JDK不知道您的时区的名称,因此它转而使用GMT offset value代替。

当我使用您的模式格式化日期时,我会获得时区部分的“GMT”。

TimeZone.getDefault().getDisplayName()给你什么?对我来说,我得到了“格林威治标准时间”。

答案 2 :(得分:1)

因为我无法在计算机上重现此问题。我想这与本地化有关。试试这个

System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z",Locale.US).format(new Date()));

希望这有帮助。

答案 3 :(得分:1)

System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(new Date()));对我来说只是返回2011-11-22 13:42:16 GMT - 所以看起来按照您的意愿工作。看起来在其他地方可能会出现问题,但您不需要创建自己的格式化程序类。

答案 4 :(得分:1)

根本不是一个优雅的解决方案,但它适用于我们。我不得不为DateFormat / SimpleDateFormat创建一个自定义实现。这看起来如下:

static {
    // this would be initialized like something as follows when the application starts
    // which causes the headaches of SimpleDateFormat not to work...
    SimpleTimeZone tz = new SimpleTimeZone(0, "Out Timezone");             
    TimeZone.setDefault(tz);  
}

// therefore this class will workaround the issue, 

public class OurOwnCustomDateFormat
    extends SimpleDateFormat {

    /** The pattern to use as the format string. */
    protected String pattern;

    public OurOwnCustomDateFormat(String pattern) {
         super(pattern);
         // store the pattern
         this.pattern = pattern;
    }

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {

         // custom implementation to format the date and time based on our TimeZone            
         toAppendTo.insert(pos.getBeginIndex(), "the date with our custom format calculated here");
         return toAppendTo; 
    }