Java 日历函数上的问题



我声明CalendarSimpleDateFormat如下:

calendar = Calendar.getInstance(TimeZone.getTimeZone("Malaysia"));
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MMMMM.dd hh:mm aaa");

或:

calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+08:00"));

然后我称之为:

sdf.format(calendar.getTime());

但结果不在正确的时区(+8小时)。可能是什么问题?

除非您要执行与日期/时间相关的计算,否则使用给定时区实例化日历是没有意义的。调用日历的getTime()方法后,您将收到Date对象,无论哪种方式(实际上基于 GMT),该对象都是无时区的。

您需要做的是为格式化程序设置TimeZone。也不要费心传递自己的格式,已经有一个内置的:

    // get current time
    // you could just as well use Date now = new Date();
    Calendar now = Calendar.getInstance();
    // Locale for formatter
    Locale malaysianLocale = new Locale("ms", "MY");
    // Default date and time format for Malaysia
    DateFormat defaultMalaysianFormatter = DateFormat.getDateTimeInstance(
            DateFormat.DEFAULT, DateFormat.DEFAULT, malaysianLocale);
    // This step is crucial
    TimeZone malaysianTimeZone = TimeZone.getTimeZone("Asia/Kuala_Lumpur");
    defaultMalaysianFormatter.setTimeZone(malaysianTimeZone);
    System.out.println(defaultMalaysianFormatter.format(now.getTime()));

这打印了类似 10 Mei 2011 2:30:05 AM 的东西,我相信这是您想要的结果。

时区

ID 应设置为 Asia/Kuala_LumpurDate.toString()始终使用默认时区返回时间字符串。但您的默认时区不同。

    Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("Asia/Kuala_Lumpur"));
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, tzCal.get(Calendar.YEAR));
    cal.set(Calendar.MONTH, tzCal.get(Calendar.MONTH));
    cal.set(Calendar.DAY_OF_MONTH, tzCal.get(Calendar.DAY_OF_MONTH));
    cal.set(Calendar.HOUR_OF_DAY, tzCal.get(Calendar.HOUR_OF_DAY));
    cal.set(Calendar.MINUTE, tzCal.get(Calendar.MINUTE));
    cal.set(Calendar.SECOND, tzCal.get(Calendar.SECOND));
    cal.set(Calendar.MILLISECOND, tzCal.get(Calendar.MILLISECOND));
    System.out.println("Current Time = " + sdf.format(cal.getTime()));

TimeZone.getTimeZone()调用不正确。您必须传递正确的标识符。

编辑 -- 您可以尝试获取 getAvailableIDs() 并遍历它们以确保您拥有正确的 ID。

如果你仔细阅读了 TimeZone 的 javadoc,使用 getTimeZone 的方法是:TimeZone.getTimeZone("GMT-8")或TimeZone.getTimeZone("GMT+8")

tl;dr

java.time.ZonedDateTime.now(
    ZoneId.of( "Asia/Kuala_Lumpur" ) 
).toString() 

2018-01-23T18:48:32.263+08:00[亚洲/Kuala_Lumpur]

避免使用旧类

问题和其他答案使用麻烦的旧日期时间类,这些类现在是遗留的,被java.time类所取代。

java.time

现代方法使用 java.time 类。忘记所有关于非常混乱的Calendar类。

当前时刻

首先获取 UTC 中的当前时刻。Instant类以 UTC 表示时间轴上的时刻,分辨率为纳秒(最多九 (9) 位小数)。

Instant instant = Instant.now() ;

时区

调整到另一个时区。

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

ZoneId z = ZoneId.of( "Asia/Kuala_Lumpur" ) ; // Or "Asia/Kuching", etc.

应用ZoneId以实例化ZonedDateTime对象。ZonedDateTimeInstant都代表同一个时刻,时间轴上的同一点,但通过不同的挂钟时间观看。

ZonedDateTime zdt = instant.atZone( z ) ;  // Same moment, different wall-clock time.

抵消

如果您只有一个 UTC 偏移量(例如 +08:00 而不是已知时区),您将使用 ZoneOffset 来获取OffsetDateTime而不是 ZoneId & ZonedDateTime。但是时区总是比单纯的偏移量更可取。区域是特定区域用户使用的偏移历史记录。

字符串

若要生成标准 ISO 8601 格式的字符串,请调用toString方法。

ZonedDateTime类通过将时区名称附加到方括号中来明智地扩展标准。

String output = zdt.toString() ;  // YYYY-MM-DDTHH:MM:SS.SSSSSSSSS[tz]

根据用户的首选项进行本地化。要进行本地化,请指定:

  • FormatStyle确定字符串应为多长或多短。
  • Locale确定 (a) 翻译日期名称、月份名称等的人类语言,以及 (b) 决定缩写、大写、标点符号、分隔符等问题的文化规范。

    区域设置 l = Locale.CANADA_FRENCH ;DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );字符串输出 = zdt.format( f );

转储到控制台。

System.out.println( "instant.toString(): " + instant ) ;
System.out.println( "output: " + output ) ;
System.out.println( "outputLocalized (always Locale.US on IdeOne.com): " + outputLocalized ) ;

请参阅此代码在 IdeOne.com 实时运行。请注意,IdeOne.com 会覆盖任何Locale设置以始终使用 Locale.US

即时字符串(): 2018-01-23T10:48:32.263Z

输出:2018-01-23T18:48:32.263+08:00[亚洲/Kuala_Lumpur]

o输出本地化(始终在 IdeOne.com 日 Locale.US):2018 年 1 月 23 日星期二下午 6:48:32 MYT


关于 java.time

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

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

要了解更多信息,请参阅 Oracle 教程。并搜索堆栈溢出以获取许多示例和解释。规范为 JSR 310。

从哪里获得java.time类?

    Java SE
  • 8Java SE 9 及更高版本
    • 内置。
    • 具有捆绑实现的标准 Java API 的一部分。
    • Java 9添加了一些小功能和修复。
  • Java SE
  • 6Java SE 7
    • 许多java.time功能在ThreeTen-Backport中向后移植到Java 6和7。
  • 人造人
    • java.time 类的 Android 捆绑包实现的更高版本。
    • 对于早期的Android,ThreeTenABP项目适应了ThreeTen-Backport(如上所述)。请参阅如何使用ThreeTenABP...

ThreeTen-Extra项目通过额外的类扩展了java.time。这个项目是未来可能添加到java.time的试验场。你可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等。

相关内容

  • 没有找到相关文章

最新更新