java.util.Date
에서를 파싱 String
했지만 로컬 시간대를 date
객체 의 시간대로 설정하고 있습니다.
구문 분석 String
할 표준 시간대가 지정되지 않았습니다 Date
. date
개체 의 특정 시간대를 설정하고 싶습니다 .
어떻게해야합니까?
java.util.Date
에서를 파싱 String
했지만 로컬 시간대를 date
객체 의 시간대로 설정하고 있습니다.
구문 분석 String
할 표준 시간대가 지정되지 않았습니다 Date
. date
개체 의 특정 시간대를 설정하고 싶습니다 .
어떻게해야합니까?
답변:
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");
TimeZone.setDefault()
호출 하기 전에 해야합니다 getTime()
. JDK 1.8에서는을 Calendar.getTime()
호출합니다 return new Date(getTimeInMillis());
.
주의하십시오 java.util.Date
물체가 그 자체로 어떤 시간대 정보를 포함하지 않는다 - 당신이에 시간대를 설정할 수 없습니다 Date
객체입니다. Date
개체에 포함 된 유일한 것은 "epoch"이후 1970 년 1 월 1 일 00:00:00 UTC 이후의 밀리 초입니다.
ZZ 코더가 보여 주듯이, DateFormat
날짜와 시간을 표시 할 시간대를 알려주기 위해 객체 의 시간대를 설정합니다 .
long
이라는 필드가 거의 있습니다 fastTime
. Date.toString()
실제로이 Calendar
밀리 초 시간을 해석하기 위해 a 를 사용합니다 . 따라서를 인쇄 Date
하면 표준 시간대가있는 것으로 나타나고 해당 시간대를 설정하는 방법에 대한 이해하기 쉬운 질문이 있습니다.
… 문자열에서 파싱… 시간대가 지정되지 않았습니다… 특정 시간대를 설정하고 싶습니다
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.
다른 정답이 언급했듯이 java.util.Date에는 시간대 † 이 없습니다 . UTC / GMT (표준 시간대 오프셋 없음)를 나타냅니다 . toString
메소드가 문자열 표현을 생성 할 때 JVM의 기본 시간대를 적용 하기 때문에 매우 혼란 스럽습니다 .
이것과 다른 많은 이유로 인해 내장 java.util.Date & .Calendar & java.text.SimpleDateFormat을 사용하지 않아야합니다. 그들은 악명 높은 문제입니다.
대신 Java 8 과 함께 제공되는 java.time 패키지를 사용하십시오 .
java.time 클래스는 세 가지 방식으로 타임 라인의 순간을 나타낼 수 있습니다.
Instant
)OffsetDateTime
하여 ZoneOffset
)ZonedDateTime
와 ZoneId
)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) 과 같은 예외 처리 규칙 을 적용하는 것이 좋습니다 .
에 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.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에는 시간대가 없습니다”라고 말합니다. 혼란 스러운가? 예. 피곤한 구식 수업을 피해야 할 또 다른 이유.
BaseCalendar.Date cdate
설정되어 있으면 해당 속성에 저장됩니다 . 여기 에서 소스 코드를 살펴보십시오 . 을 호출하여 JVM의 기본 시간대를 변경하지 않으면 juDate 객체의 시간대를 설정할 수 없습니다 TimeZone.setDefault(TimeZone.getTimeZone("NEW_TIME_ZONE"));
. 따라서,이 시간대 오프셋이고, 당신은 사용되지 않는 방법 juDate.getTimezoneOffset를 호출하여 오프셋을 얻을 수있다 ()
toString
JVM의 현재 기본 시간대를 적용 하는 방법을 제외하고 ; 묻힌 시간대를 다시 무시합니다. 간결하게하기 위해 java.util.Date에는 시간대가 없습니다. Art와 마찬가지로 진실을 알려주는 거짓말입니다.
TimeZone.setDefault
, 당신은되어 있지 java.util.Date의 객체의 시간대를 설정 - Date 객체는 여전히 UTC에서 효과적으로 행동의 매장 시간대를 무시합니다. Date의 toString
방법에 영향을 미칩니다 . 기본값을 설정하면 일반적으로 호스트 운영 체제의 시간대로 설정되는 JVM의 기본 시간대가 변경됩니다. 이 호출은 해당 JVM에서 실행중인 모든 앱의 모든 스레드에있는 모든 코드에 영향을 미치며 실행 중에 즉시 수행되므로 권장되지 않습니다 . 무례하고 위험하기 때문에 그 부름은 최후의 수단으로 만 여겨 져야합니다.
equals
( hashcode
,, getTime
.. 에서 사용 ). equals
메소드를 살펴보면 getTime()
어떤 호출 getTimeImpl()
을 호출 normalize()
하고, cdate
속성이 정규화되지 않은 경우 호출 합니다 . 에 normalize()
있어서, 시간대의 경우 상태는 저장 시간대 정보에 기초하여 1970 년 이후 밀리 재 - 계산하면 마지막 cdate
이 실행되고있는 현재 JVM 환경의 시간대 다르다. (살펴보기 sun.util.calendar.AbstractCalendar getCalendarDate(long millis, CalendarDate date)
)
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
TimeZone.setDefault
은 전체 JVM에 영향을 미치며 다른 모든 객체와 스레드에 영향을 미치기 때문에 다소 과감합니다. SecurityManager로 실행중인 경우 더 많은 합병증을 포함한 자세한 내용은 이 답변 을 참조하십시오 . 더 많은 복잡성 추가 : 이 문제 는 이 질문 에서 논의 된 바와 같이 다양한 Java 버전에서 변경되었습니다 .
표준 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 에는 도움이 될만한 다른 대안 / 유틸리티가 있습니다. 편집 스폰지의 메모는 Joda-Time 에 대해 정말 좋은 소식을 들었습니다 (내가 직접 사용하지는 않았지만).
Period
, Duration
및 Interval
. 이러한 스팬 등의 비교 방법을 포함한다 contains
, abuts
, overlap
, 및 gap
. 그리고 PeriodFormatterBuilder
그러한 "15 년 8개월"와 같은 설명 문구를 구축 할 수 있습니다.
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);
누구든지이를 필요로하는 경우 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
이 코드는 내가 작업중 인 앱에서 도움이되었습니다.
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);