JodaのTimestamp
によってDateTimeZone
の値を変更しようとしています。
DateTime dt = new DateTime(rs.getTimestamp("anytimestampcolumn"),
DateTimeZone.forID("anytimezone"));
Timestamp ts = new Timestamp(dt.getMillis());
DateTime
の場合、値は2013-04-13T22:56:27.000+03:00
TimeStamp
の場合、値は2013-04-13 22:56:27.0
Timestamp
はタイムゾーンの違いなしで来ています。
TimeZoneで正しいタイムスタンプを取得するにはどうすればよいですか?たとえば、「2013-05-13 01:56:27.0」を取得したいです。
前もって感謝します。
編集:使用MySQL、列タイプはTIMESTAMP
もちろん、rs
はResultSet
。
実際、これは重複した質問ではありません。そして、これは私が数回後に私の問題を解決する方法です:
int offset = DateTimeZone.forID("anytimezone").getOffset(new DateTime());
これは、目的のタイムゾーンからオフセットを取得する方法です。
コードに戻りましょう。クエリの結果セットからタイムスタンプを取得し、それをタイムゾーンで使用して日時を作成しました。
DateTime dt = new DateTime(rs.getTimestamp("anytimestampcolumn"),
DateTimeZone.forID("anytimezone"));
ここで、datetimeにオフセットを追加し、そこからタイムスタンプを取得します。
dt = dt.plusMillis(offset);
Timestamp ts = new Timestamp(dt.getMillis());
これは実際の方法ではないかもしれませんが、私の場合は解決します。ここで立ち往生している人の助けになることを願っています。
時間(測定可能な4次元)は世界中で異なるというのは一般的な誤解です。ある瞬間のタイムスタンプは独特です。ただし、日付は時間の「見方」に影響しますが、実際は「時刻」です。
例:2人が同時に時計を見る。タイムスタンプは同じですよね?ただし、そのうちの1つはロンドンにあり、正午(GMT、タイムゾーンオフセットは0)で、もう1つはベオグラードにあり、14:00(CET、中央ヨーロッパ、夏時間、オフセットは+2)です。
彼らの認識は異なりますが、瞬間は同じです。
詳細は この回答 。にあります
OK、これは この質問 の複製ではありませんが、「タイムスタンプ=瞬間(目的)」と「日付[時間] =時刻(主観)」という用語を混同しているので無意味です。 。
次のように分類された元の質問コードを見てみましょう。
// Get the "original" value from database.
Timestamp momentFromDB = rs.getTimestamp("anytimestampcolumn");
// Turn it into a Joda DateTime with time zone.
DateTime dt = new DateTime(momentFromDB, DateTimeZone.forID("anytimezone"));
// And then turn it back into a timestamp but "with time zone".
Timestamp ts = new Timestamp(dt.getMillis());
私はこのコードを実行していませんが、毎回true
と同じミリ秒数を出力することを確信しています:
System.out.println("momentFromDB == dt : " + (momentFromDB.getTime() == dt.getTimeInMillis());
System.out.println("momentFromDB == ts : " + (momentFromDB.getTime() == ts.getTime()));
System.out.println("dt == ts : " + (dt.getTimeInMillis() == ts.getTime()));
System.out.println("momentFromDB [ms] : " + momentFromDB.getTime());
System.out.println("ts [ms] : " + ts.getTime());
System.out.println("dt [ms] : " + dt.getTimeInMillis());
ただし、DateTime
がタイムゾーンを適用するため、文字列として印刷すると「異なる」時間になります。これが、「時間」がTimestamp
オブジェクト(基本的にlong
をラップする)として格納および転送され、Date[Time]
として表示または入力される理由です。
あなた自身の答えでは、人為的にオフセットを追加し、「間違った」時間を作成しています。そのタイムスタンプを使用して別のDateTime
を作成し、印刷すると、2回オフセットされます。
// Turn it back into a Joda DateTime with time zone.
DateTime dt = new DateTime(ts, DateTimeZone.forID("anytimezone"));
追伸時間が非常に複雑な場合は、 Joda Timeソースコード を使用して、時間の保持方法(ミリ秒)と印刷方法を確認します。
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import Java.text.SimpleDateFormat;
import Java.util.Calendar;
import Java.util.Date;
import Java.util.Locale;
import Java.util.TimeZone;
import org.junit.Before;
import org.junit.Test;
public class WorldTimeTest {
private static final int MILLIS_IN_HOUR = 1000 * 60 * 60;
private static final String ISO_FORMAT_NO_TZ = "yyyy-MM-dd'T'HH:mm:ss.SSS";
private static final String ISO_FORMAT_WITH_TZ = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
private TimeZone londonTimeZone;
private TimeZone newYorkTimeZone;
private TimeZone sydneyTimeZone;
private long nowInMillis;
private Date now;
public static SimpleDateFormat createDateFormat(String pattern, TimeZone timeZone) throws Exception {
SimpleDateFormat result = new SimpleDateFormat(pattern);
// Must explicitly set the time zone with "setCalendar()".
result.setCalendar(Calendar.getInstance(timeZone));
return result;
}
public static SimpleDateFormat createDateFormat(String pattern) throws Exception {
return createDateFormat(pattern, TimeZone.getDefault());
}
public static SimpleDateFormat createDateFormat() throws Exception {
return createDateFormat(ISO_FORMAT_WITH_TZ, TimeZone.getDefault());
}
public void printSystemInfo() throws Exception {
final String[] propertyNames = {
"Java.runtime.name", "Java.runtime.version", "Java.vm.name", "Java.vm.version",
"os.name", "os.version", "os.Arch",
"user.language", "user.country", "user.script", "user.variant",
"user.language.format", "user.country.format", "user.script.format",
"user.timezone" };
System.out.println();
System.out.println("System Information:");
for (String name : propertyNames) {
if (name == null || name.length() == 0) {
continue;
}
String value = System.getProperty(name);
if (value != null && value.length() > 0) {
System.out.println(" " + name + " = " + value);
}
}
final TimeZone defaultTZ = TimeZone.getDefault();
final int defaultOffset = defaultTZ.getOffset(nowInMillis) / MILLIS_IN_HOUR;
final int userOffset = TimeZone.getTimeZone(System
.getProperty("user.timezone")).getOffset(nowInMillis) / MILLIS_IN_HOUR;
final Locale defaultLocale = Locale.getDefault();
System.out.println(" default.timezone-offset (hours) = " + userOffset);
System.out.println(" default.timezone = " + defaultTZ.getDisplayName());
System.out.println(" default.timezone.id = " + defaultTZ.getID());
System.out.println(" default.timezone-offset (hours) = " + defaultOffset);
System.out.println(" default.locale = "
+ defaultLocale.getLanguage() + "_" + defaultLocale.getCountry()
+ " (" + defaultLocale.getDisplayLanguage()
+ "," + defaultLocale.getDisplayCountry() + ")");
System.out.println(" now = " + nowInMillis + " [ms] or "
+ createDateFormat().format(now));
System.out.println();
}
@Before
public void setUp() throws Exception {
// Remember this moment.
now = new Date();
nowInMillis = now.getTime(); // == System.currentTimeMillis();
// Print out some system information.
printSystemInfo();
// "Europe/London" time zone is DST aware, we'll use fixed offset.
londonTimeZone = TimeZone.getTimeZone("GMT");
// The same applies to "America/New York" time zone ...
newYorkTimeZone = TimeZone.getTimeZone("GMT-5");
// ... and for the "Australia/Sydney" time zone.
sydneyTimeZone = TimeZone.getTimeZone("GMT+10");
}
@Test
public void testDateFormatting() throws Exception {
int londonOffset = londonTimeZone.getOffset(nowInMillis) / MILLIS_IN_HOUR; // in hours
Calendar londonCalendar = Calendar.getInstance(londonTimeZone);
londonCalendar.setTime(now);
int newYorkOffset = newYorkTimeZone.getOffset(nowInMillis) / MILLIS_IN_HOUR;
Calendar newYorkCalendar = Calendar.getInstance(newYorkTimeZone);
newYorkCalendar.setTime(now);
int sydneyOffset = sydneyTimeZone.getOffset(nowInMillis) / MILLIS_IN_HOUR;
Calendar sydneyCalendar = Calendar.getInstance(sydneyTimeZone);
sydneyCalendar.setTime(now);
// Check each time zone offset.
assertThat(londonOffset, equalTo(0));
assertThat(newYorkOffset, equalTo(-5));
assertThat(sydneyOffset, equalTo(10));
// Check that calendars are not equals (due to time zone difference).
assertThat(londonCalendar, not(equalTo(newYorkCalendar)));
assertThat(londonCalendar, not(equalTo(sydneyCalendar)));
// Check if they all point to the same moment in time, in milliseconds.
assertThat(londonCalendar.getTimeInMillis(), equalTo(nowInMillis));
assertThat(newYorkCalendar.getTimeInMillis(), equalTo(nowInMillis));
assertThat(sydneyCalendar.getTimeInMillis(), equalTo(nowInMillis));
// Check if they all point to the same moment in time, as Date.
assertThat(londonCalendar.getTime(), equalTo(now));
assertThat(newYorkCalendar.getTime(), equalTo(now));
assertThat(sydneyCalendar.getTime(), equalTo(now));
// Check if hours are all different (skip local time because
// this test could be executed in those exact time zones).
assertThat(newYorkCalendar.get(Calendar.HOUR_OF_DAY),
not(equalTo(londonCalendar.get(Calendar.HOUR_OF_DAY))));
assertThat(sydneyCalendar.get(Calendar.HOUR_OF_DAY),
not(equalTo(londonCalendar.get(Calendar.HOUR_OF_DAY))));
// Display London time in multiple forms.
SimpleDateFormat dfLondonNoTZ = createDateFormat(ISO_FORMAT_NO_TZ, londonTimeZone);
SimpleDateFormat dfLondonWithTZ = createDateFormat(ISO_FORMAT_WITH_TZ, londonTimeZone);
System.out.println("London (" + londonTimeZone.getDisplayName(false, TimeZone.SHORT)
+ ", " + londonOffset + "):");
System.out.println(" time (ISO format w/o TZ) = "
+ dfLondonNoTZ.format(londonCalendar.getTime()));
System.out.println(" time (ISO format w/ TZ) = "
+ dfLondonWithTZ.format(londonCalendar.getTime()));
System.out.println(" time (default format) = "
+ londonCalendar.getTime() + " / " + londonCalendar.toString());
// Using system default time zone.
System.out.println(" time (default TZ) = "
+ createDateFormat(ISO_FORMAT_NO_TZ).format(londonCalendar.getTime())
+ " / " + createDateFormat().format(londonCalendar.getTime()));
// Display New York time in multiple forms.
SimpleDateFormat dfNewYorkNoTZ = createDateFormat(ISO_FORMAT_NO_TZ, newYorkTimeZone);
SimpleDateFormat dfNewYorkWithTZ = createDateFormat(ISO_FORMAT_WITH_TZ, newYorkTimeZone);
System.out.println("New York (" + newYorkTimeZone.getDisplayName(false, TimeZone.SHORT)
+ ", " + newYorkOffset + "):");
System.out.println(" time (ISO format w/o TZ) = "
+ dfNewYorkNoTZ.format(newYorkCalendar.getTime()));
System.out.println(" time (ISO format w/ TZ) = "
+ dfNewYorkWithTZ.format(newYorkCalendar.getTime()));
System.out.println(" time (default format) = "
+ newYorkCalendar.getTime() + " / " + newYorkCalendar.toString());
// Using system default time zone.
System.out.println(" time (default TZ) = "
+ createDateFormat(ISO_FORMAT_NO_TZ).format(newYorkCalendar.getTime())
+ " / " + createDateFormat().format(newYorkCalendar.getTime()));
// Display Sydney time in multiple forms.
SimpleDateFormat dfSydneyNoTZ = createDateFormat(ISO_FORMAT_NO_TZ, sydneyTimeZone);
SimpleDateFormat dfSydneyWithTZ = createDateFormat(ISO_FORMAT_WITH_TZ, sydneyTimeZone);
System.out.println("Sydney (" + sydneyTimeZone.getDisplayName(false, TimeZone.SHORT)
+ ", " + sydneyOffset + "):");
System.out.println(" time (ISO format w/o TZ) = "
+ dfSydneyNoTZ.format(sydneyCalendar.getTime()));
System.out.println(" time (ISO format w/ TZ) = "
+ dfSydneyWithTZ.format(sydneyCalendar.getTime()));
System.out.println(" time (default format) = "
+ sydneyCalendar.getTime() + " / " + sydneyCalendar.toString());
// Using system default time zone.
System.out.println(" time (default TZ) = "
+ createDateFormat(ISO_FORMAT_NO_TZ).format(sydneyCalendar.getTime())
+ " / " + createDateFormat().format(sydneyCalendar.getTime()));
}
@Test
public void testDateParsing() throws Exception {
// Create date parsers that look for time zone information in a date-time string.
final SimpleDateFormat londonFormatTZ = createDateFormat(ISO_FORMAT_WITH_TZ, londonTimeZone);
final SimpleDateFormat newYorkFormatTZ = createDateFormat(ISO_FORMAT_WITH_TZ, newYorkTimeZone);
final SimpleDateFormat sydneyFormatTZ = createDateFormat(ISO_FORMAT_WITH_TZ, sydneyTimeZone);
// Create date parsers that ignore time zone information in a date-time string.
final SimpleDateFormat londonFormatLocal = createDateFormat(ISO_FORMAT_NO_TZ, londonTimeZone);
final SimpleDateFormat newYorkFormatLocal = createDateFormat(ISO_FORMAT_NO_TZ, newYorkTimeZone);
final SimpleDateFormat sydneyFormatLocal = createDateFormat(ISO_FORMAT_NO_TZ, sydneyTimeZone);
// We are looking for the moment this millenium started, the famous Y2K,
// when at midnight everyone welcomed the New Year 2000, i.e. 2000-01-01 00:00:00.
// Which of these is the right one?
// a) "2000-01-01T00:00:00.000-00:00"
// b) "2000-01-01T00:00:00.000-05:00"
// c) "2000-01-01T00:00:00.000+10:00"
// None of them? All of them?
// For those who guessed it - yes, it is a trick question because we didn't specify
// the "where" part, or what kind of time (local/global) we are looking for.
// The first (a) is the local Y2K moment in London, which is at the same time global.
// The second (b) is the local Y2K moment in New York, but London is already celebrating for 5 hours.
// The third (c) is the local Y2K moment in Sydney, and they started celebrating 15 hours before New York did.
// The point here is that each answer is correct because everyone thinks of that moment in terms of "celebration at midnight".
// The key Word here is "midnight"! That moment is actually a "time of day" moment illustrating our perception of time based on the movement of our Sun.
// These are global Y2K moments, i.e. the same moment all over the world, UTC/GMT midnight.
final String MIDNIGHT_GLOBAL = "2000-01-01T00:00:00.000-00:00";
final Date milleniumInLondon = londonFormatTZ.parse(MIDNIGHT_GLOBAL);
final Date milleniumInNewYork = newYorkFormatTZ.parse(MIDNIGHT_GLOBAL);
final Date milleniumInSydney = sydneyFormatTZ.parse(MIDNIGHT_GLOBAL);
// Check if they all point to the same moment in time.
// And that parser ignores its own configured time zone and uses the information from the date-time string.
assertThat(milleniumInNewYork, equalTo(milleniumInLondon));
assertThat(milleniumInSydney, equalTo(milleniumInLondon));
// These are all local Y2K moments, a.k.a. midnight at each location on Earth, with time zone information.
final String MIDNIGHT_LONDON = "2000-01-01T00:00:00.000-00:00";
final String MIDNIGHT_NEW_YORK = "2000-01-01T00:00:00.000-05:00";
final String MIDNIGHT_SYDNEY = "2000-01-01T00:00:00.000+10:00";
final Date midnightInLondonTZ = londonFormatLocal.parse(MIDNIGHT_LONDON);
final Date midnightInNewYorkTZ = newYorkFormatLocal.parse(MIDNIGHT_NEW_YORK);
final Date midnightInSydneyTZ = sydneyFormatLocal.parse(MIDNIGHT_SYDNEY);
// Check if they all point to the same moment in time.
assertThat(midnightInNewYorkTZ, not(equalTo(midnightInLondonTZ)));
assertThat(midnightInSydneyTZ, not(equalTo(midnightInLondonTZ)));
// Check if the time zone offset is correct.
assertThat(midnightInLondonTZ.getTime() - midnightInNewYorkTZ.getTime(),
equalTo((long) newYorkTimeZone.getOffset(milleniumInLondon.getTime())));
assertThat(midnightInLondonTZ.getTime() - midnightInSydneyTZ.getTime(),
equalTo((long) sydneyTimeZone.getOffset(milleniumInLondon.getTime())));
// These are also local Y2K moments, just withouth the time zone information.
final String MIDNIGHT_ANYWHERE = "2000-01-01T00:00:00.000";
final Date midnightInLondon = londonFormatLocal.parse(MIDNIGHT_ANYWHERE);
final Date midnightInNewYork = newYorkFormatLocal.parse(MIDNIGHT_ANYWHERE);
final Date midnightInSydney = sydneyFormatLocal.parse(MIDNIGHT_ANYWHERE);
// Check if these are the same as the local moments with time zone information.
assertThat(midnightInLondon, equalTo(midnightInLondonTZ));
assertThat(midnightInNewYork, equalTo(midnightInNewYorkTZ));
assertThat(midnightInSydney, equalTo(midnightInSydneyTZ));
// Check if they all point to the same moment in time.
assertThat(midnightInNewYork, not(equalTo(midnightInLondon)));
assertThat(midnightInSydney, not(equalTo(midnightInLondon)));
// Check if the time zone offset is correct.
assertThat(midnightInLondon.getTime() - midnightInNewYork.getTime(),
equalTo((long) newYorkTimeZone.getOffset(milleniumInLondon.getTime())));
assertThat(midnightInLondon.getTime() - midnightInSydney.getTime(),
equalTo((long) sydneyTimeZone.getOffset(milleniumInLondon.getTime())));
// Final check - if Y2K moment is in London ..
final String Y2K_LONDON = "2000-01-01T00:00:00.000Z";
// .. New York local time would be still 5 hours in 1999 ..
final String Y2K_NEW_YORK = "1999-12-31T19:00:00.000-05:00";
// .. and Sydney local time would be 10 hours in 2000.
final String Y2K_SYDNEY = "2000-01-01T10:00:00.000+10:00";
final String londonTime = londonFormatTZ.format(milleniumInLondon);
final String newYorkTime = newYorkFormatTZ.format(milleniumInLondon);
final String sydneyTime = sydneyFormatTZ.format(milleniumInLondon);
// WHat do you think, will the test pass?
assertThat(londonTime, equalTo(Y2K_LONDON));
assertThat(newYorkTime, equalTo(Y2K_NEW_YORK));
assertThat(sydneyTime, equalTo(Y2K_SYDNEY));
}
}
//This Works just fine
DateTime dt = new DateTime();
Log.d("ts",String.valueOf(dt.now()));
dt=dt.plusYears(3);
dt=dt.minusDays(7);
Log.d("JODA DateTime",String.valueOf(dt));
Timestamp ts= new Timestamp(dt.getMillis());
Log.d("Coverted to Java.sql.Timestamp",String.valueOf(ts));
この方法でこの問題を解決しました。
String dateUTC = rs.getString("date"); //UTC
DateTime date;
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS").withZoneUTC();
date = dateTimeFormatter.parseDateTime(dateUTC);
このようにして、選択したTimeZoneを強制するサーバーTimeZoneを無視します。