java.util.Date의 시간대를 설정하는 방법은 무엇입니까?


225

java.util.Date에서를 파싱 String했지만 로컬 시간대를 date객체 의 시간대로 설정하고 있습니다.

구문 분석 String할 표준 시간대가 지정되지 않았습니다 Date. date개체 의 특정 시간대를 설정하고 싶습니다 .

어떻게해야합니까?


8
귀하의 질문에 대한 답변은 아니지만 여기에 몇 번 언급 된 후 Joda Time을 사용했습니다. 표준 API보다 나에게 더 합리적이며 이런 종류의 일을 아주 쉽게 할 수 있습니다.
clstrfsck

2
@msandiford 요즘에는 Joda-Time 대신 java.time 클래스를 사용 하십시오 . Joda 타임 프로젝트에 지금 유지 관리 모드 받는 마이그레이션을 조언 팀과 함께, java.time의 클래스. Oracle의 Tutorial을 참조하십시오 .
Basil Bourque

답변:


315

DateFormat을 사용하십시오. 예를 들어

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

6
달력 클래스에서 날짜를 만든 경우 달력의 시간대를 설정할 수 있습니다.
lwpro2

19
@ lwpro2 그 진술은 잘못된 것입니다. Calendar 객체의 시간대를 설정할 수 있지만 getTime () 메서드를 사용하여 Date 객체를 가져 오면 호스트 컴퓨터의 시간대와 함께 Date 객체가 반환됩니다.
BrDaHa

02/20/15 14:44를 구문 분석하는 데 문제가 있습니다. 누구든지 도울 수 있습니까
MS

@BrDaHa가 정확 합니다. 새 날짜 개체가 원하는 시간대에 있도록 TimeZone.setDefault()호출 하기 전에 해야합니다 getTime(). JDK 1.8에서는을 Calendar.getTime()호출합니다 return new Date(getTimeInMillis());.
jpllosa

182

주의하십시오 java.util.Date물체가 그 자체로 어떤 시간대 정보를 포함하지 않는다 - 당신이에 시간대를 설정할 수 없습니다 Date객체입니다. Date개체에 포함 된 유일한 것은 "epoch"이후 1970 년 1 월 1 일 00:00:00 UTC 이후의 밀리 초입니다.

ZZ 코더가 보여 주듯이, DateFormat날짜와 시간을 표시 할 시간대를 알려주기 위해 객체 의 시간대를 설정합니다 .


77
인터넷 검색, 실험 및 설명을 마친 후에는 이것이 답과 가치있는 강조 사항에 정확하고 도움이되는 추가 사항이라는 것을 깨달았습니다. 날짜 에는 밀리 초 값 포함 됩니다. 소스를 보면 long이라는 필드가 거의 있습니다 fastTime. Date.toString()실제로이 Calendar밀리 초 시간을 해석하기 위해 a 를 사용합니다 . 따라서를 인쇄 Date하면 표준 시간대가있는 것으로 나타나고 해당 시간대를 설정하는 방법에 대한 이해하기 쉬운 질문이 있습니다.
David Carboni

3
Date 객체 내에 표준 시간대 정보가 있습니다. 그러나 사실 일 수도 있지만 변경할 수 없습니다.
lwpro2

3
@ Iwpro2, Jesper는 Date 객체가 표준 시간대를 저장하지 않는다고 주장합니다. 시간대가 java.util.Date에 저장되어 있다고 주장하는 경우 참조를 제공하십시오.
Jim

6
@Jim, 이것은 java.util.Date의 소스 코드입니다. 여기에는 fastTime과 유닉스 시대로 정의 된 BaseCalendar.Date cdate가 포함되어 있습니다. 여기에는 시간대 정보가 포함되어 있습니다. Date 인스턴스에 시간대 정보가 포함될 수 있지만 이해할 수는 없습니다.
eis

2
@Jim 나는 당신이 그것을 설정할 수 있다고 말하지 않았다. 사용자로 설정하는 방법이 없습니다. OP는 항상 사용자 / 시스템 기본 시간대 인 것처럼 보입니다.
eis

95

tl; dr

… 문자열에서 파싱… 시간대가 지정되지 않았습니다… 특정 시간대를 설정하고 싶습니다

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메소드가 문자열 표현을 생성 할 때 JVM의 기본 시간대를 적용 하기 때문에 매우 혼란 스럽습니다 .

사법을 피하십시오

이것과 다른 많은 이유로 인해 내장 java.util.Date & .Calendar & java.text.SimpleDateFormat을 사용하지 않아야합니다. 그들은 악명 높은 문제입니다.

대신 Java 8 과 함께 제공되는 java.time 패키지를 사용하십시오 .

java.time

java.time 클래스는 세 가지 방식으로 타임 라인의 순간을 나타낼 수 있습니다.

  • UTC ( Instant)
  • (오프셋 OffsetDateTime하여 ZoneOffset)
  • 시간 영역과 ( ZonedDateTimeZoneId)

Instant

에서 java.time , 기본 빌딩 블록은 InstantUTC의 타임 라인에 순간. Instant많은 비즈니스 로직에 객체를 사용하십시오 .

Instant instant = Instant.now();

OffsetDateTime

UTC오프셋을 적용하여 일부 지역의 벽시계 시간 을 조정하십시오 .

를 적용 ZoneOffset하려면을 적용하십시오 OffsetDateTime.

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

ZonedDateTime

표준 시간대 , 오프셋 일광 절약 시간 (DST) 과 같은 예외 처리 규칙 을 적용하는 것이 좋습니다 .

에 a ZoneId를 적용하여 a 을 Instant얻습니다 ZonedDateTime. 항상 올바른 시간대 이름을 지정하십시오 . 안 등 3 ~ 4 약어를 사용하지 EST또는 IST도 독특한도 표준화됩니다.

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

LocalDateTime

입력 문자열에 오프셋 또는 영역 표시기가없는 경우 a로 구문 분석하십시오 LocalDateTime.

원하는 시간대를 확신 할 수있는 경우 a 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의 프레임 워크는 나중에 자바 8에 내장되어 있습니다. 이 클래스는 까다로운 기존에 대신 기존 과 같은 날짜 - 시간의 수업을 java.util.Date, Calendar, SimpleDateFormat.

Joda 타임 프로젝트는 지금에 유지 관리 모드 의로 마이그레이션을 조언 java.time의 클래스.

자세한 내용은 Oracle Tutorial을 참조하십시오 . 많은 예제와 설명을 보려면 스택 오버플로를 검색하십시오. 사양은 JSR 310 입니다.

java.time 객체를 데이터베이스와 직접 교환 할 수 있습니다 . JDBC 4.2 이상을 준수 하는 JDBC 드라이버를 사용하십시오 . 문자열이 필요없고 수업이 필요 없습니다 .java.sql.*

java.time 클래스는 어디서 구할 수 있습니까?

ThreeTen - 추가 프로젝트 추가 클래스와 java.time를 확장합니다. 이 프로젝트는 향후 java.time에 추가 될 수있는 입증 된 근거입니다. 당신은 여기에 몇 가지 유용한 클래스와 같은 찾을 수 있습니다 Interval, YearWeek, YearQuarter, 그리고 .


조다 타임

하지만 Joda 타임은 여전히 활발하게 유지되고, 그 업체는 빨리 편리으로 java.time로 마이그레이션라고 우리에게 이야기했다. 이 섹션은 참조로 그대로두고 java.time위 의 섹션을 대신 사용하는 것이 좋습니다 .

Joda-시간 , 날짜 - 시간 객체 ( 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();

"joda date"에 대한 StackOverflow를 검색하여 더 많은 예를 찾으십시오.


사실이 있다 몇 가지 내부 기능에 사용되는 java.util.Date에 포함 된 시간대가 (이 답변에 대한 의견을 참조). 그러나이 내부 시간대는 속성으로 노출되지 않으므로 설정할 수 없습니다. 이 내부 시간대는 날짜-시간 값의 문자열 표현을 생성하는 방법에서 사용되는 시간대가 아닙니다toString . 대신 JVM의 현재 기본 시간대가 즉시 적용됩니다. 간단히 말해서“juDate에는 시간대가 없습니다”라고 말합니다. 혼란 스러운가? 예. 피곤한 구식 수업을 피해야 할 또 다른 이유.


3
"juDate에 시간대 없음"이 잘못되었습니다. juDate에 시간대 정보가 BaseCalendar.Date cdate설정되어 있으면 해당 속성에 저장됩니다 . 여기 에서 소스 코드를 살펴보십시오 . 을 호출하여 JVM의 기본 시간대를 변경하지 않으면 juDate 객체의 시간대를 설정할 수 없습니다 TimeZone.setDefault(TimeZone.getTimeZone("NEW_TIME_ZONE"));. 따라서,이 시간대 오프셋이고, 당신은 사용되지 않는 방법 juDate.getTimezoneOffset를 호출하여 오프셋을 얻을 수있다 ()
타이어 부이

3
@blquythai 맞아, 숙제를 했어. 이전과 마찬가지로 소스 코드를 본 적이 있습니다. 거기 시간대가 묻혀 있습니다. 그러나 모든 실제적인 목적으로 시간대는 무시됩니다. java.util.Date는 표준 시간대없이 작동하며, 실제로는 묻혀있는 표준 시간대를 무시하면서 UTC로되어 있습니다. toStringJVM의 현재 기본 시간대를 적용 하는 방법을 제외하고 ; 묻힌 시간대를 다시 무시합니다. 간결하게하기 위해 java.util.Date에는 시간대가 없습니다. Art와 마찬가지로 진실을 알려주는 거짓말입니다.
Basil Bourque

@blquythai으로는 호출을 위해 TimeZone.setDefault, 당신은되어 있지 java.util.Date의 객체의 시간대를 설정 - Date 객체는 여전히 UTC에서 효과적으로 행동의 매장 시간대를 무시합니다. Date의 toString방법에 영향을 미칩니다 . 기본값을 설정하면 일반적으로 호스트 운영 체제의 시간대로 설정되는 JVM의 기본 시간대가 변경됩니다. 이 호출은 해당 JVM에서 실행중인 모든 앱의 모든 스레드에있는 모든 코드에 영향을 미치며 실행 중에 즉시 수행되므로 권장되지 않습니다 . 무례하고 위험하기 때문에 그 부름은 최후의 수단으로 만 여겨 져야합니다.
Basil Bourque

5
해당 시간대는 매우 자주 사용됩니다 equals( hashcode,, getTime.. 에서 사용 ). equals메소드를 살펴보면 getTime()어떤 호출 getTimeImpl()을 호출 normalize()하고, cdate속성이 정규화되지 않은 경우 호출 합니다 . 에 normalize()있어서, 시간대의 경우 상태는 저장 시간대 정보에 기초하여 1970 년 이후 밀리 재 - 계산하면 마지막 cdate이 실행되고있는 현재 JVM 환경의 시간대 다르다. (살펴보기 sun.util.calendar.AbstractCalendar getCalendarDate(long millis, CalendarDate date))
Thai Bui

2
@MichalM 당신의 조언에 따라, 얼마 전에 나는 임베디드 영역에 대한 여론을 추가했습니다.
Basil Bourque

75

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

이것은 나를 도왔다. SDF에서 timeZone을 설정하면 차이가 발생하지 않습니다
vishnu viswanath

더 신뢰할 수 있다고 생각합니다. (+1)
foobar

23
주의 : 호출 TimeZone.setDefault은 전체 JVM에 영향을 미치며 다른 모든 객체와 스레드에 영향을 미치기 때문에 다소 과감합니다. SecurityManager로 실행중인 경우 더 많은 합병증을 포함한 자세한 내용은 이 답변 을 참조하십시오 . 더 많은 복잡성 추가 : 이 문제이 질문 에서 논의 된 바와 같이 다양한 Java 버전에서 변경되었습니다 .
Basil Bourque

이렇게하면이 문장 다음에 생성 된 모든 스레드에서 공통 시간대가 설정됩니다.
Jaydev

이것은 수락 된 것보다 질문에 대한 더 나은 대답입니다.
francogrex

10

표준 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;
}

크레딧은이 게시물 로 이동합니다 .


1
시간대의 오프셋이 항상 일정하지는 않습니다. 실제로 지정 학적 이유로 인해 변경 될 수 있습니다. TimeZone.getDSTSavings ()는 이것을 고려하지 않고 항상 현재 오프셋을 반환합니다 . 이는 해당 날짜 이후 오프셋이 변경된 fromTimeZone / toTimeZone으로 기록 날짜를 처리하는 경우 잘못된 변환을받을 수 있음을 의미합니다.
andrerobot

6

java.util.CalendarJDK 클래스 만 사용하여 표준 시간대를 처리하는 일반적인 방법입니다. Apache Commons 에는 도움이 될만한 다른 대안 / 유틸리티가 있습니다. 편집 스폰지의 메모는 Joda-Time 에 대해 정말 좋은 소식을 들었습니다 (내가 직접 사용하지는 않았지만).


Joda Time의 +1 표준 Java API에서 얻을 수없는 추가 기능을 제공하지는 않지만 (어떤 경우에도 발견되어 기쁘다) Joda Time은 일부 작업을 더 쉽게 만듭니다.
Joshua Hutchison

2
@JoshuaHutchison Joda-Time에는 수많은 추가 기능이 있습니다. 예 : 클래스와 시간의 지속 기간을 나타내는 Period, DurationInterval. 이러한 스팬 등의 비교 방법을 포함한다 contains, abuts, overlap, 및 gap. 그리고 PeriodFormatterBuilder그러한 "15 년 8개월"와 같은 설명 문구를 구축 할 수 있습니다.
Basil Bourque

1

Date를 String으로 변환하고 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);

1
스택 오버플로에 대한 답변은 토론이나 설명이 필요합니다. 이 사이트는 코드 스 니펫 라이브러리 이상입니다.
Basil Bourque

귀하의 의견에 대해 @Basil Bourque에게 감사드립니다. 나는 답을 편집한다
avisper

0

누구든지이를 필요로하는 경우 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

0

이 코드는 내가 작업중 인 앱에서 도움이되었습니다.

    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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.