我声明Calendar
,SimpleDateFormat
如下:
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_Lumpur
。 Date.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/Montreal
、 Africa/Casablanca
或 Pacific/Auckland
。切勿使用 3-4 个字母的伪区域,例如 EST
或 IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!
ZoneId z = ZoneId.of( "Asia/Kuala_Lumpur" ) ; // Or "Asia/Kuching", etc.
应用ZoneId
以实例化ZonedDateTime
对象。ZonedDateTime
和Instant
都代表同一个时刻,时间轴上的同一点,但通过不同的挂钟时间观看。
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.Date
、Calendar
和SimpleDateFormat
。
Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。
要了解更多信息,请参阅 Oracle 教程。并搜索堆栈溢出以获取许多示例和解释。规范为 JSR 310。
从哪里获得java.time类?
- Java SE
- 8、Java SE 9 及更高版本
- 内置。
- 具有捆绑实现的标准 Java API 的一部分。
- Java 9添加了一些小功能和修复。
Java SE - 6 和 Java SE 7
- 许多java.time功能在ThreeTen-Backport中向后移植到Java 6和7。
- 人造人
- java.time 类的 Android 捆绑包实现的更高版本。
- 对于早期的Android,ThreeTenABP项目适应了ThreeTen-Backport(如上所述)。请参阅如何使用ThreeTenABP...。
ThreeTen-Extra项目通过额外的类扩展了java.time。这个项目是未来可能添加到java.time的试验场。你可以在这里找到一些有用的类,如Interval
、YearWeek
、YearQuarter
等。