Calculating a day given a Date - java

From a given Date I need to calculate midnight of its day. Here's what I came up with. It's so ugly that I figure there must be a better way.
private Date day(Date creation) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(creation);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
Suggestions?
Kent

You should consider the built-in date API obselete. Instead use the Joda date and time API.
Here's a drop-in replacement for your method.
private Date day(Date creation) {
return new DateMidnight(creation).toDate();
}
Here's a simple test:
public static void main(String[] args) {
final Date creation = new Date();
final Date midnight = new Foobar().day(creation);
System.out.println("creation = " + creation);
System.out.println("midnight = " + midnight);
}
The output is:
creation = Sun May 31 10:09:38 CEST 2009
midnight = Sun May 31 00:00:00 CEST 2009

JODA might have a better solution, at the cost of another dependency on a library. I'm looking at its DateMidnight property. I'm sorry that I can't answer more authoritatively, but I'm not a JODA user myself.

If you're looking for local time, that's the best you're going to get. And although you may consider it ugly, there's (potentially) a lot going on behind the scenes.
If you want midnight UTC, the following will work:
public static void main(String[] argv)
throws Exception
{
final long MILLIS_PER_DAY = 24 * 3600 * 1000L;
long midnightUTC = (System.currentTimeMillis() / MILLIS_PER_DAY) * MILLIS_PER_DAY;
}
Edit: I really don't recommend using local dates in "production" code. They cause more trouble than they're worth -- consider a person on the US west coast who suddenly finds his/her "day" trimmed by 3 hours because an east coast computer has a different idea of midnight.

JODA is the way to go if you have serious calendar needs, at least until JSR-310 gets into the JDK (1.7 maybe, if not 1.8).
That being said, there are a couple of things that could be done to make this code a little nicer.
import static java.util.Calendar.*;
...
private static final List<Integer> TIME_FIELDS =
Arrays.asList(HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND);
private Date day(Date creation) {
Calendar c = getInstance();
c.setTime(creation);
for(int field : TIME_FIELDS) c.set(field, 0);
return c.getTime();
}
That won't win any performance awards. You could do a standard for loop relying on the specific field values (the Calendar class has a FIELD_COUNT field kind of implying you can do something like that) but that risks issues across JDK implementations and between versions.

Using the date4j library :
DateTime start = dt.getStartOfDay();

I think the only way you're going to make this code significantly better is by a change in representation. For example,
Represent the day by the "absolute date" system explained by Nachum Dershowitz and Ed Reingold in Calendrical
Calculations.
Represent the time by counting seconds from midnight. Or if you need sub-second resolution, count milliseconds.
From your brief example I can't tell at what points in your program you need to be compatible with existing Date and Calendar classes, or if you can create a useful subclass using a saner representation.

Haven't programmed Java in a while, but you might be able to call this set method passing in the current values for year, month, and day. Although from reading a little close, you may have to call clear first. This may or may not be less verbose than using your current method.

This is just the complement of the originally posted code. It sets the Year, Month, and Day in a new GregorianCalendar object, instead of clearing everything but the Year, Month, and Day in the calendar variable. It's not much of an improvement, but I think it's clearer to say which fields you are copying, instead of which fields you're ignoring.
public Date day(Date creation) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(creation);
return new GregorianCalendar(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)).getTime();
}
Personally, I think I'd go with the Joda library proposed by others.

Related

JODA time wrong values on each iteration

i am trying Joda time in java using the latest version 2.2 i have written a small snippet here is my code
public static void main(String[] args)
{
BoilerTester clazz = new BoilerTester();
Calendar today = Calendar.getInstance();
Calendar born = Calendar.getInstance();
//when returns 0 is 10363 when returning 1 = 10362 just a millisecond what have to do with days??
System.out.println(Math.abs(today.getTimeInMillis()-born.getTimeInMillis()));
born.set(1984,10,20);
clazz.compute(born,today);
}
private void compute(Calendar born, Calendar today)
{
System.out.println("JODA: " + org.joda.time.Days.daysBetween(new org.joda.time.DateTime(born.getTime()),new org.joda.time.DateTime(today.getTime())).getDays());
}
when i run the source code i am getting this values
JODA: 10363
later I run the same code and I am getting
JODA: 10362
Yes i have run maybe 2 or 3 times the same code to get different values but why this???
thanks a lot.
My guess is that sometimes, the today and born dates are on the exact same millisecond, and sometimes they differ by a few milliseconds (the time that elapses between the first call to Calendar.getInstance() and the second one). Since getDays() returns the number of complete days, a few milliseconds could make a difference.
I was writing my answer but JB Nizet was faster (he is absolutely right on what is happening). If you want to get rid of this kind of problems, you should leverage the concept of partial in joda-time:
A partial in Joda-Time is a partial date and time representation. All implementations represent local dates and times, and do not reference a time zone. As such, they only partially represent a date or time in the datetime continuum.
For example, with a LocalDate:
LocalDate born = new LocalDate(1984, 11, 20); // BE CAREFUL!: months in JDK are 0-11, but in Joda-Time are 1-12
System.out.println(Days.daysBetween(born, LocalDate.now()).getDays());
With this "partial" representation, you are not using hours, minutes, seconds or milliseconds internally, so you cannot face this problem due to milliseconds.
You're running a mix of JDK and Joda -- don't do that -- Joda replaces the JDK time classes completely.

Calendar.getTime().getYear() gives back 0113 instead of 2013

I'm making a little game. When the game is starting for the first time i saves the time since 01.01.1970 in seconds in the SharedPreferences.
Now i want to give this date out on my screen in this form: DD.MM.YYYYY
I used the Calendar function but it give back 02.04.0113 so, there are missing 1900 Years.
Here is my Code:
private void initBornTXT() {
SharedPreferences pref = getSharedPreferences("LIFE", 0);
long born = pref.getLong("BIRTHDAY", 0);
Calendar c = Calendar.getInstance();
c.setTimeInMillis(0);
c.add(Calendar.SECOND, (int)born);
int year = c.getTime().getYear();
int month = c.getTime().getMonth();
int day = c.getTime().getDay();
String string_born = String.format("%02d.%02d.%04d", day, month, year);
TextView born_txt = (TextView)findViewById(R.id.textViewBorn);
born_txt.setText(string_born);
}
What coud be wrong?
Nothing's wrong. You've just not looked at the documentation for the method you're calling, Date.getYear():
Returns a value that is the result of subtracting 1900 from the year that contains or begins with the instant in time represented by this Date object, as interpreted in the local time zone.
Note that you should have received a warning that you're using a deprecated API: don't just ignore those warnings.
Also, do yourself a favour and don't do the formatting yourself: use SimpleDateFormat instead. (Or ideally, use Joda Time instead...) That way you can avoid the month being wrong, too... you may not have noticed that you're a month off due to months being 0-based, which is common to both Calendar and Date.
That's normal, documented behavior. See JavaDoc for Date#getYear().
A better way to get the year would be:
c.get(Calendar.YEAR)
You're using getTime, which returns a date object. Dates are based on 0=1900. So this is the expected output. Use a SimpleDateFormat instead.
Kudos for creating a Y2K bug though :)

Calendar.Month gives wrong output

I have been using java.util for all date and calendar representations. But I am facing a strange problem here. Calendar.MONTH, Calendar.DAY_OF_MONTH, etc all give wrong outputs. But when I use Calendar.getTime(), I get the right output. What might be the problem?
public class TestClass {
public static void main(String[] args) {
Calendar rightNow = Calendar.getInstance();
System.out.println(rightNow.MONTH);
System.out.println(rightNow.DAY_OF_MONTH);
System.out.println(rightNow.YEAR);
System.out.println(rightNow.getTime());
}
}
And the output for the same is:
2
5
1
Tue Jan 22 10:31:44 GMT+05:30 2013
System.out.println(rightNow.MONTH);
System.out.println(rightNow.DAY_OF_MONTH);
System.out.println(rightNow.YEAR);
System.out.println(rightNow.getTime());
You are printing Calendar constant values.
If you want values, you need to do get....
Example:
System.out.println(rightNow.get(Calendar.MONTH));
Read Calendar javadoc for more information.
Calendar.MONTH doesn't return the current month. It is a constant whose value is 2.
From the source:
public final static int MONTH = 2;
It is for use as a parameter in Calendar's get method
public int get(int field) {...}
The design of Calendar is from the early days of Java, when many of today's conventions were different, non-existant, or developing. Oracle (and earlier, Sun), would never let an API like the java.util.Calendar API become part of the standard API today.
And, for completeness, use Joda Time instead of Java's Date and Calendar API's.
java.time
ZonedDateTime rightNow = ZonedDateTime.now(ZoneId.of("Africa/Cairo"));
System.out.println(rightNow.getMonth());
System.out.println(rightNow.getMonthValue());
System.out.println(rightNow.getDayOfMonth());
System.out.println(rightNow.getYear());
System.out.println(rightNow);
Output when running just now was:
FEBRUARY
2
15
2019
2019-02-15T21:15:06.313809+02:00[Africa/Cairo]
Don’t use Calendar
The Calendar class is confusing and suffers from poor design, so no wonder that you’re wondering. Fortunately it was replaced the year after you asked this quesion by ZonedDateTime and other classes in java.time, the modern Java date and time API. So never use Calendar again now.
The Calendar class was trying to be very general, so instead of a getMonth method, etc., it had the notion of fields that could be read and set. Since it was designed long before Java had enums, each field had a number and a named constant for that number. So YEAR (of era) was 1, MONTH was 2, etc. To get the value of the field of a Calendar object you were supposed to call the get method passing the appropriate named constant, for example rightNow.get(Calendar.MONTH). Using just rightNow.MONTH is a regularly repeated mistake. It just gives you the value of the constant, 2.
Link
Oracle tutorial: Date Time explaining how to use java.time.
Calendar now = Calendar.getInstance();
out.println("month now= " + (now.get(Calendar.MONTH)+1));
OR with GregorianCalender:
GregorianCalendar nu = new GregorianCalendar();
int day = nu.get(Calendar.DAY_OF_MONTH);
int month = (nu.get(Calendar.MONTH)+1); //month +1 because january`==0
int year= nu.get(Calendar.YEAR);
int hour= nu.get(Calendar.HOUR_OF_DAY);
int minutes= nu.get(Calendar.MINUTE);
here

How to generate a Date from just Month and Year in Java?

I need to generate a new Date object for credit card expiration date, I only have a month and a year, how can I generate a Date based on those two? I need the easiest way possible. I was reading some other answers on here, but they all seem too sophisticated.
You could use java.util.Calendar:
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
Date date = calendar.getTime();
java.time
Using java.time framework built into Java 8
import java.time.YearMonth;
int year = 2015;
int month = 12;
YearMonth.of(year,month); // 2015-12
from String
YearMonth.parse("2015-12"); // 2015-12
with custom DateTimeFormatter
import java.time.format.DateTimeFormatter;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM yyyy");
YearMonth.parse("12 2015", formatter); // 2015-12
Conversions
To convert YearMonth to more standard date representation which is LocalDate.
LocalDate startMonth = date.atDay(1); //2015-12-01
LocalDate endMonth = date.atEndOfMonth(); //2015-12-31
Possibly a non-answer since you asked for a java.util.Date, but it seems like a good opportunity to point out that most work with dates and times and calendars in Java should probably be done with the Joda-Time library, in which case
new LocalDate(year, month, 1)
comes to mind.
Joda-Time has a number of other nice things regarding days of the month. For example if you wanted to know the first day of the current month, you can write
LocalDate firstOfThisMonth = new LocalDate().withDayOfMonth(1);
In your comment you ask about passing a string to the java.util.Date constructor, for example:
new Date("2012-09-19")
This version of the constructor is deprecated, so don't use it. You should create a date formatter and call parse. This is good advice because you will probably have year and month as integer values, and will need to make a good string, properly padded and delimited and all that, which is incredibly hard to get right in all cases. For that reason use the date formatter which knows how to take care of all that stuff perfectly.
Other earlier answers showed how to do this.
Like
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM");
Date utilDate = formatter.parse(year + "/" + month);
Copied from Create a java.util.Date Object from a Year, Month, Day Forma
or maybe like
DateTime aDate = new DateTime(year, month, 1, 0, 0, 0);
Copied from What's the Right Way to Create a Date in Java?
The most common sense approach would be to use the Date("YYYY-MM-DD") constructor even though it is deprecated. This is the easiest way to create a date on the fly. Screw whoever decided to deprecate it. Long live Date("YYYY-MM-DD")!!!
Don’t use this answer. Use the answers by Przemek and Ray Toel. As Przemek says, prefer to use a YearMonth for representing year and month. As both say, if you must use a date, use LocalDate, it’s a date without time of day.
If you absolutely indispensably need an old-fashioned java.util.Date object for a legacy API that you cannot change, here’s one easy way to get one. It may not work as desired, it may not give you exactly the date that you need, it depends on your exact requirements.
YearMonth expiration = YearMonth.of(2021, 8); // or .of(2021, Month.AUGUST);
Date oldFashionedDateObject = Date.from(expiration
.atDay(1)
.atStartOfDay(ZoneId.systemDefault())
.toInstant());
System.out.println(oldFashionedDateObject);
On my computer this prints
Sun Aug 01 00:00:00 CEST 2021
What we got is the first of the month at midnight in my local time zone — more precisely, my JVM’s time zone setting. This is one good guess at what your legacy API expects, but it is also dangerous. The JVM’s time zone setting may be changed under our feet by other parts of the program or by other programs running in the same JVM. In other words, we cannot really be sure what we get.
The time zone issue gets even worse if the date is transmitted to a computer running a different time zone, like from client to server or vice versa, or to a database running its own time zone. There’s about 50 % risk that your Date will come through as a time in the previous month.
If you know the time zone required in the end, it will help to specify for example ZoneId.of("America/New_York") instead of the system default in the above snippet.
If your API is lenient and just needs some point within the correct month, you’ll be better off giving it the 2nd of the month UTC or the 3rd of the month in your own time zone. Here’s how to do the former:
Date oldFashionedDateObject = Date.from(expiration
.atDay(2)
.atStartOfDay(ZoneOffset.UTC)
.toInstant());

Convert timestamp long to normal date format

In my web app, date & time of a user's certain activity is stored(in database) as a timestamp Long which on being displayed back to user needs to be converted into normal date/time format.
(Actually my database Cassandra stores the timestamp of when a column was written to it, as a long value( microseconds since 1970 ) which I will use to find out the time of that corresponding user activity)
I am using JSF 2.0(+ primefaces) which I believe has converters that may be helpful for this conversion? Or otherwise how How can I, at best, achieve these conversions?
Let me propose this solution for you. So in your managed bean, do this
public String convertTime(long time){
Date date = new Date(time);
Format format = new SimpleDateFormat("yyyy MM dd HH:mm:ss");
return format.format(date);
}
so in your JSF page, you can do this (assuming foo is the object that contain your time)
<h:dataTable value="#{myBean.convertTime(myBean.foo.time)}" />
If you have multiple pages that want to utilize this method, you can put this in an abstract class and have your managed bean extend this abstract class.
EDIT: Return time with TimeZone
unfortunately, I think SimpleDateFormat will always format the time in local time, so we can't use SimpleDateFormat anymore. So to display time in different TimeZone, we can do this
public String convertTimeWithTimeZome(long time){
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(time);
return (cal.get(Calendar.YEAR) + " " + (cal.get(Calendar.MONTH) + 1) + " "
+ cal.get(Calendar.DAY_OF_MONTH) + " " + cal.get(Calendar.HOUR_OF_DAY) + ":"
+ cal.get(Calendar.MINUTE));
}
A better solution is to utilize JodaTime. In my opinion, this API is much better than Calendar (lighter weight, faster and provide more functionality). Plus Calendar.Month of January is 0, that force developer to add 1 to the result, and you have to format the time yourself. Using JodaTime, you can fix all of that. Correct me if I am wrong, but I think JodaTime is incorporated in JDK7
java.time
ZoneId usersTimeZone = ZoneId.of("Asia/Tashkent");
Locale usersLocale = Locale.forLanguageTag("ga-IE");
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(usersLocale);
long microsSince1970 = 1_512_345_678_901_234L;
long secondsSince1970 = TimeUnit.MICROSECONDS.toSeconds(microsSince1970);
long remainingMicros = microsSince1970 - TimeUnit.SECONDS.toMicros(secondsSince1970);
ZonedDateTime dateTime = Instant.ofEpochSecond(secondsSince1970,
TimeUnit.MICROSECONDS.toNanos(remainingMicros))
.atZone(usersTimeZone);
String dateTimeInUsersFormat = dateTime.format(formatter);
System.out.println(dateTimeInUsersFormat);
The above snippet prints:
4 Noll 2017 05:01:18
“Noll” is Gaelic for December, so this should make your user happy. Except there may be very few Gaelic speaking people living in Tashkent, so please specify the user’s correct time zone and locale yourself.
I am taking seriously that you got microseconds from your database. If second precision is fine, you can do without remainingMicros and just use the one-arg Instant.ofEpochSecond(), which will make the code a couple of lines shorter. Since Instant and ZonedDateTime do support nanosecond precision, I found it most correct to keep the full precision of your timestamp. If your timestamp was in milliseconds rather than microseconds (which they often are), you may just use Instant.ofEpochMilli().
The answers using Date, Calendar and/or SimpleDateFormat were fine when this question was asked 7 years ago. Today those classes are all long outdated, and we have so much better in java.time, the modern Java date and time API.
For most uses I recommend you use the built-in localized formats as I do in the code. You may experiment with passing SHORT, LONG or FULL for format style. Yo may even specify format style for the date and for the time of day separately using an overloaded ofLocalizedDateTime method. If a specific format is required (this was asked in a duplicate question), you can have that:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss, dd/MM/uuuu");
Using this formatter instead we get
05:01:18, 04/12/2017
Link: Oracle tutorial: Date Time explaining how to use java.time.
Not sure if JSF provides a built-in functionality, but you could use java.sql.Date's constructor to convert to a date object: http://download.oracle.com/javase/1.5.0/docs/api/java/sql/Date.html#Date(long)
Then you should be able to use higher level features provided by Java SE, Java EE to display and format the extracted date. You could instantiate a java.util.Calendar and explicitly set the time: http://download.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#setTime(java.util.Date)
EDIT: The JSF components should not take care of the conversion. Your data access layer (persistence layer) should take care of this. In other words, your JSF components should not handle the long typed attributes but only a Date or Calendar typed attributes.
To show leading zeros infront of hours, minutes and seconds use below modified code. The trick here is we are converting (or more accurately formatting) integer into string so that it shows leading zero whenever applicable :
public String convertTimeWithTimeZome(long time) {
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(time);
String curTime = String.format("%02d:%02d:%02d", cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));
return curTime;
}
Result would be like : 00:01:30
I tried this and worked for me.
Date = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1, 0, 0, 0))).TotalSeconds

Categories