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

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

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

String中没有指定用于解析date的时区。我想设置date对象的特定时区。

我该怎么做?


使用dateformat。例如,

1
2
3
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");


在意识到java.util.Date对象不包含任何信息的时区的时区设置的时候,你无法在一Date对象。唯一使Date对象包含一个数是一个"时代"milliseconds自1970年1月,00:00:00 UTC。

编码器为ZZ的节目,你在DateFormat对象设置时区和时区,告诉它你想显示日期和时间。


DR

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

Ok.

1
2
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.

J.U.日期无时区

如其他正确答案所述,java.util.date没有时区?。表示UTC/GMT(无时区偏移)。非常令人困惑,因为它的toString方法在生成字符串表示时应用了JVM的默认时区。好的。避免J.U.D.日期

出于这一点和许多其他原因,您应该避免使用内置的java.util.date&;calendar&java.text.simpledateformat。他们是出了名的麻烦事。好的。

取而代之的是使用Java 8捆绑的JavaTimePayes。好的。Java.时间

java.time类可以用三种方式表示时间线上的某个时刻:好的。

  • UTC(Instant)
  • 带偏移(OffsetDateTimeZoneOffset)
  • 带时区(ZonedDateTimeZoneId)

Instant

在java.time中,基本的构建块是Instant,这是UTC时间线上的一个时刻。使用Instant对象处理大部分业务逻辑。好的。

1
Instant instant = Instant.now();

OffsetDateTime

应用从UTC的偏移量以调整到某个位置的墙上时钟时间。好的。

应用ZoneOffset获得OffsetDateTime。好的。

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

ZonedDateTime

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

ZoneId应用于Instant以获得ZonedDateTime。始终指定正确的时区名称。不要使用3-4个既不独特也不标准的缩写,如ESTIST。好的。

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

LocalDateTime

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

如果您确定要使用的时区,请指定一个ZoneId来生成一个ZonedDateTime。请参见上面TL;DR部分的代码示例。好的。格式化字符串

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

1
2
3
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]

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

JavaTimeFr框架是在Java 8和之后构建的。这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat。好的。

现在处于维护模式的joda time项目建议迁移到java.time类。好的。

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

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

在哪里获取java.time类?好的。

  • JavaSE 8、Java SE 9、Java SE 10、Java SE 11,以及后来的标准JAVA API的一部分,实现了捆绑式实现。
    • Java 9添加了一些小的特性和修复。
  • Java SE 6和Java SE 7
    • 大多数JavaTimeActudio的功能都被移植到TealEnter后端的Java 6和7中。
  • 安卓
    • java.time类的Android包实现的更高版本。
    • 对于早期的Android(<26),threetenabp项目适应threeten backport(如上所述)。看看如何使用三连珠……

threeten额外项目使用额外的类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。好的。乔达时间

虽然Joda Time仍在积极维护,但它的制造商告诉我们,只要方便,就可以迁移到java.time。我保留这一部分作为参考,但我建议使用上面的java.time部分。好的。

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

1
2
3
4
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 );

调用toString方法生成ISO 8601格式的字符串。好的。

1
String output = dateTimeIndia.toString();

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

如果需要,可以将joda time datetime转换为java.util.date。好的。

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

在stackoverflow中搜索"joda date",以找到更多的示例,其中一些非常详细。好的。

?实际上,java.util.date中嵌入了一个时区,用于某些内部函数(请参见有关此答案的注释)。但此内部时区不作为属性公开,因此无法设置。此内部时区不是toString方法在生成日期时间值的字符串表示时使用的时区;而是动态应用JVM的当前默认时区。所以,简而言之,我们经常说"J.U.Date没有时区"。迷惑?对。还有另一个避免这些劳累的老班的原因。好的。好啊。


所以你可以在JVM级别设置时区

1
2
3
4
5
6
7
8
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);

输出:

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


如果你必须与标准JDK类库,你可以只使用本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
 * Converts the given <wyn>date</wyn> from the <wyn>fromTimeZone</wyn> to the
 * <wyn>toTimeZone</wyn>.  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 <wyn>timeZone</wyn> from UTC, factoring in any
 * additional offset due to the time zone being in daylight savings time as of
 * the given <wyn>date</wyn>.
 * @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;
}

学分去本邮件。


java.util.Calendar是正常的方式来处理时使用的JDK类生产区。Apache Commons安切洛蒂继续替代/公用事业是有可能的位置。编辑的注母舰泽塔有我,我听到真的善的事情是Joda时间(虽然我没有用它自己)。


本代码是在程序中给我的工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    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);

转换日期字符串simpledateformat做它。

1
2
3
4
5
    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);


如果任何人都需要这个,如果你需要可以XMLGregorianCalendarUTC时区和时区的电流,那么所有你需要做的是设置一个呼叫toGregorianCalendar()0时区,然后它想在相同的时区,但Date知道如何转换它的你,那么你可以从那里得到的数据。。。。。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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());

结果:

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