如何设置 java.util.Date 的时区?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2891361/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 14:07:30  来源:igfitidea点击:

How to set time zone of a java.util.Date?

javadatetimezonejava.util.date

提问by Yatendra Goel

I have parsed a java.util.Datefrom a Stringbut it is setting the local time zone as the time zone of the dateobject.

我已经java.util.Date从 a解析了aString但它将本地时区设置为date对象的时区。

The time zone is not specified in the Stringfrom which Dateis parsed. I want to set a specific time zone of the dateobject.

解析的String来源中未指定时区Date。我想设置date对象的特定时区。

How can I do that?

我怎样才能做到这一点?

采纳答案by ZZ Coder

Use DateFormat. For example,

使用日期格式。例如,

SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");

回答by T.J. Crowder

java.util.Calendaris the usual way to handle time zones using just JDK classes. Apache Commonshas some further alternatives/utilities that may be helpful. EditSpong's note reminded me that I've heard really good things about Joda-Time(though I haven't used it myself).

java.util.Calendar是仅使用 JDK 类处理时区的常用方法。Apache Commons有一些可能有用的其他替代方案/实用程序。EditSpong 的笔记提醒我,我听说过关于Joda-Time 的好消息(尽管我自己没有使用过)。

回答by Jesper

Be aware that java.util.Dateobjects do not contain any timezone information by themselves - you cannot set the timezone on a Dateobject. The only thing that a Dateobject contains is a number of milliseconds since the "epoch" - 1 January 1970, 00:00:00 UTC.

请注意,java.util.Date对象本身不包含任何时区信息 - 您不能在Date对象上设置时区。Date对象包含的唯一内容是自“纪元”(UTC 时间 1970 年 1 月 1 日 00:00:00)以来的毫秒数。

As ZZ Coder shows, you set the timezone on the DateFormatobject, to tell it in which timezone you want to display the date and time.

正如 ZZ Coder 所示,您在DateFormat对象上设置时区,以告诉它您希望在哪个时区显示日期和时间。

回答by starmer

You could also set the timezone at the JVM level

您还可以在 JVM 级别设置时区

Date date1 = new Date();
System.out.println(date1);

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// or pass in a command line arg: -Duser.timezone="UTC"

Date date2 = new Date();
System.out.println(date2);

output:

输出:

Thu Sep 05 10:11:12 EDT 2013
Thu Sep 05 14:11:12 UTC 2013

回答by Basil Bourque

tl;dr

tl;博士

…parsed … from a String … time zone is not specified … I want to set a specific time zone

...解析...从一个字符串...时区未指定...我想设置一个特定的时区

LocalDateTime.parse( "2018-01-23T01:23:45.123456789" )  // Parse string, lacking an offset-from-UTC and lacking a time zone, as a `LocalDateTime`.
    .atZone( ZoneId.of( "Africa/Tunis" ) )              // Assign the time zone for which you are certain this date-time was intended. Instantiates a `ZonedDateTime` object.

No Time Zone in j.u.Date

juDate 中没有时区

As the other correct answers stated, a java.util.Date has no time zone?. It represents UTC/GMT (no time zone offset). Very confusing because its toStringmethod applies the JVM's default time zone when generating a String representation.

正如其他正确答案所述, java.util.Date 没有时区. 它代表UTC/GMT(无时区偏移)。非常令人困惑,因为它的toString方法在生成 String 表示时应用了 JVM 的默认时区。

Avoid j.u.Date

避免 juDate

For this and many other reasons, you should avoid using the built-in java.util.Date & .Calendar & java.text.SimpleDateFormat. They are notoriously troublesome.

出于这个原因和许多其他原因,您应该避免使用内置的 java.util.Date & .Calendar & java.text.SimpleDateFormat。他们是出了名的麻烦。

Instead use the java.time packagebundled with Java 8.

而是使用与Java 8捆绑在一起的java.time 包

java.time

时间

The java.time classes can represent a moment on the timeline in three ways:

java.time 类可以通过三种方式表示时间轴上的某个时刻:

  • UTC (Instant)
  • With an offset (OffsetDateTimewith ZoneOffset)
  • With a time zone (ZonedDateTimewith ZoneId)
  • 协调世界时 ( Instant)
  • 带有偏移量 ( OffsetDateTimewith ZoneOffset)
  • 带时区(ZonedDateTimeZoneId

Instant

Instant

In java.time, the basic building block is Instant, a moment on the time line in UTC. Use Instantobjects for much of your business logic.

java.time 中,基本构建块是InstantUTC 时间线上的一个时刻。将Instant对象用于您的大部分业务逻辑。

Instant instant = Instant.now();

OffsetDateTime

OffsetDateTime

Apply an offset-from-UTCto adjust into some locality's wall-clock time.

应用偏移 UTC以调整到某个地方的挂钟时间

Apply a ZoneOffsetto get an OffsetDateTime.

申请 aZoneOffset以获得OffsetDateTime.

ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );

ZonedDateTime

ZonedDateTime

Better is to apply a time zone, an offset plusthe rules for handling anomalies such as Daylight Saving Time (DST).

更好的是应用时区、偏移量以及处理异常的规则,例如夏令时 (DST)

Apply a ZoneIdto an Instantto get a ZonedDateTime. Always specify a proper time zone name. Never use 3-4 abbreviations such as ESTor ISTthat are neither unique nor standardized.

将 aZoneId应用于 anInstant以获得 a ZonedDateTime。始终指定正确的时区名称。切勿使用 3-4 个既不唯一也不标准化的缩写,例如ESTIST

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

LocalDateTime

LocalDateTime

If the input string lacked any indicator of offset or zone, parse as a LocalDateTime.

如果输入字符串缺少任何偏移或区域指示符,则解析为LocalDateTime.

If you are certain of the intended time zone, assign a ZoneIdto produce a ZonedDateTime. See code example above in tl;drsection at top.

如果您确定预期的时区,请分配 aZoneId以生成ZonedDateTime. 请参阅上面的tl;dr部分中的代码示例。

Formatted Strings

格式化字符串

Call the toStringmethod on any of these three classes to generate a String representing the date-time value in standard ISO 8601format. The ZonedDateTimeclass extends standard format by appending the name of the time zone in brackets.

toString对这三个类中的任何一个调用该方法,以生成一个表示标准ISO 8601格式的日期时间值的字符串。该ZonedDateTime班通过附加括号中的时区的名称,扩展了标准格式。

String outputInstant = instant.toString(); // Ex: 2011-12-03T10:15:30Z
String outputOdt = odt.toString(); // Ex: 2007-12-03T10:15:30+01:00
String outputZdt = zdt.toString(); // Ex: 2007-12-03T10:15:30+01:00[Europe/Paris]

For other formats use the DateTimeFormatterclass. Generally best to let that class generate localized formats using the user's expected human language and cultural norms. Or you can specify a particular format.

对于其他格式,请使用DateTimeFormatter该类。通常最好让该类使用用户预期的人类语言和文化规范生成本地化格式。或者您可以指定特定格式。



Table of all date-time types in Java, both modern and legacy

Java 中所有日期时间类型的表,包括现代的和传统的



About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

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

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

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

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多



Joda-Time

乔达时间

While Joda-Timeis still actively maintained, its makers have told us to migrate to java.time as soon as is convenient. I leave this section intact as a reference, but I suggest using the java.timesection above instead.

虽然Joda-Time仍然在积极维护,但它的制造商告诉我们尽快迁移到 java.time。我将此部分完整作为参考,但我建议使用java.time上面的部分。

In Joda-Time, a date-time object (DateTime) truly does know its assigned time zone. That means an offset from UTC andthe rules and history of that time zone's Daylight Saving Time (DST) and other such anomalies.

Joda-Time 中,日期时间对象 ( DateTime) 确实知道其分配的时区。这意味着与 UTC以及该时区夏令时 (DST) 和其他此类异常的规则和历史的偏移。

String input = "2014-01-02T03:04:05";
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeIndia = new DateTime( input, timeZone );
DateTime dateTimeUtcGmt = dateTimeIndia.withZone( DateTimeZone.UTC );

Call the toStringmethod to generate a String in ISO 8601format.

调用该toString方法以生成ISO 8601格式的 String 。

String output = dateTimeIndia.toString();

Joda-Time also offers rich capabilities for generating all kinds of other String formats.

Joda-Time 还提供了用于生成各种其他字符串格式的丰富功能。

If required, you can convert from Joda-Time DateTime to a java.util.Date.

如果需要,您可以将 Joda-Time DateTime 转换为 java.util.Date。

Java.util.Date date = dateTimeIndia.toDate();

Search StackOverflow for "joda date" to find many more examples, some quite detailed.

在 StackOverflow 中搜索“joda date”以找到更多示例,其中一些非常详细。



?Actually there isa time zone embedded in a java.util.Date, used for some internal functions (see comments on this Answer). But this internal time zone is not exposed as a property, and cannot be set. This internal time zone is notthe one used by the toStringmethod in generating a string representation of the date-time value; instead the JVM's current default time zone is applied on-the-fly. So, as shorthand, we often say “j.u.Date has no time zone”. Confusing? Yes. Yet another reason to avoid these tired old classes.

? 其实有嵌入在java.util.Date一个时区,用于一些内部功能(请参阅本答案的评论)。但是这个内部时区没有作为属性公开,也不能设置。该内部时区不是toString方法用于生成日期时间值的字符串表示形式的时区;相反,JVM 的当前默认时区是即时应用的。所以,作为速记,我们常说“juDate 没有时区”。令人困惑?是的。避免这些疲惫的旧课程的另一个原因。

回答by diadyne

If you must work with only standard JDK classes you can use this:

如果你必须只使用标准的 JDK 类,你可以使用这个:

/**
 * Converts the given <code>date</code> from the <code>fromTimeZone</code> to the
 * <code>toTimeZone</code>.  Since java.util.Date has does not really store time zome
 * information, this actually converts the date to the date that it would be in the
 * other time zone.
 * @param date
 * @param fromTimeZone
 * @param toTimeZone
 * @return
 */
public static Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone)
{
    long fromTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, fromTimeZone);
    long toTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, toTimeZone);

    return new Date(date.getTime() + (toTimeZoneOffset - fromTimeZoneOffset));
}

/**
 * Calculates the offset of the <code>timeZone</code> from UTC, factoring in any
 * additional offset due to the time zone being in daylight savings time as of
 * the given <code>date</code>.
 * @param date
 * @param timeZone
 * @return
 */
private static long getTimeZoneUTCAndDSTOffset(Date date, TimeZone timeZone)
{
    long timeZoneDSTOffset = 0;
    if(timeZone.inDaylightTime(date))
    {
        timeZoneDSTOffset = timeZone.getDSTSavings();
    }

    return timeZone.getRawOffset() + timeZoneDSTOffset;
}

Credit goes to this post.

归功于这篇文章

回答by EpicPandaForce

If anyone ever needs this, if you need to convert an XMLGregorianCalendartimezone to your current timezone from UTC, then all you need to do is set the timezone to 0, then call toGregorianCalendar()- it will stay the same timezone, but the Dateknows how to convert it to yours, so you can get the data from there.

如果有人需要这个,如果您需要将XMLGregorianCalendar时区从 UTC转换为当前时区,那么您需要做的就是将时区设置为0,然后调用toGregorianCalendar()- 它将保持相同的时区,但Date知道如何将其转换为你的,所以你可以从那里获取数据。

XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(
        ((GregorianCalendar)GregorianCalendar.getInstance());
xmlStartTime.setTimezone(0);
GregorianCalendar startCalendar = xmlStartTime.toGregorianCalendar();
Date startDate = startCalendar.getTime();
XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(startCalendar);
xmlStartTime.setHour(startDate.getHours());
xmlStartTime.setDay(startDate.getDate());
xmlStartTime.setMinute(startDate.getMinutes());
xmlStartTime.setMonth(startDate.getMonth()+1);
xmlStartTime.setTimezone(-startDate.getTimezoneOffset());
xmlStartTime.setSecond(startDate.getSeconds());
xmlStartTime.setYear(startDate.getYear() + 1900);
System.out.println(xmlStartTime.toString());

Result:

结果:

2015-08-26T12:02:27.183Z
2015-08-26T14:02:27.183+02:00

回答by avisper

Convert the Date to String and do it with SimpleDateFormat.

将日期转换为字符串并使用 SimpleDateFormat 来完成。

    SimpleDateFormat readFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    readFormat.setTimeZone(TimeZone.getTimeZone("GMT" + timezoneOffset));
    String dateStr = readFormat.format(date);
    SimpleDateFormat writeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    Date date = writeFormat.parse(dateStr);

回答by VikR

This code was helpful in an app I'm working on:

此代码对我正在开发的应用程序很有帮助:

    Instant date = null;
    Date sdf = null;
    String formatTemplate = "EEE MMM dd yyyy HH:mm:ss";
    try {
        SimpleDateFormat isoFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss");
        isoFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("US/Pacific")));
        sdf = isoFormat.parse(timeAtWhichToMakeAvailable);
        date = sdf.toInstant();

    } catch (Exception e) {
        System.out.println("did not parse: " + timeAtWhichToMakeAvailable);
    }

    LOGGER.info("timeAtWhichToMakeAvailable: " + timeAtWhichToMakeAvailable);
    LOGGER.info("sdf: " + sdf);
    LOGGER.info("parsed to: " + date);