Does Java 8's new Java Date Time API take care of DST?

时间:2015-09-29 00:40:14

标签: java datetime datetimeoffset

I am thinking of using the new java 8 Date Time API. I googled a bit and found jodaTime as good choice for java but still kind of interested to see how this new API works.

I am storing all time in UTC values in my datastore and will be converting them to Local Time Zone specific value based on user's timezone. I can find many articles showing how to use new Java Date Time API. However I am not sure if the API will take care of DST changes ? Or do we have any better way of handling Date ?

I am just learning the new Date API , so thought of hearing your thoughts on handling the DateTime and displaying it on the basis of Users TimeZone.

3 个答案:

答案 0 :(得分:32)

这取决于您使用的课​​程:

  • Instant是全球时间线(UTC)上的瞬时点,与时区无关。
  • LocalDateLocalDateTime没有时区概念,但调用now()当然会给你正确的时间。
  • OffsetDateTime有时区,但不支持夏令时。
  • ZonedDateTime拥有完整的时区支持。

他们之间的转换通常需要一个时区,所以回答你的问题:

是的,Java 8日期/时间可以处理DST,如果你正确使用它。

答案 1 :(得分:21)

The Answer AndreasDST in the United States是正确无误的。

示例代码

让我们用一些代码测试它。 wall-clock time&加拿大将于2015年11月1日02:00到期。

让我们从“本地”日期时间的凌晨1点开始,这意味着与时间轴无关并忽略时区问题。加一个小时,我们凌晨2点。有道理。

LocalDateTime localDateTime = LocalDateTime.of( 2015 , Month.NOVEMBER , 1 , 1 , 0 ); // 1 AM anywhere. Not tied the timeline nor to any time zone.
LocalDateTime localDateTimeOneHourLater = localDateTime.plusHours( 1 ); // 2 AM anywhere, in no particular time zone, ignoring DST.

接下来,我们会针对特定时区进行具体说明。我们在凌晨1点将其放入America/Los_Angeles(美国西海岸)的时区。

ZoneId zoneId_LosAngeles = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime before = localDateTime.atZone( zoneId_LosAngeles ); // Assign a time zone, tying this vague date-time idea/generality to an actual moment on the time line.

现在加一个小时,看看我们得到了什么。如果DST被忽略,我们将获得凌晨2点。如果DST得到尊重,我们将获得凌晨1点...当到达凌晨2点时,"fall back"会跳回到凌晨1点,但是会有一个新的UTC偏移量。这在秋季(秋季)通俗地称为offset-from-UTC

ZonedDateTime after = before.plusHours( 1 ); // 2 AM? Nope, 1 AM because DST Daylight Saving Time expires at 2 AM Nov 1, 2015.

转储到控制台。

System.out.println( "localDateTime : " + localDateTime );
System.out.println( "localDateTimeOneHourLater : " + localDateTimeOneHourLater );
System.out.println( "before : " + before );
System.out.println( "after : " + after );

运行时,我们得到此输出。没有时区,1 AM + 1小时= 2 AM。记住这些是"本地"日期时间值,不是UTC 。它们只代表日期时间的模糊概念,而不是时间轴上的实际时刻。

localDateTime : 2015-11-01T01:00
localDateTimeOneHourLater : 2015-11-01T02:00

但是在DST到期的当天应用了时区,我们会得到不同的结果。请注意,时间仍为01:00-07:00-08:00更改为before : 2015-11-01T01:00-07:00[America/Los_Angeles] after : 2015-11-01T01:00-08:00[America/Los_Angeles]

before

如果我们调整为UTC,这可能会更清晰,更容易验证。我们只需将afterSystem.out.println( "before.toInstant : " + before.toInstant() ); System.out.println( "after.toInstant : " + after.toInstant() ); 个对象作为Instant个对象访问即可。 System.out.println然后隐式调用toString方法。

before.toInstant : 2015-11-01T08:00:00Z
after.toInstant : 2015-11-01T09:00:00Z

跑步时。

java.sql.*

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import com.google.android.gms.gcm.GoogleCloudMessaging; import com.google.android.gms.iid.InstanceID; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; public class MainActivity extends ActionBarActivity { private String RegID = ""; private Context context = null; private GoogleCloudMessaging gcm = null; private InstanceID instanceID = null; private BroadcastReceiver mHandleMesageReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = getApplicationContext(); if(RegID.isEmpty()) { register RegInBG = new register(); RegInBG.execute("e"); post task = new post(); task.execute(RegID); mHandleMesageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { } }; } } /*Runnable task to be used to register app in the GCM service for push notifications, made by Devin Adams */ public class register extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { try { if (instanceID == null) { instanceID = InstanceID.getInstance(context); } if (gcm == null) { gcm = GoogleCloudMessaging.getInstance(context); } RegID = instanceID.getToken(getString(R.string.sender_id), gcm.INSTANCE_ID_SCOPE, null); Log.e("***********", "************"); Log.e("***********", "************"); Log.e("RegID", RegID); Log.e("***********", "************"); Log.e("***********", "************"); } catch (IOException ex) { Log.e("***********", "************"); Log.e("***********", "************"); Log.e("Error", ex.getMessage()); Log.e("***********", "************"); Log.e("***********", "************"); } return "sd"; } } public class post extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { try { String tempurl = getString(R.string.server_url); Uri.Builder b = Uri.parse(tempurl).buildUpon(); String url = b.build().toString(); HttpURLConnection connection = (HttpURLConnection) ((new URL(url))).openConnection(); connection.setRequestMethod("POST"); connection.setDoInput(true); connection.setDoOutput(true); connection.connect(); connection.getOutputStream().write((params[0]).getBytes()); connection.disconnect(); } catch (IOException ex) { Log.e("Error", ex.getMessage()); } return "getg"; } } }类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 2 :(得分:4)

是的,Java API将考虑DST更改。

本教程非常好地解释了如何在时区之间转换日期以及如何选择正确的类来表示日期: https://docs.oracle.com/javase/tutorial/datetime/iso/timezones.html

您还可以查看此类,该类代表每个区域的规则: http://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html

特别是,此方法可以告诉您特定时刻是否在夏令时: http://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html#isDaylightSavings-java.time.Instant-