年份中的Java毫秒数

时间:2012-02-04 15:16:37

标签: 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年大致 = 31,556,952,000毫秒,所以我的乘法以某种方式关闭。

有谁可以指出我做错了什么?我应该使用多长时间吗?

9 个答案:

答案 0 :(得分:32)

  

我应该使用多长时间?

是。问题在于,由于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 :(得分:23)

如果在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

答案 2 :(得分:10)

虽然其他人已经指出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));

答案 3 :(得分:8)

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 * ...

答案 4 :(得分:5)

你需要很长时间。 Ints包裹了大约20亿。

答案 5 :(得分:5)

你溢出int类型。在Java中,两个int s上的原始算术运算的结果是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;

答案 6 :(得分:4)

要解决此问题,您可以在第一个字母后添加 L 例如 1000L

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

答案 7 :(得分:3)

TL;博士

关于您使用int vs longAnswer by Ruakh)导致完全错误的数字1471228928integer overflow是正确的。但此外,您的问题提出了太阳年与日历年的问题。

  

我知道1年= 31556952000毫秒

不,那将是太阳年的长度,而不是日历年。日历年为31,536,000,000毫秒。

现代 java.time 类和ChronoUnit可以计算日历年编号。

Year y = Year.now(                    // Determine the year of the current date (today).
    ZoneId.of( "America/Montreal" )   // Determining the year means determining the current date. And determining a date requires a time zone. For any given moment, the date varies around the globe by zone.
) ;                                   // Returns a `Year` object.


long millisInYear =
ChronoUnit.MILLIS.between( 
    y.atDay( 1 )                      // Get the first of the year. Returns a `LocalDate`. 
     .atStartOfDay(                   // Determine the first moment of the day. Not always 00:00:00 because of anomalies such as Daylight Saving Time (DST).
         ZoneId.of( "America/Montreal" )  
    )                                 // Returns a `ZonedDateTime` object.
    ,
    y.plusYears(1)                    // Move to the following year.
     .atDay( 1 )                      // Get the first of the following year. Returns a `LocalDate`. 
     .atStartOfDay(                   
         ZoneId.of( "America/Montreal" )  
    )                                 // Returns a `ZonedDateTime` object.
) ;
  

315.36亿

31,556,952,000 =太阳年

Your source使用太阳年长度的近似值,大约365.2425 24小时天。这是地球绕太阳运行所需的时间。

数学:

  

365.2425 * 24 * 60 * 60 * 1000 =31,556,951,999.999996≈31,556,952,000ms

请参阅this calculator

31,536,000,000 =日历年

在西历(格里高利/ ISO)中,我们使用多年甚至365天24小时的日子,忽略了地球围绕太阳运行需要额外四分之一天的事实。我们通过每四年额外插入一天来弥补差异(大致是四年的倍数,除了可被100整除但不能被400整除的年份),the Leap Day

考虑到平日年365天,24小时工作日并且没有异常现象,例如夏令时(DST),日历年的长度为31,536,000,000毫秒。正如您在问题中所建议的那样,不是31,556,952,000

  

31,536,000,000 =(365 * 24 * 60 * 60 * 1000)

请参阅this calculator

366天的闰年将为31,622,400,000毫秒。

  

31,622,400,000 =(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 );
  

start.toString():2015-01-01T00:00-05:00 [America / Montreal]

     

stop.toString():2016-01-01T00:00-05:00 [America / Montreal]

     

millisInYear:31536000000

关于 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。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

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

答案 8 :(得分: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