문제

응용 프로그램에서 오는 타임 스탬프 값이 있습니다. 사용자는 주어진 로컬 타임 존에있을 수 있습니다.

이 날짜는 주어진 시간이 항상 GMT에 있다고 가정하는 웹 서비스에 사용되므로 사용자의 매개 변수를 Say (EST)에서 (GMT)로 변환해야합니다. 키커는 다음과 같습니다. 사용자는 TZ를 잊어 버렸습니다. 그는 WS에 보내고 자하는 창조 날짜에 들어갑니다. 필요한 것은 다음과 같습니다.

사용자 입력 : 2008 년 5 월 1 일 오후 6:12 (EST)
WS에 대한 매개 변수는 필요합니다: 2008 년 5 월 1 일 오후 6:12 (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

도움이 되었습니까?

해결책 2

응답 해주셔서 감사합니다. 추가 조사 후 나는 정답에 도달했다. Skip Head에서 언급했듯이 응용 프로그램에서 얻은 타임 스탬프가 사용자의 시간대에 조정되었습니다. 따라서 사용자가 오후 6시 12 분 (EST)에 입력하면 오후 2시 12 분 (GMT)을받습니다. 내가 필요로하는 것은 변환을 취소하는 방법이었습니다. 사용자가 입력 한 시간은 웹 서버 요청으로 보낸 시간입니다. 내가 이것을 달성 한 방법은 다음과 같습니다.

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

현재 사용자의 시간대 : Est
GMT의 현재 오프셋 (HRS) : -4 (일반적으로 -5, DST 조정을 제외하고)
ACP의 TS : 2008-05-01 14 : 12 : 00.0
GMT 및 US_EN 로케일을 사용하여 T에서 변환 된 캘린더 날짜 : 5/1/08 6:12 PM (GMT)

다른 팁

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" Calendar.getInstance()) 안에:

디버그 - 입력 캘린더는 날짜가 있습니다 [THU 10 월 23 일 12:09:05 EDT 2008
디버그 - 오프셋은 -14400000입니다
디버그 - 날짜와 함께 생성 된 GMT CAL [THU 10 월 23 일 08:09:05 EDT 2008

12:09:05 GMT는 8:09:05 EDT입니다.

여기서 혼란스러운 부분은 그 것입니다 Calendar.getTime() 당신을 반환합니다 Date 현재 시간대에서는 달력의 시간대를 수정하고 기본 날짜도 롤링하는 방법이 없습니다. 웹 서비스가 취하는 매개 변수 유형에 따라 Epoch의 밀리 초 측면에서 WS 거래를 원할 수도 있습니다.

당신은 날짜가 웹 서비스와 관련하여 사용된다고 말하므로 어느 시점에서 문자열로 직렬화된다고 가정합니다.

이 경우, 당신은 settimezone 방법 DateFormat 클래스의. 이것은 타임 스탬프를 인쇄 할 때 사용될 시간 구역을 지시합니다.

간단한 예 :

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

당신은 그것을 해결할 수 있습니다 조다 시간:

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)

그러나 그 시스템은 어떤 시간대가 있는지 알고 있기 때문에 클라이언트 측에서 수행해야합니다.

한 시간대에서 다른 시간대로 변환하는 방법 (아마도 작동합니다 :)).

/**
 * 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;
}

날짜 그리고 타임 스탬프 객체는 시간대-명백합니다. 그들은 몇 시간과 며칠 동안 그 순간에 대한 특정 해석을 약속하지 않고 에포크 이후 일정 초의 수를 나타냅니다. 시간대는 사진 만 입력합니다 그레고리 언 달력 (이 작업에 직접 필요하지 않음) 및 SimpledateFormat, 별도의 필드와 날짜 사이를 변환하려면 시간대 오프셋이 필요합니다 (또는 ) 값.

OP의 문제는 처리 시작 시점에 옳습니다. 사용자는 모호하며 지역의 비 GMT 타임 존에서 해석됩니다. 이 시점에서 값은입니다 "6:12 EST", 쉽게 인쇄 할 수 있습니다 "11.12 GMT" 또는 다른 시간대이지만 결코 가지 않을 것입니다 변화 에게 "6.12 GMT".

만들 수있는 방법이 없습니다 SimpledateFormat 그 구획 "06:12" ~처럼 "HH : MM" (로컬 타임 존으로 기본값) UTC 대신 기본값; SimpledateFormat 자신의 이익에 대해 너무 똑똑합니다.

그러나 당신은 어떤 것을 설득 할 수 있습니다 SimpledateFormat 입력에 명시 적으로 넣는 경우 적절한 시간대를 사용하려면 인스턴스 : 수신자에게 고정 문자열을 추가하십시오 (및 적절하게 검증). "06:12" 구문 분석 "06:12 GMT" ~처럼 "HH : MM Z".

명백한 설정이 필요하지 않습니다 그레고리 언 달력 필드 또는 시간대 및 일광 절약 시간 오프셋을 검색하고 사용하는 필드.

실제 문제는 로컬 타임 존의 기본값, UTC의 기본 입력 및 명시적인 시간대 표시가 필요한 입력을 분리하는 것입니다.

과거에 나를 위해 일한 것은 사용자의 시간대와 GMT 사이의 오프셋 (밀리 초)을 결정하는 것이 었습니다. 오프셋이 있으면 시간대에 적절한 시간을 얻기 위해 간단히 추가/뺄 수 있습니다 (변환이 진행되는 방식에 따라). 나는 일반적으로 캘린더 객체의 밀리 초 필드를 설정하여 이것을 달성하지만 타임 스탬프 객체에 쉽게 적용 할 수 있다고 확신합니다. 오프셋을 얻는 데 사용하는 코드는 다음과 같습니다.

int offset = TimeZone.getTimeZone(timezoneId).getRawOffset();

TimeZoneid는 사용자의 시간대 (예 : EST)의 ID입니다.

Java.Time

현대의 접근법은 다음을 사용합니다 Java.Time 번거로운 레거시 날짜 시간 시간 수업을 최초의 Java 버전과 함께 묶은 수업.

그만큼 java.sql.Timestamp 수업은 그 레거시 클래스 중 하나입니다. 더 이상 필요 없어요. 대신 사용하십시오 Instant 또는 JDBC 4.2 이상을 사용하여 데이터베이스와 직접 다른 Java.Time 클래스.

그만큼 Instant 클래스는 타임 라인의 순간을 나타냅니다 UTC 해상도와 함께 나노 초 (최대 9 개) 소수점 분수의 숫자).

Instant instant = myResultSet.getObject( … , Instant.class ) ; 

기존과 상호 작용 해야하는 경우 Timestamp, 이전 클래스에 추가 된 새로운 변환 방법을 통해 즉시 Java.Time으로 변환하십시오.

Instant instant = myTimestamp.toInstant() ;

다른 시간대로 조정하려면 시간대를 ZoneId 물체. 지정 a 적절한 시간대 이름 형식으로 continent/region, 와 같은 America/Montreal, Africa/Casablanca, 또는 Pacific/Auckland. 다음과 같은 3-4 문자 유사면을 사용하지 마십시오 EST 또는 IST 그대로 ~ 아니다 표준화되지 않았으며 독특하지 않은 실제 시간대. (!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;

적용하십시오 Instant 생산하려면 ZonedDateTime 물체.

ZonedDateTime zdt = instant.atZone( z ) ;

사용자에게 표시 할 문자열을 생성하려면 검색 스택 오버 플로우 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를 의미한다면 a OffsetDateTime 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 이상에 내장되어 있습니다. 이 수업은 번거로운 오래된 것을 대체합니다 유산 다음과 같은 날짜 시간 수업 java.util.Date, Calendar, & SimpleDateFormat.

그만큼 조다-시간 지금 프로젝트 유지 관리 모드, Java.Time 클래스.

자세한 내용은 오라클 튜토리얼. 많은 예와 설명에 대한 검색 스택 오버 플로우. 사양입니다 JSR 310.

Java.Time 수업을 어디에서 얻을 수 있습니까?

그만큼 Threeten-extra 프로젝트는 추가 클래스로 Java.Time을 연장합니다. 이 프로젝트는 Java.Time에 향후 추가 할 수있는 근거입니다. 여기에서 유용한 수업을 찾을 수 있습니다 Interval, YearWeek, YearQuarter, 그리고 .

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top