2012-02-04 112 views
19

我正在使用毫秒在Java中進行一些日期計算。我沒有太多的毫秒工作經驗,甚至無法確定一年有多少毫秒。這裏是我的嘗試:Java中的毫秒數

private static final int MILLIS_IN_SECOND = 1000; 
    private static final int SECONDS_IN_MINUTE = 60; 
    private static final int MINUTES_IN_HOUR = 60; 
    private static final int HOURS_IN_DAY = 24; 
    private static final int DAYS_IN_YEAR = 365; //I know this value is more like 365.24... 
    private static final long MILLISECONDS_IN_YEAR = MILLIS_IN_SECOND * SECONDS_IN_MINUTE * MINUTES_IN_HOUR * HOURS_IN_DAY * DAYS_IN_YEAR; 


System.out.println(MILLISECONDS_IN_YEAR); //Returns 1471228928 

我知道這1年= 31556952000毫秒,所以我的乘法是關閉莫名其妙。

任何人都可以指出我做錯了什麼?我應該使用很長時間嗎?

+2

爲什麼不試試呢?或者查看32位有符號整數的最大值是多少? – 2012-02-04 15:18:28

+0

@Dave Newton我試過了,代碼返回一個我知道不正確的值。一個int在一年中的工作時間爲毫秒,但是我正在計算錯誤的值。 – 2012-02-04 15:21:04

+0

想必閏年是無關緊要的... – 2012-02-04 16:01:37

回答

28

我應該用多長時間?

是的。問題是,由於MILLIS_IN_SECOND等都是int s,所以當你乘以它們時,你會得到一個int。您正在將int轉換爲long,但之後的乘以int已導致錯誤答案。

爲了解決這個問題,你可以先拿一個到long

private static final long MILLISECONDS_IN_YEAR = 
     (long)MILLIS_IN_SECOND * SECONDS_IN_MINUTE * MINUTES_IN_HOUR 
     * HOURS_IN_DAY * DAYS_IN_YEAR; 
+1

很好的解釋。那麼在將它們相乘之前,演員們是否會將其整合到一起? – 2012-02-04 15:26:09

+1

@ kmb385當你將某些東西放大時,結果將始終是較大的類型。 – kechapito 2012-02-04 15:35:28

+5

@ kmb385:是的,正好。或者說,我猜想,cast本身只是將* first *'int'變成'long',但在此之後,Java會將每個「int」轉換爲「long」,然後再乘以「long」 '。 – ruakh 2012-02-04 15:39:28

4

你需要很長時間。 Ints包裹了大約20億。

7
private static final long MILLISECONDS_IN_YEAR = MILLIS_IN_SECOND * ... 

所有右手邊操作數int S,所以乘法與32位有符號整數,其溢出來完成。投第一個到long,你會得到預期的價值。

private static final long MILLISECONDS_IN_YEAR = (long)MILLIS_IN_SECOND * ... 
+0

或者簡單地使用'Long'而不是'int',16個額外的字節被詛咒! – 2012-02-04 15:27:29

+0

感謝您的幫助。我不知道int溢出,我想我會得到一個運行時錯誤。 – 2012-02-04 15:30:48

+0

@BrianRoach:我不知道,我不得不將'HOURS_IN_DAY'轉換爲'int',所以我可以將它傳遞給一個'int'-期待函數,因爲有人誤導了保持它的類型的想法與「MILLISECONDS_IN_YEAR」的一致。 – ruakh 2012-02-04 15:42:58

4

您正在溢出int類型。在Java中,兩個int之間的原始算術操作的結果是int。操作數的類型決定了這一點,而不是結果變量的類型。嘗試:

private static final int MILLIS_IN_SECOND = 1000; 
private static final int SECONDS_IN_MINUTE = 60; 
private static final int MINUTES_IN_HOUR = 60; 
private static final int HOURS_IN_DAY = 24; 
private static final int DAYS_IN_YEAR = 365; //I know this value is more like 365.24... 
private static final long MILLISECONDS_IN_YEAR = (long) MILLIS_IN_SECOND * SECONDS_IN_MINUTE * MINUTES_IN_HOUR * HOURS_IN_DAY * DAYS_IN_YEAR; 
+0

工作。謝謝。 – 2012-02-04 15:22:51

0

試試這個

int MILLIS_IN_SECOND = 1000; 
    int SECONDS_IN_MINUTE = 60; 
    int MINUTES_IN_HOUR = 60; 
    int HOURS_IN_DAY = 24; 
    int DAYS_IN_YEAR = 365; 

    long MILLISECONDS_IN_YEAR = (long) MILLIS_IN_SECOND * SECONDS_IN_MINUTE * MINUTES_IN_HOUR * HOURS_IN_DAY * DAYS_IN_YEAR; 

    System.out.println(MILLISECONDS_IN_YEAR); // Returns 31536000000 
8

而另一些人已經指出arithmetic overflow,你也可以嘗試TimeUnit解決問題:

Calendar calendar = Calendar.getInstance(); 
calendar.set(Calendar.YEAR, year); 
int daysInYear = calendar.getActualMaximum(Calendar.DAY_OF_YEAR); 
System.out.println(TimeUnit.DAYS.toMillis(daysInYear)); 
2

到fi x這個,你可以在第一個後面加上L1000L

long MILLS_IN_YEAR = 1000L * 60 * 60 * 24 * 365; // Returns 31536000000 
19

如果在Android上,我建議:

android.text.format.DateUtils

DateUtils.SECOND_IN_MILLIS 
DateUtils.MINUTE_IN_MILLIS 
DateUtils.HOUR_IN_MILLIS 
DateUtils.DAY_IN_MILLIS 
DateUtils.WEEK_IN_MILLIS 
DateUtils.YEAR_IN_MILLIS 
+6

在DateUtils.YEAR_IN_MILLIS的類文檔中,它說:「這個常量實際上是364天的長度,而不是一年!」 – 2014-12-13 16:17:21

1

315.36億

考慮365天的純一年24小時天沒有像Daylight Savin那樣的異常情況g時間(DST),一年是31,536,000,000毫秒。不是你在問題中建議的31,556,952,000

315.36億=(365 * 24 * 60 * 60 * 1000)

閏年366天將31,622,400,000毫秒。

31622400000 =(366 * 24 * 60 * 60 * 1000)

java.time

現代java.time類取代具有最早版本捆綁舊日期時類的Java。這些老班級已被證明是令人困惑和麻煩的。

ChronoUnit

閏年等異常現象可能意味着在一年的毫秒數意外。所以你應該讓java.time做一個實際的計算,如果精度對你的情況很重要。

ChronoUnit類可以計算某個單位的經過時間。

long millisInYear = ChronoUnit.MILLIS.between(start , stop); 

我們需要確定一年中第一天的開始日期和下一年的確切時刻。我們通過查看LocalDate課程來完成此任務,該課程僅表示沒有時間和不帶時區的僅限日期的值。

LocalDate startLd = LocalDate.of (2015 , 1 , 1); 
LocalDate stopLd = startLd.plusYears (1); 

通過指定一個時區(ZoneId),我們得到的時間軸上的特定時刻ZonedDateTime對象。

ZoneId z = ZoneId.of ("America/Montreal"); 
ZonedDateTime start = startLd.atStartOfDay (z); 
ZonedDateTime stop = stopLd.atStartOfDay (z); 

最後,計算經過的時間(以毫秒爲單位)。

long millisInYear = ChronoUnit.MILLIS.between (start , stop); 

開始:2015-01-01T00:00-05:00 [美國/蒙特利爾] | stop:2016-01-01T00:00-05:00 [America/Montreal] | millisInYear:31536000000