年份中的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毫秒,所以我的乘法不知何故。
谁能指出我做错了什么? 我应该用多久?
我应该用多久?
是。 问题是,因为MILLIS_IN_SECOND
等等都是int
,所以当你将它们相乘时,你得到一个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;
如果在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
虽然其他人已经指出了算术溢出 ,但您也可以尝试使用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));
private static final long MILLISECONDS_IN_YEAR = MILLIS_IN_SECOND * ...
右边的所有操作数都是int
,所以乘法是用32位有符号整数完成的,它们会溢出。 将第一个转换为long
,您将获得预期值。
private static final long MILLISECONDS_IN_YEAR = (long)MILLIS_IN_SECOND * ...
你需要很长时间。 Ints包裹了大约20亿。
你溢出了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;
要解决此问题,您可以将字母L放在第一个之后: 例如 1000L
long MILLS_IN_YEAR = 1000L * 60 * 60 * 24 * 365; // Returns 31536000000
TL;博士
Ruakh的回答是正确的,你使用int
vs long
( 整数溢出 )是一个完全错误的数字的原因, 1471228928
。 但此外,您的问题提出了太阳年与日历年的问题。
我知道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 =太阳年
您的来源使用太阳年长度的近似值,大约365.2425 24小时天。 这是地球绕太阳运行所需的时间。
数学:
365.2425 * 24 * 60 * 60 * 1000 =31,556,951,999.999996≈31,556,952,000ms
看到这个计算器 。
31,536,000,000 =日历年
在西历(格里高利/ ISO)中,我们使用多年甚至365天24小时的日子,忽略了地球围绕太阳的轨道需要额外四分之一天的事实。 我们通过每四年插入一个额外的日子来弥补差异(大致是几年的倍数,除了可被100整除但不能被400整除的年份), 闰日 。
考虑到平日年365天,24小时工作日并且没有exception现象,例如夏令时(DST),日历年长度为31,536,000,000
毫秒。 您在问题中的建议不是31,556,952,000
。
31,536,000,000 =(365 * 24 * 60 * 60 * 1000)
看到这个计算器 。
366天的闰年将是31,622,400,000
毫秒。
31,622,400,000 =(366 * 24 * 60 * 60 * 1000)
java.time
现代java.time类取代了与最早版本的Java捆绑在一起的旧日期时间类。 事实certificate,那些旧课程令人困惑和麻烦。
ChronoUnit
闰年和其他exception可能意味着一年中意外的毫秒数。 因此,如果精度在您的情况下很重要,那么您应该让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 [美国/蒙特利尔]
stop.toString():2016-01-01T00:00-05:00 [美国/蒙特利尔]
millisInYear:31536000000
关于java.time
java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧遗留日期时间类,如java.util.Date
, Calendar
和SimpleDateFormat
。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。
您可以直接与数据库交换java.time对象。 使用符合JDBC 4.2或更高版本的JDBC驱动程序 。 不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
- Java SE 8 , Java SE 9 , Java SE 10及更高版本
- 内置。
- 带有捆绑实现的标准Java API的一部分。
- Java 9增加了一些小function和修复。
- Java SE 6和Java SE 7
- 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
- Android的
- 更高版本的Android捆绑java.time类的实现。
- 对于早期的Android(<26), ThreeTenABP项目采用ThreeTen-Backport (如上所述)。 请参见如何使用ThreeTenABP ….
ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如Interval
, YearWeek
, YearQuarter
等。
尝试这个
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