簡體   English   中英

如何設置 java.util.Date 的時區?

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

我從一個String中解析了一個java.util.Date ,但它將本地時區設置為date object 的時區。

解析DateString中未指定時區。 我想設置date object的特定時區。

我怎樣才能做到這一點?

使用日期格式。 例如,

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對象包含的唯一內容是自“紀元”(UTC 時間 1970 年 1 月 1 日 00:00:00)以來的毫秒數。

正如 ZZ Coder 所示,您在DateFormat對象上設置時區,以告訴它您希望在哪個時區顯示日期和時間。

tl;博士

...解析...從一個字符串...時區未指定...我想設置一個特定的時區

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.

juDate 中沒有時區

正如其他正確答案所述, java.util.Date 沒有時區 它代表UTC /GMT(無時區偏移)。 非常令人困惑,因為它的toString方法在生成 String 表示時應用了 JVM 的默認時區。

避免 juDate

出於這個原因和許多其他原因,您應該避免使用內置的 java.util.Date & .Calendar & java.text.SimpleDateFormat。 他們是出了名的麻煩。

而是使用與Java 8捆綁在一起的java.time 包

時間

java.time 類可以通過三種方式表示時間軸上的某個時刻:

  • UTC( Instant
  • 具有偏移( OffsetDateTimeZoneOffset
  • 帶時區( ZonedDateTimeZoneId

Instant

java.time 中,基本構建塊是Instant ,即 UTC 時間線上的一個時刻。 Instant對象用於您的大部分業務邏輯。

Instant instant = Instant.now();

OffsetDateTime

應用偏移 UTC以調整到某個地方的掛鍾時間

應用ZoneOffset以獲得OffsetDateTime

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

ZonedDateTime

更好的是應用時區、偏移量以及處理異常的規則,例如夏令時 (DST)

ZoneId應用於Instant以獲取ZonedDateTime 始終指定正確的時區名稱 切勿使用 3-4 個既不唯一也不標准化的縮寫,例如ESTIST

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

LocalDateTime

如果輸入字符串缺少任何偏移或區域指示符,則解析為LocalDateTime

如果您確定預期的時區,請分配ZoneId以生成ZonedDateTime 請參閱上面tl;dr部分中的代碼示例。

格式化字符串

對這三個類中的任何一個調用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]

對於其他格式,請使用DateTimeFormatter類。 通常最好讓該類使用用戶預期的人類語言和文化規范生成本地化格式。 或者您可以指定特定格式。


Java 中所有日期時間類型的表,包括現代的和傳統的


關於java.time

java.time框架內置於 Java 8 及更高版本中。 這些類取代麻煩的老傳統日期時間類,如java.util.DateCalendar ,和SimpleDateFormat

要了解更多信息,請參閱Oracle 教程 並在 Stack Overflow 上搜索許多示例和解釋。 規范是JSR 310

現在處於維護模式Joda-Time項目建議遷移到java.time類。

您可以直接與您的數據庫交換java.time對象。 使用符合JDBC 4.2或更高版本的JDBC 驅動程序 不需要字符串,不需要java.sql.*類。 Hibernate 5 & JPA 2.2 支持java.time

從哪里獲得 java.time 類?


喬達時間

雖然Joda-Time仍然在積極維護,但它的制造商告訴我們盡快遷移到 java.time。 我將此部分完整作為參考,但我建議使用上面的java.time部分。

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 );

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

String output = dateTimeIndia.toString();

Joda-Time 還提供了生成各種其他字符串格式的豐富功能。

如果需要,您可以將 Joda-Time DateTime 轉換為 java.util.Date。

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

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


其實嵌入java.util.Date一個時區,用於一些內部功能(請參閱本答案的評論)。 但是這個內部時區沒有作為屬性公開,也不能設置。 這個內部時區不是toString方法在生成日期時間值的字符串表示中使用的時區; 相反,JVM 的當前默認時區是即時應用的。 所以,作為速記,我們常說“juDate 沒有時區”。 令人困惑? 是的。 避免這些疲憊的舊課程的另一個原因。

您還可以在 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);

輸出:

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

如果你必須只使用標准的 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;
}

歸功於這篇文章

java.util.Calendar是僅使用 JDK 類處理時區的常用方法。 Apache Commons有一些可能有用的其他替代方案/實用程序。 編輯Spong 的筆記提醒我,我聽說過關於Joda-Time 的好消息(盡管我自己沒有使用過)。

將日期轉換為字符串並使用 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);

此代碼對我正在開發的應用程序很有幫助:

    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);

在這里,您可以獲取“2020-03-11T20:16:17”之類的日期並返回“11/Mar/2020 - 20:16”

 private String transformLocalDateTimeBrazillianUTC(String dateJson) throws  ParseException {
    String localDateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss";
    SimpleDateFormat formatInput = new SimpleDateFormat(localDateTimeFormat);

    //Here is will set the time zone
    formatInput.setTimeZone(TimeZone.getTimeZone("UTC-03"));

    String brazilianFormat = "dd/MMM/yyyy - HH:mm";
    SimpleDateFormat formatOutput = new SimpleDateFormat(brazilianFormat);
    Date date = formatInput.parse(dateJson);
    return formatOutput.format(date);
}

如果有人需要這個,如果您需要將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());

結果:

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

這個答案可能是最短的,它只使用 Date 類:

long current = new Date().getTime() + 3_600_000;              //e.g. your JVM time zone +1 hour (3600000 milliseconds)
System.out.printf("%1$td.%1$tm.%1$tY %1$tH:%1$tM\n", current);//european time format

但是,如果可以,請使用更現代的方法來做同樣的事情。

package org.example;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class time {
   public static void main(String[] args) {
       SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd HH:mm");
       sdf.setTimeZone(TimeZone.getTimeZone("Asia/Jakarta"));
       Date date=new Date();
       sdf.format(date);
       System.out.println(sdf.format(date));
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM