Java를 사용하여 일정표 TimeZones를 처리하는 방법
응용 프로그램에서 가져온 타임스탬프 값이 있습니다.사용자는 임의의 로컬 TimeZone에 속할 수 있습니다.
이 날짜는 지정된 시간이 항상 GMT로 설정되어 있는 Web Service에 사용되므로 사용자의 파라미터를 예를 들어 (EST)에서 (GMT)로 변환해야 합니다.중요한 점은 다음과 같습니다.사용자는 자신의 TZ를 인식하지 못합니다.WS에 송신할 작성일을 입력합니다.따라서 필요한 것은 다음과 같습니다.
사용자 입력: 2008년 5월 1일 오후 6시 12분(EST)
WS의 파라미터는 5/1/2008 6:12 PM (GMT)이어야 합니다.
타임스탬프는 기본적으로 GMT에 있어야 하는데, 파라미터를 전송할 때 TS에서 캘린더를 작성했는데(GMT에 있어야 함) 사용자가 GMT에 있지 않는 한 영업시간이 항상 비어 있습니다.무엇이 누락되어 있습니까?
Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
...
private static java.util.Calendar convertTimestampToJavaCalendar(Timestamp ts_) {
java.util.Calendar cal = java.util.Calendar.getInstance(
GMT_TIMEZONE, EN_US_LOCALE);
cal.setTimeInMillis(ts_.getTime());
return cal;
}
이전 코드에서는 다음과 같은 결과를 얻을 수 있습니다(간단한 포맷으로 쉽게 읽을 수 있습니다).
[2008년 5월 1일 오후 11시 12분]
public static Calendar convertToGmt(Calendar cal) {
Date date = cal.getTime();
TimeZone tz = cal.getTimeZone();
log.debug("input calendar has date [" + date + "]");
//Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
long msFromEpochGmt = date.getTime();
//gives you the current offset in ms from GMT at the current date
int offsetFromUTC = tz.getOffset(msFromEpochGmt);
log.debug("offset is " + offsetFromUTC);
//create a new calendar in GMT timezone, set to this date and add the offset
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.setTime(date);
gmtCal.add(Calendar.MILLISECOND, offsetFromUTC);
log.debug("Created GMT cal with date [" + gmtCal.getTime() + "]");
return gmtCal;
}
('12:09:05 EDT'에서 12 EDT 때의 과 같습니다.Calendar.getInstance() 의 경우:
DEBUG - EDT 2008 debug debug10 - 23 ( ) 12 )12 : 09 : 05 EDT 2008 ]
DEBUG - 14400000 입 debug 。
- 목) 08 EDT - GMT cal [10월 23일(목) 08:09:05 EDT 2008]
12:09:05 GMT는 8:09:05 EDT입니다.
서 헷갈리는 은 '아까부터' 입니다.Calendar.getTime()를 돌려주다Date달력의 시간대를 수정하고 기본 날짜도 롤링할 수 없습니다.웹 서비스에서 사용하는 파라미터의 유형에 따라서는는 에폭으로부터의 밀리초 단위로 WS 거래를 할 수 있습니다.
답변해 주셔서 감사합니다.더 조사해 보니 정답이 나왔다Skip Head에서 언급했듯이, 어플리케이션에서 취득한 TimeStamped는 사용자의 TimeZone으로 조정되고 있었습니다.따라서 사용자가 오후 6시 12분(EST)을 입력하면 오후 2시 12분(GMT)이 표시됩니다.필요한 것은 사용자가 입력한 시간이 WebServer 요청으로 전송한 시간이 되도록 변환을 원래대로 되돌릴 수 있는 방법이었습니다.이를 실현한 방법은 다음과 같습니다.
// Get TimeZone of user
TimeZone currentTimeZone = sc_.getTimeZone();
Calendar currentDt = new GregorianCalendar(currentTimeZone, EN_US_LOCALE);
// Get the Offset from GMT taking DST into account
int gmtOffset = currentTimeZone.getOffset(
currentDt.get(Calendar.ERA),
currentDt.get(Calendar.YEAR),
currentDt.get(Calendar.MONTH),
currentDt.get(Calendar.DAY_OF_MONTH),
currentDt.get(Calendar.DAY_OF_WEEK),
currentDt.get(Calendar.MILLISECOND));
// convert to hours
gmtOffset = gmtOffset / (60*60*1000);
System.out.println("Current User's TimeZone: " + currentTimeZone.getID());
System.out.println("Current Offset from GMT (in hrs):" + gmtOffset);
// Get TS from User Input
Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
System.out.println("TS from ACP: " + issuedDate);
// Set TS into Calendar
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
// Adjust for GMT (note the offset negation)
issueDate.add(Calendar.HOUR_OF_DAY, -gmtOffset);
System.out.println("Calendar Date converted from TS using GMT and US_EN Locale: "
+ DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
.format(issueDate.getTime()));
코드 출력은 다음과 같습니다(사용자는 2008년 5월 1일 6시 12분 (EST)을 입력).
사용자의
GMT로부터의 전류 오프셋(시간 단위):-4(일반적으로 -5(DST 조정 제외)
ACP(영어) TS: 2008-05-01 14:12:00.0
및 로케일을 : 6 PM GMT 및 US_EN 、 US _ EN calendar TS calendar : 5 / 1 / 08 、 6:12 ( GMT )
웹 서비스와 관련하여 날짜를 사용한다고 하셨기 때문에, 어느 시점에서 문자열로 연재되고 있다고 생각합니다.
이 경우 DateFormat 클래스의 setTimeZone 메서드를 확인해야 합니다.타임스탬프를 인쇄할 때 사용할 시간대를 지정합니다.
간단한 예:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
Calendar cal = Calendar.getInstance();
String timestamp = formatter.format(cal.getTime());
Joda Time으로 해결할 수 있습니다.
Date utcDate = new Date(timezoneFrom.convertLocalToUTC(date.getTime(), false));
Date localDate = new Date(timezoneTo.convertUTCToLocal(utcDate.getTime()));
Java 8:
LocalDateTime localDateTime = LocalDateTime.parse("2007-12-03T10:15:30");
ZonedDateTime fromDateTime = localDateTime.atZone(
ZoneId.of("America/Toronto"));
ZonedDateTime toDateTime = fromDateTime.withZoneSameInstant(
ZoneId.of("Canada/Newfoundland"));
타임 스탬프가 원래 시스템의 타임 존으로 설정되어 있는 것 같습니다.
이는 권장되지 않지만 작동해야 합니다.
cal.setTimeInMillis(ts_.getTime() - ts_.getTimezoneOffset());
권장되지 않는 방법은
Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)
다만, 클라이언트측에서 실행할 필요가 있습니다.시스템이 타임존을 인식하고 있기 때문입니다.
1개의 타임존에서 다른 타임존으로 변환하는 방법(아마도 :이 동작합니다.
/**
* Adapt calendar to client time zone.
* @param calendar - adapting calendar
* @param timeZone - client time zone
* @return adapt calendar to client time zone
*/
public static Calendar convertCalendar(final Calendar calendar, final TimeZone timeZone) {
Calendar ret = new GregorianCalendar(timeZone);
ret.setTimeInMillis(calendar.getTimeInMillis() +
timeZone.getOffset(calendar.getTimeInMillis()) -
TimeZone.getDefault().getOffset(calendar.getTimeInMillis()));
ret.getTime();
return ret;
}
Date 객체와 Timestamp 객체는 타임존에 의존합니다.이 객체는 에폭 이후의 특정 초수를 나타냅니다.시간이나 일 등의 특정 해석을 커밋하지 않습니다.시간대는 GregorianCalendar(이 작업에 직접 필요하지 않음) 및 SimpleDateFormat에서만 그림을 입력합니다.이 경우 개별 필드와 날짜(또는 긴) 값 간에 변환하기 위해 시간대 오프셋이 필요합니다.
OP의 문제는 처리의 첫머리에 있습니다.사용자가 시간을 입력하는 것은 애매하고 GMT 이외의 로컬 타임존으로 해석됩니다.이 시점에서 값은 "6:12 EST"로 쉽게 인쇄되지만 "6.12 GMT"로 변경되지 않습니다.
대신에, 「06:12」를 「HH:MM」(로컬 타임 존의 디폴트)로 해석하는 SimpleDateFormat을 디폴트 UTC로 하는 방법은 없습니다.SimpleDateFormat은 그 자체로는 너무 스마트합니다.
그러나 SimpleDateFormat 인스턴스를 입력에 명시적으로 입력하면 올바른 시간대를 사용하도록 설득할 수 있습니다. 수신된 (적절하게 검증된) "06:12 GMT"에 고정 문자열을 추가하여 "06:12 GMT"를 "HH:MM z"로 구문 분석할 수 있습니다.
GregoryCalendar 필드의 명시적 설정이나 시간대 및 여름 시간 오프셋을 검색하여 사용할 필요가 없습니다.
진짜 문제는 로컬타임존에 기본 입력, UTC에 기본 입력 및 실제로 명시적인 타임존 표시가 필요한 입력을 구분하는 것입니다.
과거 사용자의 타임존과 GMT 사이의 오프셋(밀리초 단위)을 결정하는 것이 효과가 있었습니다.오프셋을 얻으면 (변환이 어느 방향으로 진행되느냐에 따라) 단순히 더하기/빼기만 하면 어느 시간대에서 적절한 시간을 얻을 수 있습니다.보통 캘린더 오브젝트의 밀리초필드를 설정하면 됩니다만, 타임스탬프 오브젝트에 간단하게 적용할 수 있을 것입니다.여기 오프셋을 얻기 위해 사용하는 코드가 있습니다.
int offset = TimeZone.getTimeZone(timezoneId).getRawOffset();
timezoneId는 사용자의 시간대 ID(EST 등)입니다.
java.time
최신 접근법에서는 Java의 초기 버전에 번들된 성가신 레거시 날짜 시간 클래스를 대체한 java.time 클래스를 사용합니다.
그java.sql.Timestampclass는 그 레거시 클래스 중 하나입니다.더 이상 필요 없습니다.대신 사용Instant또는 JDBC 4.2 이후를 사용하여 데이터베이스와 직접 다른 java.time 클래스를 만듭니다.
클래스는 타임라인상의 순간을 UTC로 나노초(10진수의 최대 9자리)의 분해능으로 나타냅니다.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
기존과 상호 운용할 필요가 있는 경우Timestamp이전 클래스에 추가된 새로운 변환 메서드를 통해 즉시 java.time으로 변환합니다.
Instant instant = myTimestamp.toInstant() ;
다른 표준시로 조정하려면 표준시를 다음과 같이 지정합니다.ZoneId물건.다음 형식으로 적절한 시간대 이름을 지정합니다.continent/region, , , 등Pacific/Auckland. 다음과 같은 3~4글자 유사존은 사용하지 마십시오.EST또는IST이는 진정한 표준 시간대가 아니며 표준화되지 않았으며 고유하지도 않기 때문입니다(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
에 적용하다Instant을 생산하다ZonedDateTime물건.
ZonedDateTime zdt = instant.atZone( z ) ;
사용자에게 표시할 문자열을 생성하려면 Stack Overflow를 검색합니다.DateTimeFormatter많은 토론과 사례를 찾을 수 있습니다.
질문은 사용자 데이터 입력에서 날짜 개체로 이동하는 다른 방향에 대한 것입니다.일반적으로 데이터 입력은 날짜와 시각의 두 부분으로 구분하는 것이 좋습니다.
LocalDate ld = LocalDate.parse( dateInput , DateTimeFormatter.ofPattern( "M/d/uuuu" , Locale.US ) ) ;
LocalTime lt = LocalTime.parse( timeInput , DateTimeFormatter.ofPattern( "H:m a" , Locale.US ) ) ;
질문이 명확하지 않습니다.사용자가 입력한 날짜와 시간을 UTC로 해석하시겠습니까?아니면 다른 시간대에?
의 는, UTC 를 합니다.OffsetDateTimeUTC, UTC의 합니다.ZoneOffset.UTC
OffsetDateTime odt = OffsetDateTime.of( ld , lt , ZoneOffset.UTC ) ;
와 함께 합니다.ZoneId지만어 어???기본 표준 시간대가 탐지될 수 있습니다.또는 중요한 경우 사용자에게 그 의도를 확인해야 합니다.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
내에 , 「UTC」를 합니다.Instant.
Instant instant = odt.toInstant() ;
…혹은…
Instant instant = zdt.toInstant() ;
데이터베이스로 전송합니다.
myPreparedStatement.setObject( … , instant ) ;
java.time 정보
java.time 프레임워크는 Java 8 이후에 포함되어 있습니다.이러한 클래스는 , 및 등 문제가 많은 오래된 레거시 날짜 시간 클래스를 대체합니다.
현재 유지보수 모드에 있는 Joda-Time 프로젝트는 java.time 클래스로의 이행을 권장합니다.
자세한 내용은 Oracle 자습서를 참조하십시오.또한 Stack Overflow를 검색하여 많은 예와 설명을 확인하십시오.사양은 JSR 310입니다.
java.time 클래스는 어디서 얻을 수 있습니까?
- 자바 SE 8, 자바 SE 9 이후
- 붙박이.
- 번들 구현이 포함된 표준 Java API의 일부입니다.
- Java 9에는 몇 가지 사소한 기능과 수정 사항이 추가되어 있습니다.
- 자바 SE 6 및 자바 SE 7
- java.time 기능의 대부분은 ThreeTen 백포트의 Java 6 및7로 백포트됩니다.
- 안드로이드
- 최신 버전의 Android 번들 구현 java.time 클래스.
- 이전의 Android에서는 쓰리텐ABP 프로젝트는 ThreeTen-Backport(상기)를 채택하고 있습니다.'쓰리텐ABP 사용방법'을 참조하십시오.
쓰리텐 엑스트라 프로젝트는 java.time을 추가 클래스로 확장합니다.이 프로젝트는 향후 java.time에 추가될 수 있는 가능성을 입증하는 기반입니다.여기에는 , , , 등 유용한 클래스가 있습니다.
언급URL : https://stackoverflow.com/questions/230126/how-to-handle-calendar-timezones-using-java
'source' 카테고리의 다른 글
| 정규식에서 이스케이프해야 하는 모든 특수 문자 목록 (0) | 2022.10.26 |
|---|---|
| PHP mySQL - 기본 키의 자동 증분으로 테이블에 새 레코드 삽입 (0) | 2022.10.26 |
| MariaDB는 어떤 종류의 SQL을 사용합니까? (0) | 2022.10.26 |
| 내부로 들어가는 방법DOMNode의 HTML? (0) | 2022.10.26 |
| PHP를 사용하여 MySQL datetime에서 다른 형식으로 변환 (0) | 2022.10.26 |