Date to Day conversion in Java - java

I am able to convert date to days using the below code.
SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd");
String s1 = sfd.format(dateObj);
String a1 [] = s1.split("-");
int year = Integer.parseInt(a1[0].toString());
int month = Integer.parseInt(a1[1])-1;
int day = Integer.parseInt((a1[2]));
Calendar c1 = Calendar.getInstance();
c1.set(year,month,day);
days = c1.getTime().getTime()/(24*60*60*1000);
The above code works accurately in my system which is windows with timezone GMT +5.30.
However the same code in EST or Pacific timezone adds a day by 1 to final result when the time is 20.00 in the system.
What could be the issue ?
Do we need to set Timezone explicitly in the code ?
input dates does not hold any time stamp ..
is it correct to store in java.util.Date instead of java.sql.Date?

EDIT: As per Alex's comment, it's possible that the problems with the start of your code have blinded me to your real aim.
A Date represents an instant in time. That can fall on different dates depending on the time zone, but how do you want that to affect things? Do you want the number of days since the Unix epoch (which is always UTC) or the number of days since the 1st January 1970 in a particular time zone? Why do you want this "number of days" instead of a representation of a date such as LocalDate? What's the use case here?
EDIT: If you just want to know the number of days since the Unix epoch, you can skip most of this:
days = dateObj.getTime() / (24 * 60 * 60 * 1000);
You shouldn't be going through formatting at all just to get the year / month / day. Just create a Calendar, set the relevant time zone, call setTime with the dateObj you've already got, and then clear the hour/minute/second part of the calendar.
However, you should explicitly specify which time zone you want to consider - a Date represents an instant in time, which will mean different dates in different time zones.
You should also consider using Joda Time which makes all of this simpler and has a specific type for dates (LocalDate). That would also make it easy to find the number of days between the Unix epoch and a particular date without performing the division yourself.

java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
You can convert the object of java.util.Date to Instant using Date#toInstant and then you can find the number of days from now until this date using ChronoUnit#between.
Demo:
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
// A sample java.util.Date
Date dateObj = GregorianCalendar.from(ZonedDateTime.of(2021, 10, 2, 22, 25, 0, 0, ZoneOffset.UTC)).getTime();
Instant instant = dateObj.toInstant();
// Difference between now and the given java.util.Date
System.out.println(ChronoUnit.DAYS.between(Instant.now(), instant));
}
}
Output:
99
ONLINE DEMO
Note that the above code calculates the number of days between two moments/instants represented in UTC. If you have date-time values local to a particular timezone, you need to specify the corresponding ZoneId.
Demo:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
ZoneId tz = ZoneId.of("Australia/Brisbane");
// A sample java.util.Date representing the local date and time values in Australia/Brisbane
Date dateObj = GregorianCalendar.from(ZonedDateTime.of(2021, 10, 2, 22, 25, 0, 0, tz)).getTime();
// Difference between now in Australia/Brisbane and the given java.util.Date
System.out.println(ChronoUnit.DAYS.between(Instant.now().atZone(tz), dateObj.toInstant().atZone(tz)));
}
}
Output:
98
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Related

Milliseconds from 1970 to 2020.01.01

I was trying to get milliseconds from epoch until 2020.01.01. I used old method with Date and I also wanted to use new sexy LocalDate but two results I got are different:
long millisecondsInTheDay = 24 * 60 * 60 * 1000;
long millis1 = LocalDate.of(2020, Month.JANUARY, 1).toEpochDay() * millisecondsInTheDay; // 1577836800000
long millis2 = new Date(2020 - 1900, 0, 1).toInstant().toEpochMilli(); // 1577833200000
Difference is exactly one hour (3600_000 milliseconds). Why I get different result?
I don't want to comment on why you get a difference because I think that both of the original approaches are problematic. You need to pay close attention to things like time zones; and you really should avoid doing any sort of arithmetic on numerical values representing dates.
You need to pay special care to specify the points you are measuring between: if you want a number of milliseconds, presumably you really want to specify those points as instants in time. "1970" isn't an instant, it's a year-long period; "2020-01-01" isn't an instant either, but a period whose meaning shifts depending on time zone - there's roughly 48h-worth of instants where somewhere on the planet it is considered to be that date.
The correct way to do this (assuming you want milliseconds between epoch and the start of the day in your preferred timezone) is:
Duration between =
Duration.between(
Instant.EPOCH,
LocalDate.of(2020, Month.JANUARY, 1).atStartOfDay(zoneId));
long betweenMillis = between.toMillis(); // If you must - better to keep the type information that this is a Duration.
Note that you need to specify the zoneId, e.g. ZoneId.of("Europe/Warsaw"), because that affects when the start of the day is, and hence how many milliseconds.
Different time zones
Why I get different result?
Joachim Sauer said it already: This is because of different time zones. millis1 is the count of milliseconds until January 1, 2020 at 00:00 in UTC. millis2 counts until January 1, 2020 at 00:00 in your local time zone, presumably Europe/Warsaw. In winter Poland is at offset +01:00 from UTC, which explains the difference of 1 hour between the two. Everything agrees nicely. The epoch is one point in time and independent of time zone. It’s usually defined as January 1, 1970 at 00:00 in UTC.
That said I agree with Andy Turner that both ways to calculate are problematic.
A good calculation with java.time
Here’s my go, of course using java.time, the modern Java date and time API:
ZoneId targetZone = ZoneOffset.UTC;
long millis = LocalDate.of(2020, Month.JANUARY, 1).atStartOfDay(targetZone)
.toInstant()
.toEpochMilli();
System.out.println(millis);
Output:
1577836800000
If you did want your own time zone, just change the first line:
ZoneId targetZone = ZoneId.of("Europe/Warsaw");
1577833200000
The key is to use the same timezone (e.g. UTC) for both, the legacy and the modern API.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
long millisUsingJavaUtilDate = sdf.parse("2020.01.01")
.getTime();
long millisUsingJavaTime = LocalDate.of(2020, Month.JANUARY, 1)
.atStartOfDay(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
System.out.println(millisUsingJavaUtilDate);
System.out.println(millisUsingJavaTime);
}
}
Output:
1577836800000
1577836800000
Let's try with another timezone, America/New_York:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
long millisUsingJavaUtilDate = sdf.parse("2020.01.01")
.getTime();
long millisUsingJavaTime = LocalDate.of(2020, Month.JANUARY, 1)
.atStartOfDay(ZoneId.of("America/New_York"))
.toInstant()
.toEpochMilli();
System.out.println(millisUsingJavaUtilDate);
System.out.println(millisUsingJavaTime);
}
}
Output:
1577854800000
1577854800000
Learn more about the modern date-time API from Trail: Date Time.
Note that the legacy date-time API (java.util date-time types and their formatting API, SimpleDateFormat) are outdated and error-prone. It is recommended to stop using them completely and switch to java.time, the modern date-time API* .
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
new Date( y , m , d ) uses default time zone
Some of the other Answers are correct and very useful. But I want to make very plain and simple where your code went wrong:
➥ The deprecated constructor of java.util.Date for year-month-day arguments implicitly applies your JVM’s current default time zone.
Take the first part of the key line in your code:
new Date(2020 - 1900, 0, 1).toInstant()
… where an Instant is always in UTC (an offset of zero hours-minutes-seconds), by definition. On my machine the current default time zone in my JVM is America/Los_Angeles. On your date and time, this zone was eight hours behind UTC.
So let's try these three lines of code code:
System.out.println(
ZoneId.systemDefault()
);
System.out.println(
new Date(2020 - 1900, 0, 1)
);
System.out.println(
new Date(2020 - 1900, 0, 1).toInstant()
);
When run, we see indeed that the moment represented by new Date is the first moment of that day as seen in the time zone America/Los_Angeles, colloquially known as PST. That zone on that date is eight hours behind UTC. We can see this fact in the third line, when calling toInstant has adjusted to UTC where the time-of-day is 8 AM.
America/Los_Angeles
Wed Jan 01 00:00:00 PST 2020
2020-01-01T08:00:00Z
Avoid Date
In the bigger picture, stop using Date class!
There are no benefits to be had by studying the behavior of java.util.Date. That class is absolutely terrible, written by people who did not understand date-time handling. Along with Calendar, java.sql.Date, and SimpleDateFormat, these classes should never be used.
These legacy classes were supplanted years ago by the java.time classes, defined in JSR 310. Sun, Oracle, and the JCP community unanimously gave up on these classes. So should you.
Your problem is here:
long millis1 = LocalDate.of(2020, Month.JANUARY, 1).toEpochDay() * millisecondsInTheDay; // 1577836800000
You use the LocalDate class, which gets for you the local time (in your timezone) while time in Java (in millisec) is the amount of time elapsed between 01.01.1970 UTC (Universal Coordinated Time) this is (at the date you requested, 01.01.2020 00:00:00 UTC):
1577836800000
The difference you get is due to the time offset observed at your local time (one hour, probably you are in central european time --CET--)
Edit:
By the way, I've seen in the answers (and in your code) that you use:
new Date(2020 - 1900, 0, 1);
This is very bad code. You are assuming that the above is equivalent to the difference in milliseconds that will be between the dates 2020.1.1 and 1900.1.1 and indeed, it represents the timestamp at date 120.1.1 this is the timestamp at the first of january of year one hundred and twenty (a.C) There's no distributive property between dates in new Date() operator. And if the years were all the same duration, this could be true... but they are not. A good way would be to use:
long millis = new Date(2020, 0, 1).getTime() - new Date(1900, 0, 1).getTime();
but the later is not equivalent to what is written above.

Joda-Time strange hour

I'm trying to initialise a Joda-Time DateTime object with the hour of 12:00 here is how I do this:
public static final long MINUTE = 60 * 1000;
public static final long HOUR = 60 * MINUTE;
DateTime defaultDate = new DateTime(HOUR * 12);
System.out.print("the hour is: " + defaultDate.getHourOfDay()) // getting 14
Why I am getting 14 and not 12? Maybe Mama didn't teach me how to read clock right?!
You're specifying a number of milliseconds since the Unix epoch, which was midnight UTC.
However, you're implicitly using the system default time zone in your DateTime, and I suspect that at the Unix epoch, your system time zone was UTC+2.
If you want to use a specific time zone, you can pass that in the constructor:
DateTime defaultDate = new DateTime(HOUR * 12, DateTimeZone.UTC);
Also, rather than using your own constants, you could either use DateTimeConstants.MILLIS_PER_HOUR or use java.util.concurrent.TimeUnit for conversions.
java.time
Quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.of(LocalDate.EPOCH, LocalTime.of(12, 0)), ZoneOffset.UTC);
System.out.println(zdt);
}
}
Output:
1970-01-01T12:00Z
ONLINE DEMO
A couple of important notes:
ZonedDateTime#toString removes seconds and fraction-of-second if they are zero. If you want to display them, you can use DateTimeFormatter e.g.
String formatted = zdt.format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH));
The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Learn more about the modern Date-Time API from Trail: Date Time.
What went wrong with your code?
Quoted below the is description of DateTime(long) with my emphasis:
Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z using ISOChronology in the default time zone.
Your place, Israel was at an offset of +02:00 hours in 1970 and therefore the DateTime instance was instantiated with an offset of +02:00 hours.
Demo:
import java.util.concurrent.TimeUnit;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
public class Main {
public static void main(String[] args) {
DateTime defaultDate = new DateTime(TimeUnit.HOURS.toMillis(12), DateTimeZone.UTC);
System.out.println(defaultDate);
}
}
Output:
1970-01-01T12:00:00.000Z
Another thing, which you might have already noticed from the code, is that DO NOT perform calculations yourself if there is already a standard API (e.g. TimeUnit#toMillis) available for the same.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

server time zone java conversion

Ok, so I've pretty much tried everything. I bet it's something really simple but I can't seem to get a hold of it.
The server sends me the time, which is epoch. However when I put this into a date object it seems to automatically pick up the time zone and it adds +3 to the server time. So if the gmt time is 00.00, it says its 03.00.
I also need to add a timezone of my own. Let's say the epoch time is 00.00 again, it should read 10.00 after I add the timezone.
any help would be much appreciated. Thank you
"It seems to add" - I suspect you're using Date.toString() which does indeed use the local time zone. The Date object itself is effectively in UTC though. Use DateFormat to perform the conversion to a string instead, and you can specify which time zone to use. You may also need to use Calendar - it depends what you're trying to do.
(Alternatively, use Joda Time in the first place, which is a better API. It may be a little bulky for your Android project though. I wouldn't be surprised if there were a "Joda Time lite" project around somewhere for precisely this sort of thing...)
EDIT: Quick sample, although it's not entirely clear what you need...
long millis = getMillisFromServer();
Date date = new Date(millis);
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(customTimeZone);
String formatted = format.format(date);
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
long millis = 1316391494L;
Instant instant = Instant.ofEpochMilli(millis);
System.out.println(instant);
// The same instant at a specific timezone
ZonedDateTime zdt = instant.atZone(ZoneId.of("Australia/Brisbane"));
System.out.println(zdt);
}
}
Output:
1970-01-16T05:39:51.494Z
1970-01-16T15:39:51.494+10:00[Australia/Brisbane]
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
What went wrong with your code?
A java.util.Date object simply represents an instant on the timeline — a wrapper around the number of milliseconds since the UNIX epoch (January 1, 1970, 00:00:00 GMT). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
long millis = 1316391494L;
Date date = new Date(millis);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX[zzzz]", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = sdf.format(date);
System.out.println(strDateUtc);
sdf.setTimeZone(TimeZone.getTimeZone("Australia/Brisbane"));
String strDateBrisbane = sdf.format(date);
System.out.println(strDateBrisbane);
}
}
Output:
1970-01-16T05:39:51.494Z[Coordinated Universal Time]
1970-01-16T15:39:51.494+10:00[Australian Eastern Standard Time]
ONLINE DEMO
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

In java, what time is the start of the day?

What time is the start of a day, say 01/01/2010?
Is it 00:00:00:000 ? or is that midnight?
[edit]
It might be a stupid question but I'm confused because I used Calendar.set(Calendar.HOUR, 0) but this gives me a time of 12:00:00.
and now I've realised I should be using HOUR_OF_DAY
The start of the day isn't always midnight. It can depend on the time zone and date. (If the clock moves forward an hour at the start of the day, it will start at 1am.)
That's why Joda-Time has things like LocalDate.toDateTimeAtStartOfDay - and they're well worth using.
But yes, normally it's at 00:00:00 which is midnight. (This can also be formatted as "12am" depending on your locale etc.)
java.time
Normally, the start of the date is 00:00 hours but it may vary because of DST. Therefore, instead of assuming it to be 00:00 hours, the safest option is to use LocalDate#atStartOfDay(ZoneId zone).
Demo:
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/u", Locale.ENGLISH);
LocalDate date = LocalDate.parse("01/01/2010", dtf);
// In JVM's timezone
ZonedDateTime startOfDay = date.atStartOfDay(ZoneId.systemDefault());
System.out.println(startOfDay);
// In custom timezone
startOfDay = date.atStartOfDay(ZoneId.of("Africa/Johannesburg"));
System.out.println(startOfDay);
}
}
Output:
2010-01-01T00:00Z[Europe/London]
2010-01-01T00:00+02:00[Africa/Johannesburg]
Learn more about the the modern date-time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
ZonedDateTime from java.time
Like Arvind Kumar Avinash already does in a good answer, I recommend that you use java.time, the modern Java date and time API, for your date and time work.
If you had got a LocalDate or a string holding a date without time of day, that answer shows you how to get the start of the day (the first moment of the day). If you had already got a ZonedDateTime, you may simply use its truncatedTo method. Let’s take one of those interesting examples where the clocks are turned forward at 00:00 so the first moment of the day is 01:00:
ZonedDateTime zdt = ZonedDateTime.of(
2000, 9, 17, 15, 45, 56, 789000000, ZoneId.of("Asia/Dili"));
System.out.println("We got date and time: " + zdt);
ZonedDateTime startOfDay = zdt.truncatedTo(ChronoUnit.DAYS);
System.out.println("Start of day is: " + startOfDay);
Output:
We got date and time: 2000-09-17T15:45:56.789+09:00[Asia/Dili]
Start of day is: 2000-09-17T01:00+09:00[Asia/Dili]
What went wrong in your code?
You’ve already said it in an edit to the question, but it deserves to be mentioned in an answer too: Calendar.HOUR refers to, from the documentation:
Field number for get and set indicating the hour of the morning or
afternoon. HOUR is used for the 12-hour clock (0 - 11). …
So if your Calendar was already holding a time in the afternoon (12 noon or later), setting HOUR to 0 gives you 12 noon (12:00 on a 24 hour clock), not 12 midnight (00:00 on a 24 hour clock). Except that the time of the hour may still be non-zero, so you may also get, for example, 12:34:45.567. The Calendar class was cumbersome to work with.
In any case the Calendar class was poorly designed and is long outdated, so you shouldn’t need to worry; just don’t use that class anymore.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Documentation of Calendar.HOUR.

Getting today's date in java - I've tried the regular ways

I need today's date - and zero anything else (" 05/06/08 00:00:00 ")
I've tried
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR, 0);
Date date1 = calendar.getTime();
System.out.println(date1);
Run: (This is seriously messed up)
If the hour on the computer is < 12:00 at noon : Sun Mar 08 00:44:39 IST 2009
If the hour on the computer is > 12:00 at noon : Sun Mar 08 12:46:53 IST 2009
So I gave this up.
All the Date's setters are deprecated (except the epoch time) - so I don't want to use them either
The only thing I could think of is
Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
String sDate = dateFormat.format(calendar.getTime());
Date today = dateFormat.parse(sDate);
But this is such a lame code I can't bring myself to write it.
Any other option?
Thanks!
I use this:
public static Date startOfDay(Date date) {
Calendar dCal = Calendar.getInstance();
dCal.setTime(date);
dCal.set(Calendar.HOUR_OF_DAY, 0);
dCal.set(Calendar.MINUTE, 0);
dCal.set(Calendar.SECOND, 0);
dCal.set(Calendar.MILLISECOND, 0);
return dCal.getTime();
}
My standard advice for Java date/time questions: don't use java.util.{Calendar,Date}. Use Joda Time. That way you can represent a date as a date (with no associated time zone), instead of a date/time. Or you could use a DateMidnight if that's what you want to represent. (Be careful of combinations of time zone and date where there is no midnight though...)
What do you need to use the Date with? If you can get away with changing to use Joda throughout, that's great. Otherwise, you can use Joda to do what you want and then convert to milliseconds (and then to java.util.Date) when you really need to.
(Michael's solution when using Date/Calendar is fine if you really want to stick within a broken API... but I can't overstate how much better Joda is...)
You should use HOUR_OF_DAY instead of HOUR and combine it with MINUTE and SECOND also.
import java.util.Calendar;
import static java.util.Calendar.HOUR_OF_DAY;
import static java.util.Calendar.MINUTE;
import static java.util.Calendar.SECOND;
import static java.util.Calendar.MILLISECOND;
public class Today {
public static void main( String [] args ) {
Calendar cal = Calendar.getInstance();
cal.set( HOUR_OF_DAY, 0 );
cal.set( MINUTE, 0 );
cal.set( SECOND, 0 );
cal.set( MILLISECOND, 0 );
System.out.println( cal.getTime() );
}
}
The results you are getting are due to HOUR is used to AM/PM while HOUR_OF_DAY is 24 hrs.
HOUR_OF_DAY:
Field number for get and set indicating the hour of the day. HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM the HOUR_OF_DAY is 22.
HOUR:
Field number for get and set indicating the hour of the morning or afternoon. HOUR is used for the 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the HOUR is 10.
The time component is not just hours (and Calendar.HOUR is, as you have noticed, AM/PM).
You need to set all of the time fields to 0: HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND.
See Apache's commons-lang DateUtils.truncate()
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
The modern Date-Time API has many types which truly represent a date or time or date-time in a specific timezone. You can choose from the following options as per your specific requirement:
If you are looking for a type that represents a date without a timezone, you can use LocalDate.now. The good news is that its variant, LocalDate#now(ZoneId) returns the current date from the system clock in the specified time-zone.
If you are looking for an object that represents a date without a timezone, and with time units set to zero, you can call LocalDate#atStartOfDay on the object obtained with Option#1.
If you are looking for an Instant representing the Date-Time object obtained with Option#2, you can attach this object with ZoneId.of("Etc/UTC") using LocalDateTime#atZone to obtain a ZonedDateTime and convert the same into an Instant using ZonedDateTime#toInstant.
Demo:
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalDate todayInSystemTz = LocalDate.now();
System.out.println(todayInSystemTz);
LocalDate todayInIndia = LocalDate.now(ZoneId.of("Asia/Kolkata"));
System.out.println(todayInIndia);
LocalDateTime todayInSystemTzWithZeroTimeUnits = todayInSystemTz.atStartOfDay();
System.out.println(todayInSystemTzWithZeroTimeUnits);
ZonedDateTime todayInUtcWithZeroTimeUnits = todayInSystemTzWithZeroTimeUnits.atZone(ZoneId.of("Etc/UTC"));
System.out.println(todayInUtcWithZeroTimeUnits);
Instant instant = todayInUtcWithZeroTimeUnits.toInstant();
System.out.println(instant);
// Can I represent the obtained Instant in India?
System.out.println(instant.atZone(ZoneId.of("Asia/Kolkata")));
// Can I represent the obtained Instant in New York?
System.out.println(instant.atZone(ZoneId.of("America/New_York")));
}
}
Output:
2021-06-20
2021-06-20
2021-06-20T00:00
2021-06-20T00:00Z[Etc/UTC]
2021-06-20T00:00:00Z
2021-06-20T05:30+05:30[Asia/Kolkata]
2021-06-19T20:00-04:00[America/New_York]
ONLINE DEMO
The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
For any reason, if you need to convert this object of Instant to an object of java.util.Date**, you can do so as follows:
Date date = Date.from(instant);
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
**
A java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String strDateNewYork = sdf.format(date);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = sdf.format(date);
As mentioned above you should use
Calendar.HOUR_OF_DAY
As opposed to
Calendar.HOUR
Also you need to clear out the other fields (Calendar.MINUTE, Calendar.SECOND, and Calendar.MILLISECOND) by setting them to zero.
Sorry there's no easy way here. A pain, and that's why they're working on a new API for Java 7 I believe based on Joda Time.
...or you can do it the hacker way:
long MS_PER_DAY = 86400000L;
Date dateTime=new Date();
long offset = TimeZone.getDefault().getOffset(dateTime.getTime());
Date date= new Date(((dateTime.getTime()+offset)/MS_PER_DAY)*MS_PER_DAY-offset);
I know this is a very old question, no longer active, but it came to be on the top when I searched Google.
While all advise is very good, I can't believe no one simply answered:
Date date = new Date(System.currentTimeMillis());
System.out.println(date);
Which returns effectively, today's date.
Why the string manipulation?
Can you not just set the values you need on the Calendar object before converting to a Date using getTime()?
Another vote for JodaTime.
java.util.Date and Calendar are so bad they are broken. (And SimpleDateFormat is rubbish too!)
For what it's worth, Java 7 will include a new date time library based strongly around JodaTime.

Categories