Win a copy of Functional Reactive Programming this week in the Other Languages forum!

# Adding days to January 1, 1900

Ron Rea
Greenhorn
Posts: 23
I am trying to convert a 5 digit numeric number to a date with a format of MM/DD/YYYY. The 5 digit number represents the number of days since January 1, 1900 - where January 1, 1900 = 1.
Any ideas on how to, for example, turn 37106 into 08/03/2001?
Thanks.

Jim Yingst
Wanderer
Sheriff
Posts: 18671
Well, java.util.Date has methods to convert to and from the number of milliseconds since Jan 1, 1970. (This value can be negative.) So you can get a Date for Jan 1, 1900, nad convert it into milliseconds. Then add (number_of_days * milliseconds_per_day), and convert the resulting milliseconds into a Date. Then use a DateFormat to print the Date as a String in the desired format.

Joshua Bloch
Author and "Sun God"
Ranch Hand
Posts: 124
Ron,
Hi. This sort of thing should be easy with Calendar, but unfortunately it isn't. Often the easiest way to deal with dates is as longs representing milliseconds since the beginning of the "epoch" (January 1, 1970, 00:00:00 GMT). Besides being predictable and fast, dates represented in this fashion are immutable, which has many advantages (discussed in Item 13: Favor immutability).
Here's a little program that solves your problem using this technique:
<pre>
import java.util.*;
public class ConvertDate {
// The number of ms in a day
static final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000;
// The number of ms since 1/1/1970 representing 1/1/1900
static final long START = -2208988800000L;
public static void main(String[] args) {
int daysSinceStart = Integer.parseInt(args[0]) - 1;
long millisSinceStart = daysSinceStart * MILLIS_PER_DAY;
System.out.println(new Date(START + millisSinceStart).toGMTString());
}
}
</pre>
This program isn't quite politically correct as it uses the toGMTString method, which was deprecated in 1.1. Arguably it should not have been deprecated, but that's water over the dam. Feel free to replace this call with the appropriate DateFormat call if you wish.
Regards,
------------------
Joshua Bloch
Author of Effective Java

Joshua Bloch
Author and "Sun God"
Ranch Hand
Posts: 124
Wow! Jim and I -- independently, I swear -- suggested exactly the same thing at nearly the same time.
I should point out that there's a tiny error in the original post - if 1 represents 1/1/1900, then 37106 represents 08/04/2001. Perhaps you meant to say that 0 represents 1/1/1900, in which case remove the "- 1" from the daysSinceStart computation in my program.
Regards,

------------------
Joshua Bloch
Author of Effective Java

Jim Yingst
Wanderer
Sheriff
Posts: 18671
Wow! Jim and I -- independently, I swear -- suggested exactly the same thing at nearly the same time.

What are you talking about? I beat you by over two hours.
For amusement, here's the version I had written. Note that we share one variable name as well - though I suppose it was reasonably obvious.
<code><pre>
public class DateConverter {

private static DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
private static long JAN_1_1900_MILLIS;
static {
try {
JAN_1_1900_MILLIS = formatter.parse("01/01/1900").getTime();
}
catch (ParseException e) {
e.printStackTrace();
}
}

private static final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;

public static Date getDate(int days) {
long millis = JAN_1_1900_MILLIS + days * MILLIS_PER_DAY;
return new Date(millis);
}

public static String getDateString(int days) {
return formatter.format(getDate(days));
}

public static void showConversion(int days) {
System.out.println(days + " days after 01/01/1900 = " + getDateString(days));
}

public static void main(String[] s) {
showConversion(0);
showConversion(1);
showConversion(365);
showConversion(37106);
}
}
</pre></code>
I should point out that there's a tiny error in the original post...

Actually there are two. "The 5 digit number represents the number of days since January 1, 1900" - this is a nice unambiguous definition or the meaning of the number which is subsequently contradicted by "January 1, 1900 = 1". I implemented the former statement and ignored (overlooked, really ) the latter. Depending on which of these two interpretations is chosen, the date for 37106 is either 08/04/2001 (Josh's version), or 08/05/2001 (my version). I don't see a way to get 08/03/2001.
[This message has been edited by Jim Yingst (edited July 11, 2001).]

Joshua Bloch
Author and "Sun God"
Ranch Hand
Posts: 124
Originally posted by Jim Yingst:
Wow! Jim and I -- independently, I swear -- suggested exactly the same thing at nearly the same time.

What are you talking about? I beat you by over two hours.

Actually I think there may be timezone issues at work. Your messages consistently come out with times later than those on my machine's clock. Who knows? Anyway you slice it, it's past my bedtime
By the way, you are, of course, correct that the original post listed two inconsitent descriptions of the integer date. That's why I suggested that Ron probably intended 0 to represent 1/1/1900. Well, it looks like we've beaten this one to death.
G'night,

------------------
Joshua Bloch
Author of Effective Java

Rajesh Pohuja
Greenhorn
Posts: 6
Originally posted by Joshua Bloch:
This sort of thing should be easy with Calendar, but unfortunately it isn't.

I am not sure of the proper way to do such conversion but
you can use Calendar to do it. Here is a modified version
of Jim's DateConverter class without all those calculations.
It produces same results.

Rajesh Pohuja
Greenhorn
Posts: 6
Another advantage of using java.util.Calendar is that it handles pre-1600 dates correctly, just in case you need to convert from those dates

Jim Yingst
Wanderer
Sheriff
Posts: 18671
Actually I think there may be timezone issues at work.

Eh? I'm in Santa Clara. How many time zones is that from Cupertino, anyway?
Seriously - the JavaRanch server is in Colorado, so all our messages are timestamped Mountain Standard Time. Which of course should affect us both equally.
Sorry, I was feeling a bit obnoxiously competetive yesterday. Someone recently accused me of being "too nice", so I thought I should work to change that.

Hagar Nishaachar
Greenhorn
Posts: 4
While on the topic of Date calculations, can someone suggest how I can add x months to a date.
ie. newDate = oldDate + x
Where 'x' is term in months.
Thanks,
Hagar

Joel McNary
Bartender
Posts: 1840
Hagar da orrible:
Welcome to JavaRanch!
We don't have many rules here at JavaRanch, but we do have one. Please change your display name to comply with The JavaRanch Naming Policy. (We are looking for names that are not obviously fictitious.)
To answer your question, you should use the functions in the java.util.Calendar class.

(Edited to show correct semantics...field, then increment -- JAM)
[ September 04, 2003: Message edited by: Joel McNary ]

Hagar Nishaachar
Greenhorn
Posts: 4
Thanks !
Name change is done.

Wayne L Johnson
Ranch Hand
Posts: 399
Not to nitpick, but I think it's:
...
aCalendar.add(Calendar.MONTH, x); // FIELD, then amount
...
The amount can be positive or negative.

Hagar Nishaachar
Greenhorn
Posts: 4
Yes Mate that correct.
Thanks for the pointer.
cheers
Hagar