How do I use Julian Day Numbers with the Java Calendar API? - java

Julian Day Numbers are a means of representing timestamps as a continuous count of days (and fractional days) since noon UTC, January 1, 4713 B.C. The Java 7 SE API does not contain support for this format. Developers who have used the SQLite database may have used the native Julian Day support provided by the strftime() functions.
The advantages of representing timestamps as Julian Day Numbers include:
A date and time can be represented to millisecond precision in a primitive data type (double)
Days in a year are somewhat more concrete than seconds in a day
Circumvents the problem of "leap seconds" if this degree of precision is unimportant
Days between dates arithmetic is trivial; sorting precedence is easily determined
Very lightweight
Disadvantages
The Java Date/Time API does not have built-in support for JDN's
Unsuitable for very precise time measurements
Only defined for UTC and must be mapped from UTC to local time
Unsuitable for display to end-users; must be converted/formatted before display
Julian Day Numbers are commonly used in astronomical calculations and their definition is highly standardized and accepted. Similarly, Modified Julian Day Numbers (which count from midnight UTC, 17 November 1858) are standardly defined and used in aerospace applications (see http://tycho.usno.navy.mil/mjd.html).
For applications that make extensive use of date/time arithmetic or chronological sorting (or if persisting lightweight primitives is more appealing than persisting timestamps), internally representing dates and times as JDN's or MJD's may make sense for you.
The following code defines functions that facilitate using either Julian Day Numbers or Modified Julian Day Numbers with the Java Date/Time/Calendar API. The code is based on algorithms published in Jean Meeus's "Astronomical Algorithms", 1st ed., 1991.
public class JulianDay {
private static final int YEAR = 0;
private static final int MONTH = 1;
private static final int DAY = 2;
private static final int HOURS = 3;
private static final int MINUTES = 4;
private static final int SECONDS = 5;
private static final int MILLIS = 6;
:
:
// Converts a timestamp presented as an array of integers in the following
// order (from index 0 to 6): year,month,day,hours,minutes,seconds,millis
// month (1-12), day (1-28 or 29), hours (0-23), min/sec (0-59) to a
// Modified Julian Day Number.
// For clarity and simplicity, the input values are assumed to be well-formed;
// error checking is not implemented in the snippet.
public static double toMJD(int[] ymd_hms) {
int y = ymd_hms[YEAR];
int m = ymd_hms[MONTH];
double d = (double) ymd_hms[DAY];
d = d + ((ymd_hms[HOURS] / 24.0) +
(ymd_hms[MINUTES] / 1440.0) +
(ymd_hms[SECONDS] / 86400.0) +
(ymd_hms[MILLIS] / 86400000.0));
if (m == 1 || m == 2) {
y--;
m = m + 12;
}
double a = Math.floor(y / 100);
double b = 2 - a + Math.floor(a / 4);
return (Math.floor(365.25 * (y + 4716.0)) +
Math.floor(30.6001 * (m + 1)) +
d + b - 1524.5) - 2400000.5; // for Julian Day omit the 2400000.5 term
}
// Converts an Modified Julian Day Number (double) to an integer array representing
// a timestamp (year,month,day,hours,mins,secs,millis). Works for all positive JDN
public static int[] toTimestamp(double mjd) {
int ymd_hms[] = { -1, -1, -1, -1, -1, -1, -1 };
int a, b, c, d, e, z;
double jd = mjd + 2400000.5 + 0.5; // if a JDN is passed as argument,
// omit the 2400000.5 term
double f, x;
z = (int) Math.floor(jd);
f = jd - z;
if (z >= 2299161) {
int alpha = (int) Math.floor((z - 1867216.25) / 36524.25);
a = z + 1 + alpha - (int) Math.floor(alpha / 4);
} else {
a = z;
}
b = a + 1524;
c = (int) Math.floor((b - 122.1) / 365.25);
d = (int) Math.floor(365.25 * c);
e = (int) Math.floor((b - d) / 30.6001);
ymd_hms[DAY] = b - d - (int) Math.floor(30.6001 * e);
ymd_hms[MONTH] = (e < 14)
? (e - 1)
: (e - 13);
ymd_hms[YEAR] = (ymd_hms[MONTH] > 2)
? (c - 4716)
: (c - 4715);
for (int i = HOURS; i <= MILLIS; i++) {
switch(i) {
case HOURS:
f = f * 24.0;
break;
case MINUTES: case SECONDS:
f = f * 60.0;
break;
case MILLIS:
f = f * 1000.0;
break;
}
x = Math.floor(f);
ymd_hms[i] = (int) x;
f = f - x;
}
return ymd_hms;
}
}
This answer has been provided here as well: How can I convert between a Java Date and Julian day number?. In the current post, references for the algorithm are provided along with some more discussion. The implementation of algorithms above also contains no Java API dependencies (aside from Math functions).

java.time
The java.time framework built into Java 8 and later supplants the old date-time classes bundled with the earliest versions of Java. See Oracle Tutorial. Much of the functionality has been back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
The java.time classes include the java.time.temporal.JulianFields. This class provides three implementations of TemporalField to give limited support for Julian date-only values (no time-of-day). So you can get whole number of days, not the double requested in the Question. Read that class doc closely to be sure it behaves to your expectations. Note that unlike most other java.time classes, these Julian classes ignore any offset-from-UTC or time zone information (always treated as a local date).
JULIAN_DAY → Count of whole days since day 0, which is January 1, 4713 BCE in the Julian calendar ( -4713-11-24 Gregorian ).
MODIFIED_JULIAN_DAY → Like JULIAN_DAY but subtracting 2_400_000.5 (basically dropping the first two digits of Julian date number). Note that results here are one fewer (-1) than Julian date number of item above.
RATA_DIE → Similar to the two items above in that it is a count of days from an epoch. But here the epoch is the ISO 8601 date of 0001-01-01.
In this example we start with the ISO 8601 date of 1970-01-01.
LocalDate localDate = LocalDate.of ( 1970 , 1 , 1 );
long julianDate = JulianFields.JULIAN_DAY.getFrom ( localDate );
long modifiedJulianDate = JulianFields.MODIFIED_JULIAN_DAY.getFrom ( localDate );
long rataDie = JulianFields.RATA_DIE.getFrom ( localDate );
localDate: 1970-01-01 | julianDate: 2440588 | modifiedJulianDate: 40587 | rataDie: 719163
ThreeTen-Extra
The ThreeTen-Extra project is the experimental proving grounds for possible future additions to java.time. The name comes from the JSR 310 that defines java.time.
This library includes additional support for Julian dates in its Julian calendar system (Chronology). Like the support in Java 8, this library is limited to date-only values (no partial days or time-of-day).
With this library you can instantiate JulianDate objects.
Many methods and features for you to examine there.

I know that this is not a Java Calendar API, but maybe you should try Jodd tool.
JulianDateStamp julianStamp = new JulianDateStamp(julianDays);
JDateTime jdate = new JDateTime(julianStamp);
Date date = new Date(jdate.getTimeInMillis());
This works perfect for:
2113488,2746855323 -> 1074.06.01 18:35
2453479,5866961805 -> 2005.04.19 02:04
Read more.

If you are willing to move outside the core JDK classes, then Joda can be a solution.
Joda supports the Julian calendar system. From their doc page:
Chronology julianChrono = JulianChronology.getInstance();
DateTime dt = new DateTime(1066, 10, 14, 0, 0, 0, julianChrono);
That would be the Battle of Hastings 1066 in the Julian Calendar system.

Related

CodenameOne - fixing Calendar get(Calendar.DAY_OF_WEEK) bigger value than expected

I am creating a workaround to fix the SimpleDateFormat "clone" class of CN1 in my app.
I cannot use other classes from pure Java.
I used this instruction in my CN1 app
int dayNumber=c.get(Calendar.DAY_OF_WEEK);
for handling the u letter in the format string.
At the time of the creation of this post it's Wednesday
dayNumber happens to have value of 4.
So I replaced that instruction with
int dayNumber=c.get(Calendar.DAY_OF_WEEK)-1;
because I found in Oracle documentation
Day number of week (1 = Monday, ..., 7 = Sunday)
I would like to know if it is correct
so that I have the 7 days of the week covered so it is just as
(1 = Monday, ..., 7 = Sunday)
and I can have the right u value for Java and Android compatibility.
I understand that java.time, the modern Java date and time API, is not yet part of CodeName One, and that therefore you cannot use it in your case. Apart from special situations like yours no one should use Calendar since it is poorly designed and long outdated. Everyone should use java.time.
To get (1 = Monday, ..., 7 = Sunday) from Calendar (the numbers that you would get by default from java.time):
int dayNumber = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7 + 1;
Seen under modulo 7 I am first adding 5, then 1, so 6 in total, which is the same as subtracting 1. I am using this trickery to make sure I get a number in the 1 through 7 interval (which we don’t always by simply subtracting 1 from the return value from Calendar).
I am demonstrating the edge cases and using java.time for it:
LocalDate ld = LocalDate.of(2021, Month.SEPTEMBER, 5);
ZonedDateTime startOfDay = ld.atStartOfDay(ZoneId.of("Etc/UTC"));
Calendar c = GregorianCalendar.from(startOfDay);
int dayNumber = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7 + 1;
System.out.format("%s: %s = %d%n", ld, ld.getDayOfWeek(), dayNumber);
ld = ld.plusDays(1);
startOfDay = ld.atStartOfDay(ZoneId.of("Etc/UTC"));
c = GregorianCalendar.from(startOfDay);
dayNumber = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7 + 1;
System.out.format("%s: %s = %d%n", ld, ld.getDayOfWeek(), dayNumber);
Output is:
2021-09-05: SUNDAY = 7
2021-09-06: MONDAY = 1
Disclaimer: I don’t know the CodeName One Calendar in particular. I strongly expect it to behave exactly the same as the original java.util.Calendar, and my answer is based on the assumption that it does.

Java LocalDateTime minusYears for floating number of years

Java LocalDateTime minusYears takes long argument. In case, if I want to minus floating number of year eg. 2.5 years, how can I do that?
Is there any in-built support?
Note: I take both value and unit as input from the user. The above question is bit of generalization (I have same problem with respect to hours, years, weeks etc.). Sometime it can be 2.7 hours or 2.8 years or 5.3 weeks etc
You don't have any built-in support for that but you can do that easily by converting the year value in month (* 12):
float year = 2.5F;
LocalDateTime dateTime = dateTime.minusMonths((int)(year * 12);
And you can also create a util method if required:
public static LocalDateTime removeYear(LocalDateTime dateTime, float year) {
int monthToRemove = (int)(year * 12);
return dateTime.minusMonths(monthToRemove);
}
By testing it with :
public static void main(String[] args) {
LocalDateTime date = removeYear(LocalDateTime.now(), 2.5F);
System.out.println(date);
}
Output :
2016-01-31T16:33:26.755
Note that to make the method more robust you could check that year represent a float that accept only some kinds of values such as zero for the fractional part (2.0) or some fractional such as 0.5.
What about :
double years = 2.5;
long months = (long) (years * 12);// 30 month
LocalDateTime ld = LocalDateTime.now();
ld = ld.minusMonths(months);
But Note this can lose some days for example if you have :
years = 2.7
=>years * 12 > 32.400000000000006
so here you can lose 0.400000000000006 month.
So maybe if you round it, it can be more helpful :
long months = Math.round(years * 12);
Edit :
based on your comment :
Actually I take both value and unit as input. The above question is
bit of generalization. Sometime it can be 2.7 hours or 2.8 years or
5.3 weeks etc
I think you need something like this :
But be careful with months
public static LocalDateTime changeDate(LocalDateTime date, float time, String unit) {
long newTime;
switch (unit) {
case ("hour"):
newTime = Math.round(time * 60);
date = date.minusMinutes(newTime);// If hours then subtract minutes
break;
case ("day"):
newTime = Math.round(time * 24);
date = date.minusHours(newTime);// If days then subtract hours
break;
case ("week"):
newTime = Math.round(time * 7);
date = date.minusDays(newTime);// If week then subtract days
break;
case ("month"):
newTime = Math.round(time * 30);// here You have to check again
date = date.minusDays(newTime);// If month then subtract days
break;
case ("year"):
newTime = Math.round(time * 12);
date = date.minusMonths(newTime);// If days then subtract months
break;
default:
break;
}
return date;
}
You can utilise both the minusYears and minusMonth methods to do the job.
example:
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime result = dateTime.minusYears(2).minusMonths(6);
When you say "2.5" years I am assuming you mean "two years and a half" as opposed to "two years and 5 months" but yeah you can correct that anyway if need be.
There's no built in support, but you can do this, if you want to sacrifice precision:
public static void main(String[] args) {
LocalDate ld = LocalDate.of(2015, 12, 1);
System.out.println(minusFpYears(ld, 2.5f));
}
static LocalDate minusFpYears(LocalDate ld, float fpyears) {
float fpmonths = fpyears % 1;
long years = (long)(fpyears - fpmonths);
long months = (long)(12L * fpmonths);
return ld.minusYears(years).minusMonths(months);
}
Thanks for the code! Actually I take both value and unit as input. The
above question is bit of generalization. Sometime it can be 2.7 hours
or 2.8 years or 5.3 weeks etc.
Make LocalDate minusFpWeeks(LocalDate ld, float fpweeks), LocalDateTime minusFpHours(LocalDateTime ld, float fphours) etc functions, to handle that.

Find Day of Week Without Using Calendar function in Java

I need to find the day of the week (i.e. Monday, Tuesday...) given MM-DD-YYYY. So basically what java calendar would do, but without using java calendar.
It is possible, though unusual, to compute a number that corresponds to the day of the week from a calendar date.
In brief, you will first need to calculate a serial date number from the calendar date, i.e. a number that is a continuous count of days that have elapsed since a certain fixed point in time (informally called 'the epoch'). The most commonly encountered serial date scheme encountered in modern computing is Posix Time, which has an epoch date of Jan 1, 1970 at midnight UTC.
You will need to decide what level of precision is needed for this calculation, eg. whether you will need to account for the Julian Calendar (used in most of Europe before the Gregorian Calendar reform by Pope Gregory in 1584), whether to correct for century days, etc.
Several algorithms are available to arithmetically convert a calendar date to a serial date number with a given epoch. Historically, the most commonly used epoch for these calculations has been the Julian Day number system (not to be confused with the Julian Calendar), which counts days from November 24, 4714 BC in the proleptic Gregorian calendar. Below is Java code which implements one such algorithm published by Jean Meeus in his book "Astronomical Algorithms, 2nd Ed." This algorithm computes a Julian Day number and assumes that days are exactly 86400 seconds in length, accounts for the general Gregorian Reform, and accounts for century and leap days:
public class JulianDay {
private static final int YEAR = 0;
private static final int MONTH = 1;
private static final int DAY = 2;
private static final int HOURS = 3;
private static final int MINUTES = 4;
private static final int SECONDS = 5;
private static final int MILLIS = 6;
:
:
// Converts a timestamp presented as an array of integers in the following
// order (from index 0 to 6): year,month,day,hours,minutes,seconds,millis
// month (1-12), day (1-28 or 29), hours (0-23), min/sec (0-59) to a
// Julian Day Number.
// For clarity and simplicity, the input values are assumed to be well-formed;
// error checking is not implemented in the snippet.
public static double toJD(int[] ymd_hms) {
int y = ymd_hms[YEAR];
int m = ymd_hms[MONTH];
double d = (double) ymd_hms[DAY];
d = d + ((ymd_hms[HOURS] / 24.0) +
(ymd_hms[MINUTES] / 1440.0) +
(ymd_hms[SECONDS] / 86400.0) +
(ymd_hms[MILLIS] / 86400000.0));
if (m == 1 || m == 2) {
y--;
m = m + 12;
}
double a = Math.floor(y / 100);
double b = 2 - a + Math.floor(a / 4);
return (Math.floor(365.25 * (y + 4716.0)) +
Math.floor(30.6001 * (m + 1)) +
d + b - 1524.5);
}
}
Once you have a serial date number, it is straightforward to compute the day of the week from the remainder when the date number is divided by 7 (the number of days in a week).
If you are talking about simply avoiding the Calendar Object then you could use the Date Object (deprecated) but still works and call setMonth, setYear, and setDate to get the desired date. You then have to use a DateFormatter to get your desired output. I used a SimpleDateFormat and the E specifier to get the day of the week.
Date dNow = new Date();
SimpleDateFormat ft = new SimpleDateFormat ("E");
System.out.println("Current Date: " + ft.format(dNow));
This outputs the current day of the week "Sun", "Sat", etc..
This link will help with the formatting https://www.tutorialspoint.com/java/java_date_time.htm
java.time
Using the java.time classes that supplant the troublesome old date-time classes. The LocalDate class represents a date without a time-of-day and without a time zone.
DayOfWeek dow =
LocalDate.parse(
"01-23-2016" ,
DateTimeFormatter.ofPattern( "MM-dd-uuuu" )
).getDayOfWeek()
That code returns a DayOfWeek enum object. From there you can interrogate for:
Integer number, 1-7 for Monday-Sunday
Localized name of the day.
Example code.
int dowNumber = dow.getValue() ;
String dowName = dow.getDisplayName(
TextStyle.FULL ,
Locale.CANADA_FRENCH ) ; // Or Locale.US, Locale.ITALY, etc.
TIP: Pass around the DayOfWeek objects themselves in your own code, rather than internally track the day-of-week as a number or string. This makes your code more self-documenting, ensures valid values, and provides for type-safety.
I was looking for the answer myself and found another answer based on Zeller's algorithm:
// d = day in month
// m = month (January = 1 : December = 12)
// y = 4 digit year
// Returns 0 = Sunday .. 6 = Saturday
public int dow(int d, int m, int y) {
if (m < 3) {
m += 12;
y--;
}
return (d + int((m+1)*2.6) + y + int(y/4) + 6*int(y/100) + int(y/400) + 6) % 7;
}
Source: here

Java.util.Date() behavior [duplicate]

I am doing some date calculations in Java using milliseconds and noticing an issue with the following:
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
I know that that 1 Year is roughly = 31,556,952,000 Milliseconds, so my multiplication is off somehow.
Can anyone point out what I am doing wrong? Should I be using a long?
Should I be using a long?
Yes. The problem is that, since MILLIS_IN_SECOND and so on are all ints, when you multiply them you get an int. You're converting that int to a long, but only after the int multiplication has already resulted in the wrong answer.
To fix this, you can cast the first one to a long:
private static final long MILLISECONDS_IN_YEAR =
(long)MILLIS_IN_SECOND * SECONDS_IN_MINUTE * MINUTES_IN_HOUR
* HOURS_IN_DAY * DAYS_IN_YEAR;
If on android, I suggest:
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
While others have already pointed out arithmetic overflow, you can also try TimeUnit to solve the problem:
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 * ...
All the operands on the right hand side are ints, so the multiplication is done with 32bit signed integers, which overflows. Cast the first one to long and you'll get the expected value.
private static final long MILLISECONDS_IN_YEAR = (long)MILLIS_IN_SECOND * ...
You're overflowing the int type. In Java, the result of a primitive arithmethic operation over two ints is an int. The type of the operands decides this, not the type of the result variable. Try:
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;
You need a long. Ints wrap around 2 billion.
To fix this, you can put the letter L after the first one: e.g. 1000L
long MILLS_IN_YEAR = 1000L * 60 * 60 * 24 * 365; // Returns 31536000000
tl;dr
The Answer by Ruakh is correct about your use of int vs long (integer overflow) being the cause of a totally wrong number, 1471228928. But furthermore, your Question raises issue of solar year versus calendar year.
I know that that 1 Year = 31556952000 Milliseconds
No, that would be the length of a solar year, not a calendar year. A calendar year is 31,536,000,000 milliseconds.
The modern java.time classes and ChronoUnit can calculate the calendar year number.
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.
) ;
31536000000
31,556,952,000 = Solar year
Your source is using an approximation of the length of a solar year, about 365.2425 24-hour days. This is the amount of time it takes the earth to orbit the sun.
The math:
365.2425 * 24 * 60 * 60 * 1000 = 31,556,951,999.999996 ≈ 31,556,952,000 ms
See this calculator.
31,536,000,000 = Calendar year
In the Western calendar (Gregorian/ISO), we use years of an even 365 24-hour days, ignoring the fact that the earth's orbit around the sun takes an extra quarter day. We make up for the discrepancy by inserting an extra day every four years (roughly, years which are multiples of four with the exception of years divisible by 100 but not by 400), the Leap Day.
Considering a plain year of 365 days with 24-hour days and no anomalies to account for such as Daylight Saving Time (DST), a calendar year is 31,536,000,000 milliseconds long. Not 31,556,952,000 as you suggest in your Question.
31,536,000,000 = ( 365 * 24 * 60 * 60 * 1000 )
See this calculator.
A Leap Year with 366 days will be 31,622,400,000 milliseconds.
31,622,400,000 = ( 366 * 24 * 60 * 60 * 1000 )
java.time
The modern java.time classes supplant the old date-time classes bundled with the earliest versions of Java. Those old classes have proven to be confusing and troublesome.
ChronoUnit
Leap year and other anomalies might mean an unexpected number of milliseconds in a year. So you should let java.time do an actual calculation, if precision is important in your situation.
The ChronoUnit class can calculate elapsed time in a certain unit.
long millisInYear = ChronoUnit.MILLIS.between( start , stop );
We need to determine the exact moment of the start of the first day day of the year and of the following year. We do that by going through the LocalDate class, which represents a date-only value without a time-of-day and without a time zone.
LocalDate startLd = LocalDate.of ( 2015 , 1 , 1 );
LocalDate stopLd = startLd.plusYears ( 1 );
By assigning a time zone (ZoneId) we get ZonedDateTime objects for specific moments on the timeline.
ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime start = startLd.atStartOfDay ( z );
ZonedDateTime stop = stopLd.atStartOfDay ( z );
Lastly, calculate the elapsed time in milliseconds.
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
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
try this
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

Bug in Java Calendar / Date for 2nd October 2010?

I'm not sure what I'm doing wrong, but I've got a piece of code which calculates the number of days between two dates, and which looks something like the following:
final Calendar first = new GregorianCalendar(2010, Calendar.OCTOBER, 1);
final Calendar last = new GregorianCalendar(2010, Calendar.NOVEMBER, 1);
final long difference = last.getTimeInMillis() - first.getTimeInMillis();
final long days = difference / (1000 * 60 * 60 * 24);
System.out.println("difference: " + difference);
System.out.println("days: " + days);
To summarise, the code block above calculates the number of days between 1st October 2010 and 1 November 2010. I'm expecting to see it return 31 days (seeing as there's 31 days in October)
difference: xxxx
days: 31
but instead it's showing 30 days in October!
difference: 2674800000
days: 30
I've managed to narrow it down to between the the dates 2 October 2010 and 3 October 2010, which seems to only have 82800000 milliseconds, instead of a full 86400000 milliseconds (exactly one hour missing).
Does anyone have any ideas what I'm doing wrong? Or is the 2nd October a special date which has one minute less than a regular day?
(86400000 - 82800000)/1000 = 3600, which is one hour. You're seeing daylight savings time, combined with the rounding of integer math
You could get around it by doing the calculations with floating point numbers and rounding at the end, or you could check out a library like Joda time which offers much better date math than what's built in.
You may be better off comparing the year and day or year instead of the milliseconds that pass in a day.
int lastYear= last.get(Calendar.YEAR);
int firstYear= first.get(Calendar.YEAR);
int lastDayofYear = last.get(Calendar.DAY_OF_YEAR);
int firstDayofYear = first.get(Calendar.DAY_OF_YEAR);
int nDaysElapse = lastDayofYear - firstDayofYear;
int nYearsElapse = lastYear- firstYear;
int days = (nYearsElapse*365)+nDaysElapse;
You should read this post to get a better understanding of how Calendar is interrelated with date/time stamps.
Having read that site, my initial questions were:
What do you mean by days? Do you mean '24-hour blocks' or do you mean calendar days? In the same vein, do you care if you are off slightly due to daylight savings etc?
If you mean Calendar days, your best bet is probably to:
final Calendar first = new GregorianCalendar(2010, 9, 1);
final Calendar last = new GregorianCalendar(2010, 10, 1);
Calendar difference = Calendar.getInstance();
difference.setTimeInMillis(last.getTimeInMillis() - first.getTimeInMillis());
int numDays = difference.get(Calendar.DAY_OF_YEAR) - difference.getMinimum(Calendar.DAY_OF_YEAR);
Of course, the above code will only work if the number of days < 365. You will need to create a rolling calculation e.g.
int yearDiff = last.get(Calendar.YEAR) - first.get(Calendar.YEAR);
Calendar tmp = new GregorianCalendar();
tmp.setTimeInMillis(first.getTimeInMillis());
for(int i = 0; i < yearDiff; i++) {
numDays += tmp.getActualMaximum(Calendar.DAY_OF_YEAR);
i++;
tmp.add(Calendar.YEAR, 1);
}
This should allow you to get the number of days in a correct and consistent manner, without worrying about Daylight Savings, Leap Years etc.
That said, JodaTime probably has this functionality built in.
The answer by Brad Mace is correct.
Use a Library
This question is a good example of why you should use a good date-time library wither than roll your own. For Java that means using either Joda-Time or the new java.time package in Java 8.
Joda-Time
Example code in Joda-Time.
DateTimeZone timeZone = DateTimeZone.forID( "Australia/Melbourne" );
DateTime theFirst = new DateTime( 2014, DateTimeConstants.OCTOBER, 1, 0, 0, 0, timeZone ).withTimeAtStartOfDay();
DateTime nextMonth = theFirst.plusMonths( 1 ).withTimeAtStartOfDay();
int days = Days.daysBetween( theFirst, nextMonth ).getDays();
Or if you don't care about time-of-day, use the LocalDate class.
java.time
Java 8 and later comes with a new java.time framework to supplant the old java.util.Date/.Calendar classes. Inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.
Example code using Java 8. Note that the enum ChronoUnit returns a 64-bit long rather than int.
LocalDate firstOfOctober = LocalDate.of( 2010 , java.time.Month.OCTOBER , 1 );
LocalDate nextMonth = firstOfOctober.plusMonths( 1 );
long daysInMonth = ChronoUnit.DAYS.between( firstOfOctober , nextMonth );
The code you put in your post is calculating the time between September 1 and October 1, not October 1 and November 1. The output is correct for the code you posted.

Categories

Resources